Approve されてもラベルを付けるまでマージできなくする方法
この記事では、Approveされてもラベルを付けるまでマージできないようにする方法について解説します。
背景
とあるプロジェクトで、 GitFeatureFlow というフローを採用しています。
このフローでは、mainブランチからトピックブランチを切って開発し、開発が終わったらmainブランチに向けてプルリクエストを作成します。その後、プログラムのレビューをレビュアーに依頼します。しかし、 Approveされてもすぐにマージできません。QAを依頼し、QAが通過してからマージできます。
この運用において1点懸念がありました。それは、Approveされたプルリクエストはワンクリックでマージできてしまうので、QA未完了の機能が誤ってマージされる可能性があることです。
そこで、私はApproveされてもラベルを付けるまでマージできないようにする仕組みを作りました。これにより、QA未完了の機能がマージされるミスを防ぐことができます。同じようなケースで悩んでいる方の参考になれば幸いです。
実際の動作
実際に動作しているプルリクエストは下記から閲覧できます。
ラベルを付けていない例
ラベルを付けていないのでマージがブロックされている
ラベルを付けた例
ラベルを付けているのでマージができる
方針
- 特定のラベルを付けるまではBranch Protection ruleでマージできないようにする
- セキュリティ上のリスクを軽減するため、GitHub Appを用いずに自前で実装する
ワークフローの作成
そこで、次のようなワークフローを作成しました。
特定のラベル (この例では マージOK
) が付けられたら、プルリクエストの Label Check
checkにsuccessのステータスを付けます。一方、特定のラベルが付けられていない場合は、プルリクエストのchecksにpendingのステータスを付けます。
name: Pull Request
on:
pull_request:
types:
- synchronize
- labeled
- unlabeled
- opened
- reopened
permissions:
statuses: write
jobs:
ready-deploy:
runs-on: ubuntu-latest
name: Label Check
steps:
- name: Set status check to success
if: "contains(github.event.pull_request.labels.*.name, 'マージOK')"
run: |
curl --request POST \
--url https://api.github.com/repos/${{github.repository}}/statuses/${{github.event.pull_request.head.sha}} \
--header 'authorization: Bearer ${{secrets.GITHUB_TOKEN}}' \
--header 'content-type: application/json' \
--data '{
"context": "Label Check",
"state": "success",
"description": "マージできます"
}'
- name: Set status check to pending
if: "!contains(github.event.pull_request.labels.*.name, 'マージOK')"
run: |
curl --request POST \
--url https://api.github.com/repos/${{github.repository}}/statuses/${{github.event.pull_request.head.sha}} \
--header 'authorization: Bearer ${{secrets.GITHUB_TOKEN}}' \
--header 'content-type: application/json' \
--data '{
"context": "Label Check",
"state": "pending",
"description": "\"マージOK\" ラベルを付けるとマージできます"
}'
on
は、プルリクエストの特定のイベントで発火するように設定しています。ちなみに synchronize
は新しいコミットが追加された時に発火します。コミットにstatusが紐づいているため、コミットが増えたら再度statusを付け直す必要があるためです。
permissions
には statuses: write
を設定しています。デフォルトの GITHUB_TOKEN
はステータスを書き換える権限がないため、この設定が必要です。逆に contents
など他の権限は不要です。
step
では、statusのREST APIにPOSTすることでステータスを付けています。
Branch Protection rule の設定
無事に Label Check
checkが付けられるようになったので、次はBranch Protection ruleの設定をします。
Branch Protection ruleは、特定のブランチに対して、マージの条件を設定できます。今回は、Label Check
checkがsuccessになっていることをマージの条件にします。
Settings > Branches > Branch protection rulesから、Branch name patternに main
を設定して、Require status checks to pass before mergingの項目に Label Check
を追加します。
ちなみに、Require branches to be up to date before mergingは、プルリクエストをマージする前に、最新のmainをpullしなければならない制約です。この機能はGitFeatureFlowを使用している場合、マージしてから先にマージされた作業との競合が発覚するリスクを軽減します。オンにしておくのがオススメです。
Branch protection rule の設定画面
Terraformを用いる場合は次のように設定します。
resource "github_branch_protection_v3" "repo" {
repository = github_repository.repo.name
branch = "main"
required_status_checks {
contexts = ["Label Check"]
strict = true # Require branches to be up to date before merging
}
}
まとめ
Approveされても特定のラベルを付けるまでマージできないようにする方法について紹介しました。シンプルなワークフローを書いて、開発者体験を低下させることなくより安全に開発を進められる仕組みを作れました。
Discussion