815 文字
4 分

AIなどの特定ユーザーの作成したPRに要求するApproval数を増やす

現時点で Ruleset や Branch protection rules では、ユーザーやヘッドブランチのパターンに応じてルールを適用することはできない。

そのため、AI などの Bot アカウントによって作成された PR に対して、通常よりも厳格なルールを適用したい場合は、GitHub Actions を利用する必要がある。

例:Devin の PR に 2 個以上の Approvals を要求する#

PR が変更または PR がレビューされる度に、現在の Approval 数を確認し、指定された数に達していない場合は失敗したステータスを発行し、指定された数に達した場合は成功したステータスを発行することで実現できる。

この例では Devin を対象にしているが、AI_USERNAME を変更することで任意のユーザーを対象にすることができる。

name: Check Approvals for Devin PRs
on:
pull_request_review:
types: [submitted]
pull_request:
types: [opened, synchronize, reopened]
env:
AI_USERNAME: devin-ai-integration[bot]
REQUIRED_APPROVALS: 2
permissions:
pull-requests: read
statuses: write
jobs:
check-ai-prs:
runs-on: ubuntu-latest
steps:
- name: Check AI PRs
if: github.event.pull_request.user.login == env.AI_USERNAME
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
// 略:GitHub Scripts部分を参照
- name: Skip Check (Not an AI PR)
if: github.event.pull_request.user.login != env.AI_USERNAME
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { owner, repo } = context.repo;
await github.rest.repos.createCommitStatus({
owner,
repo,
sha: context.payload.pull_request.head.sha,
state: 'success',
context: `AI Approval Requirement`,
description: 'This PR was not created by the AI bot. Skipping approval check.',
target_url: `https://github.com/${owner}/${repo}/actions/runs/${{ github.run_id}}`
});

GitHub Scripts 部分:

/*レビューの取得 */
const { owner, repo } = context.repo;
// pull_request_reviewの場合でもpull_requestと同様に取得できる
const pr = context.payload.pull_request;
const requiredApprovals = ${{ env.REQUIRED_APPROVALS }};
const { data: reviews } = await github.rest.pulls.listReviews({
owner,
repo,
pull_number: pr.number
});
/* 最終的なステータスがApprovedのユーザーを取得 */
const approvers = new Set();
const latestReviewStates = new Map();
for (const review of reviews) {
// 後からコメントされたケースでもApprovedとして扱われるためコメントは無視
if (review.state === 'COMMENTED') {
continue;
}
latestReviewStates.set(review.user.login, review.state);
}
for (const [user, state] of latestReviewStates.entries()) {
if (state === 'APPROVED') {
approvers.add(user);
}
}
console.log(`Current unique approvers: ${approvers.size} (${Array.from(approvers).join(', ')})`);
/* 状況に合わせてステータスを発行 */
const isSuccess = approvers.size >= requiredApprovals;
await github.rest.repos.createCommitStatus({
owner,
repo,
sha: pr.head.sha,
state: isSuccess ? 'success' : 'failure',
context: `AI Approval Requirement`,
description: isSuccess
? 'All required approvals have been received.'
: `Waiting for ${requiredApprovals - approvers.size} more approval(s).`,
target_url: `https://github.com/${owner}/${repo}/actions/runs/${{ github.run_id}}`
});

ルールの設定とステータスを発行する理由#

このワークフローによって発行されるステータス(例ではAI Approval Requirement)を Ruleset や Branch protection rules で必須にすることで、Devin の PR に対しては 2 個以上の Approval がないとマージが出来ないようになる。

ワークフロー自体のステータスではないため注意。

どのトリガーに対しても常に同じステータスを発行してほしい場合は、実行したワークフローのステータスとは別に GitHub Status API を利用してステータスを発行し、そのステータスを扱う必要がある。

なぜなら、GitHub Actions で自動的に生成されるステータスがトリガー毎に生成される上、ルールで指定した場合すべてのトリガーで success することが要求されるようになってしまうためである。具体的に例ではCheck Approvals for Devin PRs (pull_request)Check Approvals for Devin PRs (pull_request_review)の 2 つを満たす必要が発生するが、pull_requestの方はレビューで発火しないため approvals が 2 個以上になっても失敗したままになってしまう。

AIなどの特定ユーザーの作成したPRに要求するApproval数を増やす
https://blog.ohirunewani.com/posts/github-actions-more-approvals-required-for-specific-users-prs/
作者
hrdtbs
公開日
2025-04-29
ライセンス
CC BY-NC-SA 4.0