目次

  1. この記事で学べること
  2. 想定読者
  3. はじめに
  4. GitHub の Branch Protection Rules より柔軟な制御をしたいとき、ありませんか?
  5. Commit Status を使った approve 数制御の仕組み
  6. approval-rules の紹介と使い方
  7. まとめ
  8. 参考リンク

この記事で学べること

  • 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 のイメージ

アイデア

Commit Status を Branch Protection の「Required status checks」と組み合わせると、特定の Commit Status が success でなければマージをブロックする、という制御が可能になります。

今回はこの仕組みを、以下のように approve 数の判定に応用しました。

  1. PR のレビューイベント(pull_request_review)をトリガーに GitHub Actions を起動
  2. Actions 内で PR のレビュー状態を取得し、定義したルールに基づいて必要な approve 数を判定
  3. 条件を満たしていれば Commit Status を success、満たしていなければ pending に設定
  4. 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 上では以下のように表示されます。

Approve 数が足りない場合の Commit Status

Approve 数が足りた場合の Commit Status

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 数を柔軟に変えたい方は、このアイデアをぜひ活用してみてください。

参考リンク

今回の技術選定や実装にあたって、以下の記事を参考にさせていただきました。