はじめに
私の所属しているチームでは、プルリクエストを作成したら
複数人でコードをレビューする運用を行っています。
運用を始めた頃は、チームメンバーを全員を含めたTeamを作成し、
手動でTeamをレビュアーに設定していましたが、以下のような問題がありました。
- Teamのうち一人がapproveすると、レビュアーからTeamが消えてしまう。他のメンバーにもレビューしてもらいたい場合、再度レビュアーを設定する必要がある。(手間だし、忘れてしまうことも)
- そもそもレビュアーを設定し忘れる
そこで、GitHub Actionsを使って、自動でレビュアーをアサインする仕組みを導入しました。
実現したいこと
この記事で実現したいことを簡単にまとめると、以下の通りです。
- プルリクを作成したら、チームのメンバー全員を、自動でレビュアーに指定する。
- Teamのメンバーを変更した場合も、設定ファイルを書き換えずに済むと嬉しい。
- ドラフト作成時にはレビュアーを設定しない。
- レビュー対象はmasterブランチのみ。
レビュアーを自動でアサインする仕組みはいくつかありますが、
上記の要件と合わなかったため、自前のGitHub Actionsを設定することにしました。
事前準備
個人アクセストークンの取得
このページで解説するGitHub Actionsの実行には、admin:org権限をもった個人アクセストークンが必要です。
公式ドキュメントを参考に、トークンを取得します。
このトークンに付与するスコープ、すなわち権限を選択します。 トークンを使用してコマンドラインからリポジトリにアクセスするには、[repo] を選択します。
トークンを取得できたら、リポジトリのSecretsに登録しておきます。
slack通知設定
このページで解説するGitHub Actionsは、GitHubのSlack通知と組み合わせるととても便利です
設定がまだの場合は、設定しておくことを強くオススメします。
GitHub と Slack を連携させる
連携していれば、レビュアーに設定されたら、slackで通知が飛んでくるようになります
GitHub Actionsの設定
以下のymlファイルを、リポジトリの.github/workflows/
配下に設置します。
TODOコメントが入っているところは、任意の値に変更してください。
ファイルの内容については、次で詳しく解説していきます。
name: PR Reviewer Auto Assignment
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
branches:
- master
jobs:
reviewer-assign:
runs-on: ubuntu-latest
env:
API_BASE_URL: "https://api.github.com"
COMMON_HEADER: "Accept: application/vnd.github.v3+json"
ORG: "ORG" # TODO:任意の値に変更する
TEAM_SLUG: "TEAM_NAME" # TODO:任意の値に変更する
if: github.event.pull_request.base.ref == 'master' && github.event.pull_request.draft == false
steps:
- name: Get Members List
id: get-members-list
run: |
response=$(curl -X GET \
-H "$COMMON_HEADER" \
-H "Authorization: token ${{ secrets.ORG_TOKEN }}" \ # TODO:任意の値に変更する
$API_BASE_URL/orgs/$ORG/teams/$TEAM_SLUG/members)
members=$(echo $response | jq '[.[].login | select(. != "${{ github.actor }}")]')
echo ::set-output name=members::$members
- name: Set Reviewers
id: set-reviewers
run: |
curl -X POST \
-H "$COMMON_HEADER" \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
$API_BASE_URL/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/requested_reviewers \
-d '{ "reviewers": ${{ steps.get-members-list.outputs.members }} }'
# 上記処理が失敗した場合、slack通知
error-notifications:
if: failure()
needs: reviewer-assign
uses: REPO/.github/workflows/error-notifications.yml@master # TODO:任意の値に変更する
with:
detail: "レビュアーのアサインに失敗しました。"
トリガーの設定
on
パラメータにpull_request
を指定しています。
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
branches:
- master
types
には以下のものを指定することができ、何も指定しない状態(デフォルト)では★のついたトリガーが指定されています。
- assigned
- unassigned
- labeled
- unlabeled
- opened★
- edited
- closed
- reopened★
- synchronize★
- converted_to_draft
- ready_for_review
- locked
- unlocked
- review_requested
- review_request_removed
- auto_merge_enabled
- auto_merge_disabled
今回は、ドラフト作成後、Ready For Reviewに変更した場合もトリガーに含めたかったので、
デフォルトではなく明示的に指定しました。
使いまわすパラメータは環境変数に設定しました。
jobs:
reviewer-assign:
runs-on: ubuntu-latest
env:
API_BASE_URL: "https://api.github.com"
COMMON_HEADER: "Accept: application/vnd.github.v3+json"
ORG: "ORG" # TODO:任意の値に変更する
TEAM_SLUG: "TEAM_NAME" # TODO:任意の値に変更する
TODOコメントがついているところは、任意の値に変更してください。
ここでは二つの条件を指定しています。
二つの条件をクリアすると、以降のステップが実行されます。
if: github.event.pull_request.base.ref == 'master' && github.event.pull_request.draft == false
一つ目の条件は、baseブランチがmasterであること
です。
自分はbaseブランチがどっちかよくわからなくなってしまうのですが、PRの向き先がbaseブランチです。
二つ目の条件は、draftではないこと
です。
これを指定することで、ドラフト作成時にレビュアーがアサインされるのを防いでいます。
チームメンバーの取得
steps:
- name: Get Members List
id: get-members-list
run: |
response=$(curl -X GET \
-H "$COMMON_HEADER" \
-H "Authorization: token ${{ secrets.ORG_TOKEN }}" \ # TODO:任意の値に変更する
$API_BASE_URL/orgs/$ORG/teams/$TEAM_SLUG/members)
members=$(echo $response | jq '[.[].login | select(. != "${{ github.actor }}")]')
echo ::set-output name=members::$members
一つ目のステップでは、Teamに設定されているメンバーを以下のAPIで取得しています。
チームメンバーの取得は、GITHUB_TOKENでは権限が足りないため、「事前準備」に記載の個人アクセストークンを使用します。
secrets.ORG_TOKEN
はSecretsに登録した際の名前に変更してください。
jq部分がちょっとわかりにくいので解説すると、
responseを配列で扱うために、フィルターを[]で囲んでいます。
jq '[ /*example*/ ]'
本人(github.actor)はレビュアーに指定できないので、ここで除外しておきます。
select(. != "${{ github.actor }}")
echo ::set-output name=members::$members
ここでは何をしているかというと、次のステップから参照できるように、変数members
を設定しています。
他のステップから参照する場合は次のように書きます。
# 書き方
${{ steps.<step-id>.outputs.<変数名> }}
# 例
${{ steps.get-members-list.outputs.members }}
レビュアーのアサイン
- name: Set Reviewers
id: set-reviewers
run: |
curl -X POST \
-H "$COMMON_HEADER" \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
$API_BASE_URL/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/requested_reviewers \
-d '{ "reviewers": ${{ steps.get-members-list.outputs.members }} }'
二つ目のステップでは、一つ目のステップで取得したメンバーをレビュアーにアサインしています。
【おまけ】レビュアーのアサインに失敗した場合
アサインに失敗した場合は、チームのslackに通知するように設定しました。
# 上記処理が失敗した場合、slack通知
error-notifications:
if: failure()
needs: reviewer-assign
uses: REPO/.github/workflows/error-notifications.yml@master # TODO:任意の値に変更する
with:
detail: "レビュアーのアサインに失敗しました。"
slack通知については、【Github Actions】reusable workflowを使って、エラー時にslack通知する
で解説しています。
さいごに
GitHub Actionsを使ったレビュアー自動設定について紹介しました。
実際にこの設定を導入したところ、チーム内でのプルリク作成→レビュー依頼が、スムーズにできるようになったと感じています。
最後までお読みいただき、ありがとうございました