Github Profileに活動状況、よく使っている言語を載せる(github-profile-summary-cards)

Github上での活動状況、よく使っている言語等をGithub Profileに入れて、セルフブランディングに役立てるようになりました。 得意な技術ややりたいことが、社内外のアピールできるとやっていて楽しい仕事に繋がるかもしれません。

自動的にGithubの活動状況、よく使っている言語の情報を取得してくれるgithub-profile-summary-cardsというGithub Actionを紹介したいと思います。

こんな感じのやつができます。 f:id:moritamorie:20200907124113p:plain

Github Profileに好きなコンテンツを載せるには

まず、公開リポジトリに、ユーザ名と同じリポジトリを作り、その中にREADME.mdファイルを置くとそのコンテンツが、Github Profileの上部に表示されるようになります。なので、以下のように新しいリポジトリを作成する画面で、「Add a README file」にチェックを入れてリポジトリを作ります。

f:id:moritamorie:20200907230946p:plain

すると自動的に作られたREADME.mdのコンテンツがGithub Profileに表示されるようになります。

f:id:moritamorie:20200907231336p:plain

github-profile-summary-cardsとは

以下のようなGithubの活動状況、よく使っている言語に関するSVG画像を自動的に作ってくれるGithub actionです。

f:id:moritamorie:20200907124113p:plain

公式のリポジトリはこちら↓です。 github.com

デザインテーマ

色々なデザインテーマのSVG画像を作ってくれます。

default

f:id:moritamorie:20200907233830p:plain

dracula

f:id:moritamorie:20200907233625p:plain

monokai

f:id:moritamorie:20200907233940p:plain

solarized

f:id:moritamorie:20200907234045p:plain

solarized_dark

f:id:moritamorie:20200907234131p:plain

vue

f:id:moritamorie:20200907234214p:plain

やってみる

SVG画像を作るGithub actionsのworkflowが動くように

先程作ったユーザ名と同じリポジトリ.github/workflows/profile-summray-cards.ymlファイルを作って、SVG画像を作るGithub actionsのworkflowを動くようにします。

name: GitHub-Profile-Summary-Cards

on:
  schedule: # execute every 24 hours
    - cron: '* */24 * * *'
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    name: generate

    steps:
      - uses: actions/checkout@v2
      - uses: vn7n24fzkq/github-profile-summary-cards@release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          USERNAME: ${{ github.repository_owner }}

②workflowを実行し、SVG画像を作る

プロジェクトのActionsタブからRun workflowを押すと、profile-summary-card-outputディレクトリができ、デザインテーマ毎のSVG画像と、画像ファイルのプレビューが見れるREADME.mdが生成されます。 f:id:moritamorie:20200907233155p:plain

③作ったSVG画像がGithub Profileに表示されるように

profile-summary-card-outputディレクトリに作成されたREADME.md(画像プレビュー)を参考に、ユーザ名と同じリポジトリ直下のREADME.mdを編集します。以下のようにしてみます。

[![](https://raw.githubusercontent.com/moritamori/moritamori/master/profile-summary-card-output/dracula/0-profile-details.svg)](https://github.com/vn7n24fzkq/github-profile-summary-cards)
[![](https://raw.githubusercontent.com/moritamori/moritamori/master/profile-summary-card-output/dracula/1-repos-per-language.svg)](https://github.com/vn7n24fzkq/github-profile-summary-cards)
[![](https://raw.githubusercontent.com/moritamori/moritamori/master/profile-summary-card-output/dracula/2-most-commit-language.svg)](https://github.com/vn7n24fzkq/github-profile-summary-cards)

README.mdの内容がGithub profileに表示されます。 f:id:moritamorie:20200907235010p:plain

プライベートリポジトリのコンテンツも含める

デフォルトのGITHUB_TOKENを使うとパブリックリポジトリのコンテンツだけが対象になりますが、プライベートリポジトリのコンテンツも含めることができます。(参考URL

①Personal Access Tokenの作成

Personal Access Tokensに、新しくprofile-summray-cards用のトークンを作成します。repouserの権限だけあれば大丈夫でした。 f:id:moritamorie:20200908001333p:plain

②プロジェクトのSecretsにPERSONAL_ACCESS_TOKENを設定

f:id:moritamorie:20200908001535p:plain

profile-summray-cards.ymlGITHUB_TOKENをPERSONAL_ACCESS_TOKENに置き換える

${{ secrets.GITHUB_TOKEN }}
↓
${{ secrets.PERSONAL_ACCESS_TOKEN }}

再度、ワークフローを実行すると、プライベートリポジトリも含めて計算してくれるようになります。

f:id:moritamorie:20200908002550p:plain

【Electron】SpectronでメニューのE2Eテストをする

Electronアプリをバージョンアップした時やリファクタリングした時に動かなくなってしまう恐れがあるので、SpectronでメニューのE2Eテストを書いてみました。

ElectronのテスティングフレームワークSpectronはメニューのテストをする機能はないので、spectron-menu-addon-v2パッケージを使って使ってみました。メニューテストを書ける非常にシンプルなパッケージです。 www.npmjs.com

spectron-menu-addon-v2は、spectron-menu-addonパッケージでは対応していないElectronとSpectronのアップデートに対応させてもののようです。 試しに書いてみたテストコードを共有したいと思います。以下のHelpメニューのLearn Moreを押すというのと、メニューのステータスをチェックするというシンプルなテストです。

f:id:moritamorie:20200901000235p:plain

spectron-menu-addon-v2をインストール

Electronアプリにspectron-menu-addon-v2をインストールします。

$ yarn add spectron-menu-add-v2

Jestでテストコードを書く

こんな感じのコードを書いてみました。

// electron-menu-addon-app/src/__tests__/AppTest.js

const Application = require("spectron").Application;
const electronPath = require("electron");
const path = require("path");

const electron = require('electron')
const spectronMenuAddon = require('spectron-menu-addon-v2')

const menuAddon = new spectronMenuAddon.SpectronMenuAddon()

let app;

beforeAll(() => {
  app = menuAddon.createApplication({ args: [path.join(__dirname, '..')], path: electron.toString() })

  return app.start();
}, 15000);

afterAll(function () {
  if (app && app.isRunning()) {
    return app.stop();
  }
});

test("メニューのLearn Moreをクリック", async function () {
  menuAddon.clickMenu('Help', 'Learn More')
});

test("メニューのLearn Moreの状態をチェック", async function () {
  const menuStatus = await menuAddon.getMenuItem('Help', 'Learn More')
  console.log(menuStatus)
  expect(menuStatus.checked).toEqual(false)
  expect(menuStatus.enabled).toEqual(true)
  expect(menuStatus.label).toEqual('Learn More')
  expect(menuStatus.visible).toEqual(true)
});

サンプルコード

作ったプロジェクトのリンクを貼っておきますので、よかったら参考にしてみてください。 github.com

【Electron】Circle CIでSpectronのE2Eテストを動くように

先日Circle CIのチュートリアルに「Automated testing with continuous integration for Electron applications」という記事が追加されていたのでやってみました。

ちょっと前にGithub ActionsでSpectronのE2Eテストを自動で動かせるようにならないか試してみたところ、以下のようなエラーが発生していてChromeが起動しなかったので、今度はCircle CIでやってみたいと思っていたので良いタイミングでした。

また、今後CypressはElectronをサポートする予定とないとGithub issueでコメンとしているので、改めてSpectronを試してみようと思いました。

Client initialization failed after ***0 attempts: 
RuntimeError Client initialization failed after ***0 attempts: 
Error: unknown error: 
Chrome failed to start: 
exited abnormally. (chrome not reachable)

環境

  • Node.js (>= 11)がインストールされていること
  • CircleCIアカウントがあること
  • GitHubアカウントがあること

テストするElectronアプリケーションを作る

まずは、create-electron-appでアプリケーションを作ります。

$ npx create-electron-app electron-test-app

できたアプリケーションのディレクトリに移動しておきます。

$ cd electron-test-app 

Electronのバージョン10.0.1が出てその変更の影響か、そのままではテスト実行時に以下のエラーが発生していました。ローカル環境のChromeのバージョンを上げる必要がありそうです。

Failed to create session.
    session not created: 
    This version of ChromeDriver only supports Chrome version 83

今回は、Electronのバージョンを9.2.0に下げてやってみました。バージョン変更後、npm startで起動します。

$ yarn upgrade electron@9.2.0
$ npm start

こんな画面が表示されたかと思います。 f:id:moritamorie:20200830171634p:plain

devtools(画面右側ペイン)が開いていると、テストを実行した時に止まったままになってしまうので、コードを修正しdevtoolsが動かないようにします。

一度、コンソールから起動したElectronアプリケーションをCtrl-Cで停止し、electron-test-app/src/index.jsテキストエディタで開いて、mainWindow.webContents.openDevTools()の箇所をコメントアウトします。

// electron-test-app/src/index.js

19:  // Open the DevTools.
20:  // mainWindow.webContents.openDevTools(); // ←ここをコメントアウト

再度、npm startでアプリケーションを起動すると、今度はdevtoolsが起動しなくなります。

f:id:moritamorie:20200830172416p:plain

JestとSpectronをセットアップする

以下を作ったアプリケーションに追加します。

以下のコマンドを実行し、アプリケーションにJestとSpectronを追加します。

$ npm install --save-dev jest spectron

アプリケーションのルート直下にあるpackage.jsonを修正し、jestのテストが実行されるようにします。

// package.json

{
    〜〜〜
    "scripts" : {
        〜〜〜
        "test" : "jest"
    }
    〜〜〜
}

テストコードを作る

srcディレクトリに__tests__ディレクトリを作成し、その中にAppTest.jsを作ります。 Jestがデフォルトで__tests__ディレクトリの中のjs/ts/jsxファイルをテストとして実行してくれます。(参照)

こんなテストファイルを追加してみます。テストしている内容に関しては説明を割愛します。

const Application = require("spectron").Application;
const electronPath = require("electron");
const path = require("path");

let app;

beforeAll(() => {
  app = new Application({
    path: electronPath,

    args: [path.join(__dirname, "../../")]
  });

  return app.start();
}, 10000);

afterAll(function () {
  if (app && app.isRunning()) {
    return app.stop();
  }
});

test("アプリケーションウィンドウが表示されること", async function () {
  let windowCount = await app.client.getWindowCount();

  expect(windowCount).toBe(1);
});

test("ヘッダーが適切なテキストになっていること", async function () {
  const headerElement = await app.client.$("h1");

  let headerText = await headerElement.getText();

  expect(headerText).toBe("💖 Hello World!");
});

テストを実行して、うまく動くことを確認します。

$ npm run test

f:id:moritamorie:20200830174812p:plain

Circle CI上でプロジェクトを作成

Githubリポジトリを作ってPushしておきます。

$ git init && git add . && git commit -m 'initial commit'
$ git push 

次にCircle CIのProjects画面上でSet Up Projectを押して、アプリケーションのプロジェクトをセットアップします。 f:id:moritamorie:20200830175544p:plain

言語毎にCIの実行内容を記述したymlファイルのテンプレートが用意されていますがElectronはないので、Use Existing Configを押します。 f:id:moritamorie:20200830180202p:plain

とりあえずStart Buildingを押して、一度セットアップを終えます。

f:id:moritamorie:20200830180152p:plain

CIの実行内容を作成

セットアップが終わったら、再度ローカルの開発環境に戻り.circleci/config.ymlというymlファイルを作成します。

$ mkdir .circleci && touch .circleci/config.yml

ymlファイルをテキストエディタで以下のように編集して、再度GithubにpushするとCircle CIで自動的にテストが行われるようになります。

version: 2.1
jobs:
  build:
    working_directory: ~/repo
    docker:
      - image: circleci/node:11-browsers
    steps:
      - checkout
      - run:
          name: Update NPM
          command: "sudo npm install -g npm"
      - restore_cache:
          key: dependency-cache-{{ checksum "package-lock.json" }}
      - run:
          name: Install Dependencies
          command: npm install
      - save_cache:
          key: dependency-cache-{{ checksum "package-lock.json" }}
          paths:
            - ./node_modules
      - run:
          name: Run tests
          command: npm run test

Cicle CIの画面に戻って、Pipelinesを開くと正常にテストが動いているのを確認できます。

f:id:moritamorie:20200830181926p:plain

参考資料

【Electron】remote moduleがdeprecatedになっている背景

Electron 10.0.0が先日リリースされて、remote module がデフォルトで無効になりました。

バージョンを上げた時に、一部機能が動かなくなる場合など出てくると思いますので

  • そもそもremote moduleとは
  • なぜ remote module を使うとよくないのか

を整理してみたので、共有してみたいと思います。

この内容は2020年02月に開催されたCovalenceConf 2020のセッション(Jeremy Apthorp: Remote Module Considered Harmful )を元にまとめた内容であり、コードは動画内のものを引用しています。

remote module とは

remote module を使うことでレンダラプロセス内であたかもメインプロセス内のオブジェクトを直接触れるように見せかけることができます。

例えば、remote module を使って、レンダラプロセスで以下のようなサーバーを起動するようなコードを書くことができます。が、実際にはメインプロセスでソケットが開いていて、3000番ポートにリクエストがあった際、メインプロセスからレンダラプロセスをIPCで通信します。

// CovalenceConf 2020のセッション
// (Remote Module Considered Harmful )から引用

// Renderer process
const remote = require('electron').remote

const remoteHttp = remote.require('http')

const s = remoteHttp.createServer((req, res) => {
  res.setHeader('Access-Control-Allow-Origin, '*')
  res.end('yay')
})

s.listen(3000, () => {
  fetch('http://localhost:3000')
    .then(r=> r.text())
    .then(t => alert(t))
})

問題が発生する要因

remote moduleを通してメインプロセスとレンダラプロセスのIPC通信を実現する手段として、proxy objectsというものが介在しているようです。

まずい点その①遅い(パフォーマンス問題)

proxy objects が介在すると気がつかない間にIPC通信が増えてしまい、気がつかない間にパフォーマンスに問題が発生するケースがあるようです。 動画内では、以下のコードスニペットをあげており、この短いコードの中で9回IPC通信が行われるのように。

また、そもそもレンダラプロセスからメインプロセスのオブジェクトにアクセスすると、IPC通信を介することでローカルオブジェクトへのアクセスより1000倍遅くなるようです。

// CovalenceConf 2020のセッション
// (Remote Module Considered Harmful )から引用

// Main process
global.thing = {
  rectangle: {
    getBounds() {
      return { x, y, width, height } }
    setBounds(bounds) { /* ... */ }
  }
}
// Renderer process
let thing = remote.getGlobal('thing')
let { x, y, width, height} =
  thing.rectangle.getBounds()
thing.rectangle.setBounds(
  { x, y, width, height: height + 100 })

パフォーマンス問題が発生することで、プロセス間の非同期処理が失敗したり、デバッグが難しい問題を引き起こすことがあるようです。

まずい点その②セキュリティ問題がある

remote module を使ってレンダラプロセスからメインプロセスにIPC通信する際、ELECTRON_BROWSER_FUNCTION_CALLというIPCメッセージを送れると、メインプロセスの全ての権限が与えられてなんでもできちゃうという潜在的な問題があるようです。 PNGjsonを読み込むなど信頼できないコードが含まれる場合もある(セキュリティ脆弱性NVD - CVE-2019-7317NVD - CVE-2014-3188)ので、セキュリティホームになるようです。

remote moduleを無くすためのElectronの展開

以下のElectronのバージョンでそれぞれ対応を行い、徐々にremote module を無くす予定のようです。

  • v9: 明示的に有効にせずremote module を使っている場合、警告を出す
  • v10: デフォルトでremote moduleを無効に
  • (今後) v12: require('electron').remote または enableRemoteModule: trueにしている場合、警告を出すように
  • (今後) v14: require('electron').remoteを削除

remote moduleを無くすためのアプリケーション側の対応

現状 remote モジュールを使って、レンダラプロセスからあたかもローカルオブジェクトのようにメインプロセス内のオブジェクトを使っている場合、今後どうしたら良いのか。 対応としては2つあるようです。

①明示的にIPC通信で処理するように置き換える

remote moduleを使ってメインプロセス内のオブジェクトを参照し、暗黙的にIPC通信が行われることによって様々な問題が発生するので、明示的なIPC通信に置き換えていくことを推奨しているようです。

f:id:moritamorie:20200830103205p:plain

② 移管されるelectron-userland/remoteを使う

build-inで提供されている remote moduleは将来的に削除され、electron-userland/remoteに移管されるのでそれを使い続けるというのもできるようです。

参照ドキュメント

Sentryのエラー通知メールの設定変更方法

Webサービスを運用しているとエラーが来ますが、適切に設定していないと以下のような原因で通知メールが多くなり、見逃してしまうことがよくあります。

  • 関わりがないプロジェクトのメールも飛んできて、重要な通知が埋もれてしまう
  • 同じエラーが何度も飛んでくることで、無意識的に関心が向かなくなってしまう
  • メールのタイトルで判別しづらく、関係ないと思ってスルーしてしまう

エラーの通知サービスとしてSentryを使っているのですが、どの画面に何の設定があるのか分かりづらいので余計に適切に設定しづらく感じます。

Sentryの 画面上の設定方法(2020/08/29現在)とSentry以外でよりエラー通知メールに気がつけるように工夫している点に関して共有したいと思います。 Sentryの画面構成は今後変わる可能性がある点に関しては、ご注意ください。

設定画面

Sentryのエラー通知の設定画面は3つあります。それぞれ設定できることが違います。

  • ①プロジェクト毎の設定画面
  • ②個人ユーザ毎の設定画面
  • ③アラートの設定画面

特に設定した方が良いと思う設定をそれぞれ共有してみたいと思います。

①プロジェクト毎の設定画面

以下の設定ボタンを押し、プロジェクトの設定画面で アラートを押します。

f:id:moritamorie:20200829210907p:plain

この画面内の、メールの設定 - Subject Templateの箇所で、 [$projectID]を追加し、メールの件名にプロジェクトID(アプリケーション名)が入るようにしています。 f:id:moritamorie:20200829211657p:plain

こうすると

  • メールタイトルでどのアプリケーションのエラー通知か分かりやすくなる
  • メール受信フィルタで、アプリケーション毎にメールを分けられるようになる
    • => どこまで未読かが分かりやすくなり、新規のエラーに気が付きやすくなる

と思います。

ステージング環境でのエラー通知メールもを受け取るようにして、本番環境のエラーと判別しやすくしやすくする場合などは ${tag:environment}も追加しておくと良さそうです。

②個人ユーザ毎の設定画面

以下の画面で、User Settings => 通知、と選択します。

f:id:moritamorie:20200829210632p:plain

遷移した画面(Notifications)内の、アラート - Fine tune alerts by projectを選択すると、プロジェクト毎にメールを受信するかどうかを設定できます。課題の割り当て、ステータスの解決時等のメール通知をプロジェクト毎に設定する場合は、その下のワークフロー - Fine tune workflow notifications by projectから設定できます。

f:id:moritamorie:20200829213852p:plain

プロジェクトのメール通知は、オンオフデフォルト(上部のDEFAULT PROJECT ALERTS - Send Me Alertsの設定が適用される)から選択できます。 f:id:moritamorie:20200829214004p:plain

③アラートの設定画面

アラートは、プロジェクトが作られた時に自動的に1つ作られます。通知する人や、通知頻度、通知する環境(production, stating)をより適切に設定するにはデフォルトの設定から変更すると良いと思います。

左ナビゲーションから、アラート => Rulesタブ => プロジェクト毎の設定ボタン、と選択します。 f:id:moritamorie:20200829214409p:plain

Productionのエラー通知だけ(エラーが最初に発生した時にだけ)を受信したい場合には、この画面で

  • ALERT SETUP - 環境 で、production のように選択
  • ALERT CONDITIONSで、The issue is first seenを選択

のように設定すると、エラー通知するメールを減らす事ができ、埋もれにくくなると思います。

f:id:moritamorie:20200829214725p:plain

メール受信に関する工夫

エラー通知されたメールを把握しやすくする

プロジェクト毎の設定画面の「受信フィルター」で

を除外できるので、プロジェクトで古いブラウザーは対応しない等の方針があれば、設定しておくとより必要なエラー通知だけを受信できるようになります。 f:id:moritamorie:20200831002401p:plain

メールは、Gmailで受信していますが、以下のように受信メールフィルタを作って、プロジェクト毎にラベル付けをして、メールを振り分けています。

f:id:moritamorie:20200829215546p:plain

エラー通知されたメールを気が付きやすいように

「Checker Plus for Gmail」というChrome拡張を使って、Sentryの各プロジェクトIDでラベル付けされたメールが届くと音がなるようにしています。 f:id:moritamorie:20200830094013p:plain

寄付すると音を変更できるようになるので、プロジェクト毎に変更してみると良いかもしれません。

また、デスクトップ通知も有効にして、より気が付きやすくしています。 f:id:moritamorie:20200830094730p:plain

終わりに

設定画面が色々なところにあって分かりづらいですが、適切に設定できるととても便利です。 他にもデプロイ時に通知を飛ばしたり、メールではなくSlackに通知を飛ばしたり、色々できるので、プロジェクトに応じて設定を変更してみると良いかもです。

参照ドキュメント

【Ruby,Rails】Blazer gemで年月、年月日(Date)を選択するクエリを作り、時系列で指標を把握できるように

RailsアプリケーションのWebサービスを運用・改善するに当たって様々な指標を把握するために、blazeradhoqといったgemを追加し、SQL集計ダッシュボードを作っています。 特に年月日を絞り込みの条件に入れると時系列の変化を観測し、サービス改善に役にたつと感じています。

f:id:moritamorie:20200821133530p:plain

今回は、Blazer gemを使った年月、年月日(Date)を選択するSmart Variablesを使ったクエリの作り方を紹介したいと思います。

年月指定

Blazerの設定ファイル(blazer.yml)に設定を追加

blazer.ymlに以下のようなSmart Variablesを追加しています。Smart Variablesという機能は、集計SQLの中にパラメータ(この例では{recent_months})を入れると、画面に事前に定義したSmart Variablesのクエリの結果をセレクトボックスとして表示するものです。 Smart Variablesのクエリの結果の1つ目のカラムがセレクトボックスの値になり、表示されるラベルは、2つ目のカラムがラベルになります。。

data_sources:
  main:
    〜〜〜
    smart_variables:
      recent_months:
        select DATE_FORMAT(CURRENT_DATE, '%Y-%m-01'), DATE_FORMAT(CURRENT_DATE, '%Y-%m')
          UNION ALL
        select DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -1 MONTH), '%Y-%m-01'), DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -1 MONTH), '%Y-%m')
          UNION ALL
        select DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -2 MONTH), '%Y-%m-01'), DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -2 MONTH), '%Y-%m')
          UNION ALL
        select DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -3 MONTH), '%Y-%m-01'), DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -3 MONTH), '%Y-%m')
          UNION ALL
        select DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -4 MONTH), '%Y-%m-01'), DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -4 MONTH), '%Y-%m')
          UNION ALL
        select DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -5 MONTH), '%Y-%m-01'), DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -5 MONTH), '%Y-%m')
          UNION ALL
        select DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -6 MONTH), '%Y-%m-01'), DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -6 MONTH), '%Y-%m')
          UNION ALL
        select DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -7 MONTH), '%Y-%m-01'), DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -7 MONTH), '%Y-%m')
          UNION ALL
        select DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -8 MONTH), '%Y-%m-01'), DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -8 MONTH), '%Y-%m')
          UNION ALL
        select DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -9 MONTH), '%Y-%m-01'), DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -9 MONTH), '%Y-%m')
          UNION ALL
        select DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -10 MONTH), '%Y-%m-01'), DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -10 MONTH), '%Y-%m')
          UNION ALL
        select DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -11 MONTH), '%Y-%m-01'), DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -11 MONTH), '%Y-%m')
          UNION ALL
        select DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -12 MONTH), '%Y-%m-01'), DATE_FORMAT(ADDDATE(CURRENT_DATE, INTERVAL -12 MONTH), '%Y-%m')

日付の絞り込みはテーブルの型によりますが、Blazerの画面で以下のようなクエリを追加すると集計できます。

SELECT 
  date,
  count(*)
FROM
  orders
WHERE
  YEAR( date ) = YEAR({recent_months})
    AND
  MONTH( date ) = MONTH({recent_months})
ORDER BY
  date
GROUP BY
  date

画面上のrecent_monthsのセレクトボックスで2020-08を選択すると、以下のクエリが実行されます。

SELECT 
  date,
  count(*)
FROM
  orders
WHERE
  YEAR( date ) = YEAR('2020-08-01')
    AND
  MONTH( date ) = MONTH('2020-08-01')
ORDER BY
  date
GROUP BY
  date

年月日指定

年月日に関してはvariablesの機能で実現できるので、事前に設定ファイルの修正などは必要ありません 集計SQLクエリに{start_time} または {end_time}を含めると、簡単にデータを抽出できます。

{start_time}{end_time}の両方を指定した場合

以下のように {start_time}{end_time}の両方を指定した場合、Today, Last 7 Days, Last 30 Days, Custom Rangeから期間を選択できます。デフォルトはLast 30 Days

f:id:moritamorie:20200821141918p:plain

SQLは以下のような感じです。

SELECT 
  date,
  count(*)
FROM
  orders
WHERE
  date >= {start_time} 
    AND
  date <= {end_time}
ORDER BY
  date
GROUP BY
  date

Custom Rangeを選択すると開始日・終了日を選択できるようになります。

f:id:moritamorie:20200821142525p:plain

{start_time}{end_time}のどちらかを指定した場合

{start_time}{end_time}のどちらかを指定した場合、日付選択だけできます。

f:id:moritamorie:20200821143247p:plain

SQLは以下のような感じです。

SELECT 
  count(*)
FROM
  orders
WHERE
  date ={start_time}

Github actions (image-actions)でWebサイトの画像を常に適切な圧縮サイズに保つ

サイトの画像を変えたりしているうちに気がつかないうちにサイズが大きい画像ファイルが混じっているってことありますよね。サイト表示のパフォーマンスが落ち、離脱に繋がりそうなので避けたいと思っていました。

最近、Githubで管理している画像を自動的に圧縮してくれるGithub actionsのcalibreapp/image-actionsというのを導入することでだいぶ改善しました。

圧縮できる画像があれば以下のようなレポートをPRにつけて、変換した画像を表示してくれます。 自動的にコミットができていて、画像に変換してくれているのを確認できます。

f:id:moritamorie:20200723015918p:plain

メリット

calibreapp/image-actionsを使うことで、

  • 既にcommitしている画像ファイルも変換してくれる
  • 今後、画像を追加したときも自動的に変換してくれる

ということが実現でき

  • 網羅的に対応できるので漏れがない
  • 自動的にやってくれるので手間がかからない

というメリットがあるかと思います

既に圧縮済の画像かどうかを判別する方法として、圧縮サイズの変化が1%未満かどうかで判別しているようです。(参照した実装

コード

公式のものをコピペしただけですが、以下のようなYAMLファイル(パス: .github/workflows/calibreapp-image-actions.yml)を追加するだけです。

name: Compress images
on: pull_request
jobs:
  build:
    name: calibreapp/image-actions
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@master

      - name: Compress Images
        uses: calibreapp/image-actions@master
        with:
          githubToken: ${{ secrets.GITHUB_TOKEN }}

画像を圧縮したくないディレクトリの指定や画像のクオリティの調整などオプションに関しては、公式のREADMEを参照してみてください。

github.com