🐡

PRの差分に応じてコメントするGitHub Actionsを作って公開した

2023/02/28に公開

はじめに

自分のチームでは開発のフレームワークにスクラムを採用しており、Google が提唱したFour Keysを元に開発生産性の向上に取り組んでいます。その中でデプロイ頻度や変更のリードタイムを改善する目的として、PR の差分をチーム内で決めた行数以下にするというルールを導入しています。

これによって PR の粒度が細かくなるので、レビューのコストが大幅に減ります。また、実装の方向性が間違っている場合も早期に気づけるので、手戻りの発生を未然に防ぐことができます。

しかし、この変更差分を特定に行数以下に収めること自体は個人の努力義務になっています。
そこで、このルールの促進と変更行数に関する口頭の指摘を防ぐことを目的として、PR の変更行数に応じてコメントをする GitHub Actions を作成しました!
今回は作成した GitHub Actions について紹介したいと思います!

今回紹介する GitHub Actions は Marketplace にも公開してあり、簡単に導入できるので興味のある方はぜひ使ってみてください!
https://github.com/marketplace/actions/review-git-diff-action

作成した GitHub Actions

今回作成した GitHub Actions の全体像は下記になります。

https://github.com/KazukiHayase/review-git-diff-action/blob/main/action.yml

処理の流れ

1. inputsのバリデーション

inputsとして

  • threshold:変更行数の上限
  • message:上限を超えた際のメッセージ

を受け取ります。
それぞれがちゃんとセットしてあるかをチェックします。

2. 変更行数の計算

ベースブランチの最新のコミットと、headのコミットの差分を計算します。git diff --numstatで追加・削除された行数を出力して、awkコマンドでそれぞれを足し合わせて変更行数を算出します。

3. 変更行数の評価

inputsで受け取った変更行数の上限と、2 で計算した実際の変更行数を比較します。

4. PR にコメント

3 で変更行数が上限を超えている場合、PR にコメントをします。

詰まった箇所

inputsのバリデーションは手動で行う必要がある

inputsthresholdmessageにはrequired: trueを指定しています。ただ、required: trueを指定しても値が設定されているかは検証されません。こちらに関しては Issue でも議論されています。
そのため今回は Issue に載っていた方法を用いて、明示的にinputsの検証をすることにしました。

- name: Validate inputs
  run: |
    [[ "${{ inputs.threshold }}" ]] || { echo "threshold input is empty" ; exit 1; }
    [[ "${{ inputs.message }}" ]] || { echo "message input is empty" ; exit 1; }
  shell: bash

ifでの比較が文字列として評価されてしまう

最初は PR にコメントをするステップの条件は下記のように記載していました。

if: env.GIT_DIFF > inputs.threshold

ただこれだと文字列の比較として扱われてしまい、期待する挙動にならないことがありました。
そのため、変更行数の評価は shell のexprコマンドを使用して比較を行い、結果をアウトプットとして出力するようにしました。そのアウトプットをifで評価することで PR にコメントをするステップの実行を制御しています。

- name: Evaluate Git diff
  id: evaluate_git_diff
  run: |
    diff=${{ env.GIT_DIFF }}
    threshold=${{ inputs.threshold }}
    result=$([ "$(expr $diff \> $threshold)" = 1 ] && echo "true" || echo "false")
    echo "should_post_comment=$result" >> $GITHUB_OUTPUT
  shell: bash

- name: Post comments
  if: steps.evaluate_git_diff.outputs.should_post_comment == 'true'
  # 省略

まとめ

やりたいことはシンプルだったのですが、いざ作ってみると意外と詰まる箇所があったのでいい勉強の機会になりました。
自動生成の差分は除外するなどいくつかやりたいことはあるので、今後も改善を進めていこうかなと思っています。

株式会社BuySell Technologies

Discussion