目次
- この記事で学べること
- 想定読者
- はじめに
- GitHub の Branch Protection Rules より柔軟な制御をしたいとき、ありませんか?
- Commit Status を使った approve 数制御の仕組み
- approval-rules の紹介と使い方
- まとめ
- 参考リンク
この記事で学べること
- GitHub の Branch Protection だけでは実現できない、条件付き approve 数制御の考え方
- Commit Status を活用した柔軟なマージ制御の仕組み
- Custom GitHub Action approval-rules の導入方法と設定例
想定読者
- GitHub でのコードレビュー運用を改善したいエンジニア
- Branch Protection の approve 数設定に不便さを感じている人
- 自動生成 PR やドキュメント PR のレビューフローを効率化したい人
はじめに
株式会社 WinTicket でエンジニアをしている谷中(@azoookid)です。
Web チームに所属し、WINTICKET Web 版の開発を担当しています。
今回は、Web チームでの開発における approve 数管理の課題を解決するために、GitHub の Commit Status を活用した仕組みを導入したので、その内容を紹介します。
同じような課題を抱えている方の参考になれば幸いです。
GitHub の Branch Protection Rules より柔軟な制御をしたいとき、ありませんか?
GitHub の Branch Protection Rules には「Required approvals」という設定があり、PR をマージするために必要な approve 数を指定できます。しかし、この設定はリポジトリ(ブランチ)単位で一律にしか適用できません。
WINTICKET Web チームでは、コード品質を担保するために 3 approve を必須として運用してきました。しかし、すべての PR に対して一律 3 approve を求めるのは、運用上負担が大きいケースがありました。
具体的には、以下のような PR です。
Renovate による依存更新 PR
JavaScript エコシステムに乗っている Web アプリケーションのため、Renovate による依存更新 PR が頻繁に作成されます。量も多いため、各々が動作確認する前提で 1 approve でマージできるのが理想です。
API 定義変更に伴う infra 層再生成 PR
サーバーの API 定義変更により Web の infra 層再生成 PR が自動で作成されます。自動生成された差分なので複数人でのレビューは不要であり、1 approve でマージできるのが理想です。
リリース PR
リリース時は設定ファイルのバージョンをインクリメントする PR が作成されます。この PR をマージすることで、Staging 環境へ差分がリリースされ動作確認ができます。
リリース差分の確認は別プロセスで行っているため、PR マージ自体は 1 approve でできるのが理想です。
技術検証中のE2Eテストシナリオ実装 PR
WINTICKET Web では現在 Playwright を用いた E2E テストの検証を行っています。テストシナリオは monorepo でアプリケーションコードと同じリポジトリに置いていますが、検証スピード向上のため E2E テストファイルへの変更のみの PR は 1 approve でマージできるのが理想です。
総じて、メインアプリケーションコードの品質に直接関わらないような差分については approve 数を減らした運用にしたいというモチベーションがありました。
Commit Status を使った approve 数制御の仕組み
GitHub Commit Status とは
Commit Status は、特定のコミットに対して外部システムから success / pending / failure / error の状態を付与できる GitHub の機能です。GitHub Actions の Check Runs とは別に、REST API 経由で任意のステータスを書き込むことができます。

アイデア
Commit Status を Branch Protection の「Required status checks」と組み合わせると、特定の Commit Status が success でなければマージをブロックする、という制御が可能になります。
今回はこの仕組みを、以下のように approve 数の判定に応用しました。
- PR のレビューイベント(
pull_request_review)をトリガーに GitHub Actions を起動 - Actions 内で PR のレビュー状態を取得し、定義したルールに基づいて必要な approve 数を判定
- 条件を満たしていれば Commit Status を
success、満たしていなければpendingに設定 - Branch Protection で該当の Commit Status を Required status check に設定
実際にルール評価と Commit Status 書き込みを行っているコードの抜粋です。
// 1. PR のレビュー一覧から、各ユーザーの最新レビュー状態を取得
const latestReviewByUser = new Map<string, { submittedAt: Date; state: string }>();
for (const review of reviews) {
// approve 後のコメントで状態が上書きされないよう COMMENTED は無視
if (review.state === "COMMENTED") continue;
const submittedAt = new Date(review.submitted_at ?? "");
const reviewer = review.user?.login ?? "";
const existing = latestReviewByUser.get(reviewer);
if (!existing || existing.submittedAt < submittedAt) {
latestReviewByUser.set(reviewer, { submittedAt, state: review.state });
}
}
// 2. 現在の approve 数をカウント
const approvalCount = [...latestReviewByUser.values()].filter((r) => r.state === "APPROVED").length;
// 3. ルールを先頭から順に評価し、最初にマッチしたルールで判定
const satisfiedRule = approvalRules
.map((rule) => validateApprovals({ rule, reviews, payload, changedFiles }))
.find((result) => result != null);
// 4. マッチしたルールに基づいて Commit Status を書き込み
if (satisfiedRule != null) {
await octokit.rest.repos.createCommitStatus({
owner,
repo,
sha: headSha,
state: satisfiedRule.approved ? "success" : "pending",
context: "PR Approval Check",
description: `${satisfiedRule.approved ? "Approved" : "Needs more approvals"} (${satisfiedRule.approvalCount}/${satisfiedRule.rule.requires.count})`,
});
}
approve 数が足りない場合は pending、足りている場合は success になり、PR 上では以下のように表示されます。


GitHub 標準の「Required approvals」を 0 に設定し、マージ可否の判定を Commit Status 側に委ねることで、柔軟な approve 数制御が実現できます。
(WinTicket の GitHub では、 org の方針として最低 1 approve は必須になっています。そのため、Web チーム管理レポジトリでは「Required approvals」は 1 に設定しています)
既存ツールとの比較
同様のアプローチをとるツールとして、Palantir 社の policy-bot があります。policy-bot は高機能ですが、以下の理由から自作を選択しました。
- セルフホストが前提で、さらに Webhook を受け取る GitHub App の整備も必要になり、導入コストが高かった
- Organization 全体を横断的に管理するユースケース向きで、今回のようにリポジトリ単位で細やかな制御をしたいケースにはオーバースペックだった
GitHub Actions だけで完結する軽量なソリューションが欲しかったため、Custom GitHub Action として実装しました。
approval-rules の紹介と使い方
OSS として WinTicket/approval-rules で公開しています。
ワークフローの設定例
JSON 形式でルールを定義し、GitHub Actions で実行することで、柔軟な approve 数制御が可能です。
JSON ルール定義 (approval-rules.json)
[
{
"name": "Requires 1 approve for Renovate PR",
"if": {
"has_author_in": {
"users": ["renovate[bot]"]
}
},
"requires": {
"count": 1
}
},
{
"name": "Requires 1 approve for release PR",
"if": {
"from_branch": {
"pattern": "release/.*"
}
},
"requires": {
"count": 1
}
},
{
"name": "default",
"requires": {
"count": 3
}
}
]
GitHub Workflow
name: PR Approval Check
on:
pull_request_review:
types: [submitted, dismissed]
pull_request:
types: [opened, synchronize]
jobs:
check-approvals:
runs-on: ubuntu-latest
steps:
- name: Check Approval Rules
uses: WinTicket/approval-rules@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
現時点(2026/03/09)では以下 3 条件に対応しています。
- PR 作成者が誰であるか
- PR ブランチ名がどのパターンにマッチするか
- PR の変更ファイルパスがどのパターンにマッチするか
現状は WINTICKET での開発に必要な条件をベースに実装していまが、今後必要に応じて拡張していく予定です。
具体的な実装に興味のある方は WinTicket/approval-rules のコードをご覧ください。
注意点
Commit Status の書き換えリスク
この仕組みは Commit Status を利用してマージ可否を制御しています。そのため悪意のある PR 作成者が、Commit Status に write 権限のある GITHUB_TOKEN を使用し、ワークフロー内や API 経由で直接 success ステータスを書き込むことで、approve 数のチェックを意図的にバイパスできてしまいます。
厳密なセキュリティ保証が必要な場合は、独立した認証情報で動作する GitHub App として運用する policy-bot などの導入を検討してください。
GitHub API のレートリミット
この Custom GitHub Action は GitHub API を呼び出すため、呼び出し回数が多いとレートリミットに引っかかる可能性があります。大規模な開発で多数の PR が短期間に作成される場合は、専用の GitHub App を用意することも検討してください。
詳細は GitHub API のドキュメントをご覧ください。
まとめ
GitHub の Branch Protection Rules の「Required approvals」は一律設定しかできませんが、Commit Status と GitHub Actions を組み合わせることで、条件に応じた柔軟な approve 数制御が実現できます。
この仕組みを利用した Custom GitHub Action(WinTicket/approval-rules)を OSS として公開しています。
ワークフローに追加するだけで導入でき、セルフホストのインフラは不要です。
AI Agent による PR 生成が増えてきている今、複数人がチェックするほどでない差分については、なるべくレビュー負担を減らしてマージできるようにしたいといったニーズも今後増えてくるのではないでしょうか。
様々な条件に応じて approve 数を柔軟に変えたい方は、このアイデアをぜひ活用してみてください。
参考リンク
今回の技術選定や実装にあたって、以下の記事を参考にさせていただきました。
