📝

Pull Request の commit log に「指摘修正」が含まれていたらコメントする

2024/12/23に公開

これは GitHub Advent Calendar 2024 23日目の記事です.

コードレビューで「指摘修正」という commit message を見たことはありませんか. commit message はあとから履歴を見たときに見出しとなる重要な文章です. 「指摘修正」という commit log が連なっているともはや履歴としての意味をなさなくなってしまいます, と先人たちも言っています.

そもそもコードレビューを受けたり、指摘内容を修正したりするのはソフトウェアを開発する過程のひとつにすぎません。
ただの過程(もしくはただの作業)をソフトウェアの歴史として残したとて、後から見た人は「知らんがな」で終わってしまいます。[1]

指摘されたので修正しました〜というメッセージはあとから見たときに有益になることは少ないと思う。[2]

commit message の規約が定まっていれば指摘しやすいですが, そうでない場合は指摘するのも大変です[3]. コードの内容について指摘したら(されたら), commit message の内容にも指摘する(される)というのは心理的なハードルも高く見逃されがちです. こういうときは機械を使って解消します. 今回は GitHub Actions を使って Pull Request の commit log に「指摘修正」が含まれていたらコメント追加します.

完成したものはこちらになります.

Pull Request のコメント. 「指摘事項修正」という commit message に対してコミットメッセージを具体的に書くように指示している

https://github.com/toms74209200/git-message-check-example

name: Check commit message contains 「指摘修正」

on:
  pull_request:
    branches:
      - master

permissions:
  contents: read
  pull-requests: write

jobs:
  check-commit-message:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - id: commit_message
        name: Check Commit Message
        run: |
          echo matches=`git log --format=%B origin/${{ github.base_ref }}..origin/${{ github.head_ref }} -E --grep='(指摘.*修正|レビュー.*修正|指摘.*対応|レビュー.*対応)'` >> $GITHUB_OUTPUT
      - name: Create PR comment
        if: steps.commit_message.outputs.matches
        run: |
          cat  << EOF > comment.md
          ## コミットメッセージは具体的に書きましょう

          コミットメッセージに「指摘修正」や「レビュー修正」などの曖昧な表現が含まれています。
          コミットログは変更履歴の見出しとしての役割を担っているため、より具体的に変更内容について記述すると良いでしょう。
          またコミットメッセージを簡潔に書くことができないような場合は、コミットを複数に分割することを検討してみてください。
          例えば、以下のように書き換えることができます。

          - 「マジックナンバーを定数に置き換え」
          - 「早期リターンを使うように変更」
          EOF
      - name: Add PR comment
        if: steps.commit_message.outputs.matches
        run: |
          gh pr comment ${{ github.event.number }} --body-file comment.md
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

https://github.com/toms74209200/git-message-check-example/blob/ad14017ab9f9c2d9501b51eb907055d11f0666e5/.github/workflows/check-commit-message.yml

実装

実装の方針としては, Pull Request の差分の commit log から「指摘修正」のような特定の文言が含まれていれば, 該当する Pull Request にコメントを追加するとすればよさそうです.

まず Pull Request の差分の commit log を取得します. git log では <commit1>..<commit2> という引数を追加すると commit1 から commit2 までの commit log を取得できます. また GitHub Actions では github context に Pull Request の merge 先 base_ref と merge 元 head_ref があるのでこれらを使って Pull Request の差分の commit log を取得できます[4].

注意すべきは GitHub Actions 上で動かすため, actions/checkoutfetch-depth を適切に設定する必要があります[5]. 今回はめんどうなので fetch-depth: 0 にして全ての commit log を fetch しておきます. また local branch ではないので, branch の ref には origin が必要です(1敗).

ここまでをワークフローの step として書くと以下のようになります.

- uses: actions/checkout@v4
  with:
    fetch-depth: 0
- id: commit_message
  name: Check Commit Message
  run: |
    git log origin/${{ github.base_ref }}..origin/${{ github.head_ref }}

次に commit log から「指摘修正」のような特定の文言が含まれているかを検出します. 流行りのAI? いいえ, 男は黙って正規表現. メンバーの学習によって検出頻度は収束していくはずなので, 検出ロジックはてきとうでも問題ないでしょう.

git log にはそのものずばり --grep があります. 今回は「指摘修正」や「レビュー修正」のような文言を抜き出します. またフォーマットを指定して message だけを取得します.

あとはこれを GITHUB_OUTPUT に入れて後続の step で使えるようにするだけです.

- uses: actions/checkout@v4
  with:
    fetch-depth: 0
- id: commit_message
  name: Check Commit Message
  run: |
    echo matches=`git log --format=%B origin/${{ github.base_ref }}..origin/${{ github.head_ref }} -E --grep='(指摘.*修正|レビュー.*修正|指摘.*対応|レビュー.*対応)'` >> $GITHUB_OUTPUT

この結果をもとに Pull Request にコメントを追加します. Pull Request にコメントを追加する方法については過去に記事を書いているので詳細は以下を参考にしてください.

https://zenn.dev/toms74209200/articles/github-actions-pr-comment

GitHub CLI を使ってコメントを追加するのが簡単です. コメントの内容には「指摘修正」という commit message がよくないということだけではなく, どんな commit message を書くべきかということも記載します. こういうときこそ生成AIの出番です.

- uses: actions/checkout@v4
  with:
    fetch-depth: 0
- id: commit_message
  name: Check Commit Message
  run: |
    echo matches=`git log --format=%B origin/${{ github.base_ref }}..origin/${{ github.head_ref }} -E --grep='(指摘.*修正|レビュー.*修正|指摘.*対応|レビュー.*対応)'` >> $GITHUB_OUTPUT
- name: Create PR comment
  if: steps.commit_message.outputs.matches
  run: |
    cat  << EOF > comment.md
    ## コミットメッセージは具体的に書きましょう

    コミットメッセージに「指摘修正」や「レビュー修正」などの曖昧な表現が含まれています。
    コミットログは変更履歴の見出しとしての役割を担っているため、より具体的に変更内容について記述すると良いでしょう。
    またコミットメッセージを簡潔に書くことができないような場合は、コミットを複数に分割することを検討してみてください。
    例えば、以下のように書き換えることができます。

    - 「マジックナンバーを定数に置き換え」
    - 「早期リターンを使うように変更」
    EOF
- name: Add PR comment
  if: steps.commit_message.outputs.matches
  run: |
    gh pr comment ${{ github.event.number }} --body-file comment.md
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

これですべての step が完成しました.


簡単な機械検出も GitHub Actions なら一瞬で実装できます. どんどん GitHub Actions を使って自動化していきましょう.

脚注
  1. 「コードレビューの修正(1回目)」みたいなコミットメッセージを避ける | FJORD BOOT CAMP(フィヨルドブートキャンプ) ↩︎

  2. 自分の言葉で書かれたコミットメッセージが好き - #june29jp ↩︎

  3. commit message の Lint ツールとして commitlint があります. ↩︎

  4. ワークフロー実行に関するコンテキスト情報へのアクセス - GitHub Docs ↩︎

  5. GitHub Actions workflows で Pull Request の差分コミットだけ fetch する ↩︎

Discussion