N番煎じですが、やってみる機会があったので一般化してメモしておきます。
背景: コードレビューを素早く行なうことの重要性
チーム開発で重要なことは色々あります*1が、Pull Requestを出したときに素早くレビューをしてもらえるというのはとにかく重要なことの一つです(日本語版)。
レビュー依頼がきたら今すぐ仕事をやめてレビューをしなければならない、というわけでないですが、一日に2~3回は見るようにしようと思いながら過ごしています。レビュー依頼を手動で「XXXさん(あるいはチーム)、以下のPull Requestのレビューお願いします!」とmentionしてもいいですが、一日に何回も明示的にレビュー依頼をしていると「ちょっとうるさいかもな、まとめて依頼しよう」などを考えてしまうこともあり、案外難しいことだったりします。また、レビューの頻度が人によって異なる場合もありますし「レビュー依頼のPull Requestがあったらなるべく早く見ていくぞ」というチーム文化を作っていくことも重要です。
これを実現するための一つの手段として、定期的なレビュー依頼をBotに自動で行なわせる、というものがあります。前職までの経験でも、これがきちんと機能していたチームは開発体験がすごくよかった印象が強いです。
レビューのフローを整理する
OpenになっているPull Requestをレビュー依頼で通知させればいいかというと、もちろんそんなことはないでしょう。
- 1: Draftになっている下書きはレビュー依頼はまだ不要
- 2: レビューが完了して、修正待ちになっているレビューはまだ不要
特に2の状態になっているか / 本当にレビューが必要な状態かは案外把握が難しいです。GitHubに備わっている機能だけで何とかしようとすると割と面倒だったりするので、Pull Requestのラベルに「レビュー依頼」または「WIP」を用意するのが結果としてシンプルになるかもしれません。
GitHub Actionsでレビュー依頼を自動化する
以上を踏まえて、GitHub Actionsで定期的なレビュー依頼を自動化してみましょう。例えば以下のように書くことができます。GitHub Actions以外で実行してもよいですが、tokenの扱いやgh
コマンドがdefaultで入っているなどを考えると、GitHub Actionsが一番簡単かなと思います。
name: レビュー依頼状態のPull RequestをSlackに通知する on: schedule: # 平日のutc1時=JST10時に実行する。複数時間でレビュー依頼をしたい場合は配列を増やせばOK - cron: '0 1 * * 1-5' jobs: get_pull_requests_review_required: runs-on: ubuntu-latest timeout-minutes: 5 permissions: contents: read pull-requests: read id-token: write outputs: pull_requests_review_required: ${{ steps.set_pull_requests.outputs.value }} steps: - name: Checkout code uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - id: set_pull_requests name: レビューすべきPull Requestを出力に格納する env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | PULL_REQUESTS_REVIEW_REQUIRED=$(gh pr list --state open --search "draft:false review:required -label:WIP" --json 'url,title,author' | jq -c '.') echo "value=$(echo ${PULL_REQUESTS_REVIEW_REQUIRED})" >> $GITHUB_OUTPUT greeting_slack: runs-on: ubuntu-latest timeout-minutes: 5 needs: get_pull_requests_review_required if: "needs.get_pull_requests_review_required.outputs.pull_requests_review_required != '[]'" steps: - name: レビュー依頼の文面を投げる uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 with: channel-id: "C12345abcde" payload: | { "unfurl_links": false, "unfurl_media": false, "text": "以下のPull Requestのレビューをお願いします!" } env: SLACK_BOT_TOKEN: ${{ secrets.SLACL_NOTIFY_PULL_REQUEST_REVIEWS_TOKEN }} notify_slack: runs-on: ubuntu-latest timeout-minutes: 5 needs: - get_pull_requests_review_required - greeting_slack strategy: matrix: pull_request: ${{ fromJson(needs.get_pull_requests_review_required.outputs.pull_requests_review_required) }} steps: - name: 各Pull Requestのリンクを投稿する uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 with: channel-id: "C12345abcde" payload: | { "unfurl_links": false, "unfurl_media": false, "text": "<${{ matrix.pull_request.url }} | ${{ matrix.pull_request.title }}> by ${{ matrix.pull_request.author.login }}" } env: SLACK_BOT_TOKEN: ${{ secrets.SLACL_NOTIFY_PULL_REQUEST_REVIEWS_TOKEN }}
概ね見たまんまですが、見所としてはこんな感じでしょうか。
gh
コマンドが便利- OpenになっているPull Requestやその他細かい条件をさっと書ける、
curl
でエンドポイントをごにょごにょ叩かなくて済む
- OpenになっているPull Requestやその他細かい条件をさっと書ける、
slackapi/slack-github-action
も便利- tokenとchannel-idを用意すればあとはテキストを投げるだけ
strategy.matrix
を使って、動的にワークフローを展開する- 実質的なfor文で並列で処理もしてくれる
- 今回の場合は複数のPull Requestの情報を加工してから一回SlackのAPIを叩けば十分だが、加工を
jq
でやると割と面倒なのでstrategy.matrix
で片づけた*2
WIP
のラベルが付いていないものをレビュー依頼の対象としているので、レビューが完了したらWIP
のラベルを付与する必要があります。レビュアーが毎回ラベルの付与をするのは面倒なので、レビューをSubmitしたらWIP
のラベルを自動的に付与するactionsも同時に用意しておくと便利でしょう。
name: レビューがsubmitされた場合、Pull Requestに付与されているWIPのラベルを自動で外す on: pull_request_review: types: - submitted jobs: remove_wip_label_when_review_submitted: runs-on: ubuntu-latest timeout-minutes: 5 permissions: contents: read pull-requests: write id-token: write repository-projects: read # ref: https://github.com/cli/cli/issues/6274 steps: - name: Checkout code uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: WIPのラベルを外す env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh pr edit ${{ github.event.pull_request.number }} --remove-label WIP
それではよいチーム開発を!