png 画像のファイルサイズを節約できるかをチェックする GitHub Actions を作った

Posts

リポジトリ内の png 画像のファイルに対し、圧縮してファイルサイズを減らすことができるかチェックする、GitHub Actions(action-png-size-lint)を作りました。

The GitHub Action is that check file size if png images can be reduced. - GitHub - chick-p/action-png-size-lint: The GitHub Action is that check file size if png images can be reduced.
GitHub

このアクションでは、zopflipng を使って png ファイルの圧縮後のサイズを算出し、ファイルサイズを減らせるようであればエラーで CI を落とします。

モチベーション

GitHub.com では、ひとつのリポジトリのサイズを 5GB 未満にすることを推奨しています
リポジトリのサイズが大きくなると、リポジトリのクローンなどの Git の操作に時間がかかります。
たとえばブログのようなデータを管理する場合、リポジトリのサイズが大きくなる要因のひとつとして、たくさんの画像ファイルを管理することが考えられます。
できればコミットするときに圧縮済みの画像ファイルをコミットしたいところですが、つい圧縮作業をするのを忘れてしまいます。
そのため、Pull Request を作成した段階でファイルサイズを減らすことができるかを確認できるようにしたいと考えました。

関連する GitHub Actions

今回のアクションと同じように、画像ファイルを圧縮できる GitHub Actions には、calibreapp/image-actions があります。
calibreapp/image-actions は、その名のとおりオープンソースの電子書籍ビューアーである calibre を使っています。
今回のアクションと calibreapp/image-actions との大きな違いは、次の 2 つです。

  • image-actions では png 形式以外の画像ファイルにも対応している
  • エラーで CI を落とすのではなく、圧縮した画像ファイルをコミットする

今回作ったアクションでは、圧縮後のファイルをコミットせずにエラーで落とすようにしました。
なぜなら、コミットを作ってしまうとリポジトリサイズの削減には貢献しないからです。
圧縮したファイルを含むコミットを作ると、リポジトリには圧縮前と後の 2 つのコミットが存在することになります。
Squash してコミットをまとめれば良いのですが、CI にそこまでさせるには強力すぎではと考えました。

Actions の使い方

ディレクトリの画像パスを [object Object] に指定する

GitHub Actions のステップに次のアクションを指定します。
入力には次の 2 つの変数を設定します。

  • image-paths:チェック対象の画像ファイルのパス
  • limit:CI を落とす、ファイルのサイズ削減が可能な割合のしきい値
    たとえば「90」を指定すると、元のファイルサイズの 90% よりもサイズを小さくできそうであればエラーになります。
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: chick-p/action-png-size-[email protected]
        with:
          image-paths: |
            fixtures/**/*.png
          limit: 90

変更した画像だけをチェックする(2022年8月27日追記)

ユースケースとして変更したファイルだけチェックすることが想定されます。
image-paths に指定したパスの png 画像がチェック対象になるため、ワークフロー側でファイルだけに絞り込んで image-paths に渡すと、変更したファイルだけをチェックできます。

lint.yml
on:
  pull_request:
    paths:
      - "*.png"

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/[email protected]
        with:
          fetch-depth: 100

      - name: "Diff files"
        run: |
          {
            echo 'CHANGED_FILES<<EOF'
            git diff ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} --diff-filter=AM --name-only
            echo 'EOF'
          } >> "$GITHUB_ENV"

      - uses: chick-p/action-png-size-[email protected]
        with:
          image-paths: ${{ env.CHANGED_FILES }}
          limit: 90

今後実装したい機能

除外対象を指定できるようにする

GitHub Actions の on.pull_request.paths-ignore のように除外対象を指定できるようにしたいです。