🏹

変更があるときだけコミット [GitHub Actions]

2022/02/04に公開
1

概要

https://zenn.dev/snowcait/articles/18c9137f49e378
以前書いたこの記事のリライトです。
continue-on-error が使えるようになったので綺麗に書けるようになりました。

コード

.github/workflows/commit.yml
name: Commit

on:
  pull_request:

jobs:
  commit:
    runs-on: ubuntu-20.04
    timeout-minutes: 5
    
    steps:
      - run: cat $GITHUB_EVENT_PATH
      - uses: actions/checkout@v2.4.0
        with:
          ref: ${{ github.head_ref }}
      - run: ./script.sh
      - name: Diff
        id: diff
        run: |
          git add -N .
          git diff --name-only --exit-code
        continue-on-error: true
      - name: Commit & Push
        run: |
          set -x
          git config user.name github-actions[bot]
          git config user.email 41898282+github-actions[bot]@users.noreply.github.com
          git add .
          git commit --author=. -m 'generated'
          git push
        if: steps.diff.outcome == 'failure'

解説

checkout

PR が作成されたときに何かしらツールを実行してそのブランチにコミットすることが多いのではないかと思います。
pull_request イベントの場合 GITHUB_REF にはマージブランチ (refs/pull/:prNumber/merge) が入ります。
マージブランチだとマージ先の変更も含んでしまうので head ブランチにチェックアウトします。

push イベントの場合は GITHUB_REF に head ブランチが入るので ref は指定不要です。

script

ツール等を実行します。

diff

git diff--exit-code を付けると差分があった場合に終了コード 1 を返します。
差分がない場合は 0 で正常終了します。
--name-only は付けても付けなくても構いません。
標準出力が不要な場合は代わりに --quiet を付けます。

通常の git diff だと新規ファイルが認識されないので git add -N . しておきます。

continue-on-error: true を設定し終了コードに依らず処理を続行します。

全体の結果を failure にしたい場合

全体の結果を failure にしたい場合は continue-on-error は不要です。
代わりに commit の if に failure() を追加してください。

      - name: Diff
        id: diff
        run: |
          git add -N .
          git diff --name-only --exit-code
      - name: Commit & Push
        run: |
          set -x
          git config user.name github-actions[bot]
          git config user.email 41898282+github-actions[bot]@users.noreply.github.com
          git add .
          git commit --author "$(git log --pretty=format:"%an <%ae>")" -m 'generated'
          git push
        if: failure() && steps.diff.outcome == 'failure'

もしくは continue-on-error: true のまま push の後で exit 1 します。

      - name: Diff
        id: diff
        run: |
          git add -N .
          git diff --name-only --exit-code
        continue-on-error: true
      - name: Commit & Push
        run: |
          set -x
          git config user.name github-actions[bot]
          git config user.email 41898282+github-actions[bot]@users.noreply.github.com
          git add .
          git commit --author "$(git log --pretty=format:"%an <%ae>")" -m 'generated'
          git push
          exit 1
        if: steps.diff.outcome == 'failure'

commit

Committer として github-actions[bot] を設定します。
メールを 41898282+github-actions[bot]@users.noreply.github.com にしておくとアイコンが表示されるようです。
https://github.com/actions/checkout/issues/13#issuecomment-724415212

Author として head コミットの Author を設定します。(最終コミットに依存した自動生成を想定)
--author=. は直近のコミットの情報を取得します。
--author="$(git log --pretty=format:"%an <%ae>")" などでも良さそうです。

push イベントの場合にペイロードから取得する例

ペイロードから取得することもできます。

        run: |
          set -x
          git config user.name github-actions[bot]
          git config user.email 41898282+github-actions[bot]@users.noreply.github.com
          git add .
          git commit --author="$AUTHOR" -m 'generated'
        env:
          AUTHOR: ${{ github.event.head_commit.author.name }} <${{ github.event.head_commit.author.email }}>

diff ステップの結果が steps.diff.outcome に入っています。
failure だった場合に実行することで差分があるときにだけコミットします。

余談: steps.diff.conclusion

全体の結果は steps.diff.conclusion に依存します。
continue-on-errortrue のときは常に success ですが false のときは差分があれば failure になります。

Discussion

雪猫雪猫

--author=. は直前がマージコミットだったときに意図しないユーザーが author になる問題がある。
PR の作成者を author とするか、なくしてしまって github-actions[bot] としてコミットする方がいいのかもしれない。