n8n×GitHub APIでPRレビュー自動化フローを構築する
n8nとGitHub APIを連携し、PRオープンからレビュアーアサイン・CI待機・squash mergeまでを自動化するワークフロー構築手順を解説。
チームのコードレビューが滞っていませんか?
Pull Requestを出したはいいものの、誰にレビューを頼めばいいか迷う。 レビュー依頼を出したきり数日間放置されてしまう。 CIが通ったかどうかを毎回手動で確認しに行く手間が地味につらい。 マージ後にソースブランチの削除を忘れてリポジトリが散らかる一方になる。
こうした「人間のすき間に落ちるタスク」が積み重なると、開発サイクルが目に見えない形で遅くなります。 本記事では n8n と GitHub REST API を組み合わせ、PRオープンからレビュアーアサイン・Slack通知・CI待機・squash mergeとブランチ削除までを一本のワークフローで自動化する手順を解説します。 既存のSlack環境やGitHubリポジトリをそのまま使えるため、追加ツールのコストや学習コストを最小限に抑えながら導入できます。
n8nとGitHub APIで実現するPRライフサイクル自動化
n8n はノーコード/ローコードで複数のサービスを連携できるオープンソースのワークフロー自動化ツールです。 セルフホスト版を使えばソースコードやトークンを社外に出さずに運用でき、セキュリティポリシーが厳しい現場でも採用しやすいのが特徴です。 n8nのクラウドホスト版(n8n.cloud)であれば自前のサーバー管理が不要で、まず試してみたいチームに向いています。
今回構築するフローの全体像は次のとおりです。
- GitHubでPRがオープンされる
- n8nのWebhookエンドポイントがイベントを受信する
- GitHub REST APIでレビュアーを自動アサインする
- Slackにレビュー依頼通知を送る
- n8nのScheduleトリガーがCI StatusをAPIでポーリングする
- 全チェックが通ったらSlackに承認依頼を送る
- 承認操作後にsquash mergeを実行する
- マージ後にソースブランチを自動削除する
各ステップにエラーハンドリングとリトライを組み込むことで、GitHub APIのレート制限にも対応できます。 最初から全ステップを実装する必要はなく、STEP 1〜2の通知自動化から段階的に追加していくアプローチが実践的です。
STEP 1: PATの発行とn8n Webhookの設定
GitHub Personal Access Tokenを発行する
n8nからGitHub REST APIを呼び出すにはPersonal Access Token(PAT)が必要です。 GitHubのSettings → Developer settings → Personal access tokensから新しいトークンを発行します。
Classic tokenの場合は次のスコープを付与します。
repo(プライベートリポジトリも操作する場合)read:org(Organization内のユーザー情報取得)
Fine-grained tokenを使う場合は対象リポジトリを限定した上で、Pull requests(読み書き) と Commit statuses(読み取り) の権限を付与します。 発行したトークンは必ずn8nのCredentials(GitHub認証)として登録し、フロー内に直接貼り付けないようにします。 トークンを直接設定ファイルに書き込むと、設定の誤公開やリポジトリ漏洩時に認証情報が流出するリスクが生じます。
n8nのWebhookノードを設定する
n8nのUIで新しいワークフローを作成し、最初のノードとして Webhook ノードを配置します。
HTTP Methodは POST、パスは /github-pr-webhook のように任意の文字列を指定します。
「Webhook URL」に表示されるURLをコピーし、GitHubリポジトリのSettings → Webhooks → Add webhookに貼り付けます。
Content typeは application/json、Secretは任意の文字列を設定して控えておきます。
Eventsは Let me select individual events を選び、Pull requests と Pull request reviews にチェックを入れます。
GitHubからのリクエストが正規のものかどうか確認するため、署名検証を実装します。 Function ノードをWebhookノードの直後に配置して以下のコードを記述します。
const crypto = require('crypto');
const secret = $env.GITHUB_WEBHOOK_SECRET;
const payload = JSON.stringify($input.item.json.body);
const sig = $input.item.json.headers['x-hub-signature-256'];
const computed =
'sha256=' +
crypto.createHmac('sha256', secret).update(payload).digest('hex');
if (sig !== computed) {
throw new Error('Invalid webhook signature');
}
return $input.item;
$env.GITHUB_WEBHOOK_SECRET はn8nの環境変数として設定しておきます。
この検証を入れておくことで、第三者がエンドポイントを叩いてもフローが誤作動しません。
環境変数はn8nの Settings → Environment Variables 画面から追加できます。
STEP 2: レビュアーを自動アサインしてSlackに通知する
Webhookイベントの action フィールドが opened または reopened の場合のみ後続処理を行います。
IF ノードを使って次の条件を設定します。
- 条件式:
{{ $json.body.action === 'opened' || $json.body.action === 'reopened' }}
条件を満たさないイベント(labeled・synchronize など)は別ブランチに流し、ログに記録しておくと後からデバッグしやすくなります。
GitHub REST APIでレビュアーをアサインする
HTTP Request ノードを配置し、GitHub REST APIを呼び出してレビュアーをアサインします。 設定項目は次のとおりです。
- Method:
POST - URL:
https://api.github.com/repos/{{ $json.body.repository.full_name }}/pulls/{{ $json.body.pull_request.number }}/requested_reviewers - Authorizationヘッダー:
Bearer {{$credentials.githubPat}} - Content-Type:
application/json - Body:
{"reviewers": ["alice", "bob"], "team_reviewers": []}
レビュアーのリストをハードコードしたくない場合は、GitHubの CODEOWNERS ファイルを読み込んで変更ファイルのパスと照合するロジックを Function ノードで実装すると、より動的なアサインが可能になります。
CODEOWNERSの記法では src/components/ @alice のようにディレクトリ単位でオーナーを定義できます。
Slackへのレビュー依頼通知を送る
続けて Slack ノードを配置し、レビュー依頼メッセージを送信します。
チャンネルはチーム共通の #dev-review などを指定し、メッセージには次の情報を含めると受け取る側がすぐに判断できます。
- PRタイトル(
$json.body.pull_request.title) - PRオーナーのGitHubユーザー名
- PR URL(
$json.body.pull_request.html_url) - 変更ファイル数と追加・削除行数
n8nのSlackノードでは blocks 形式でボタン付きのリッチなメッセージも送れます。
まずはシンプルなテキスト通知から始め、チームの運用に合わせて後からリッチ形式に変更するとよいでしょう。
STEP 3: CI Status Checkをポーリングして承認依頼を送る
CIが通ったかどうかをリアルタイムで知るには、GitHub Webhooksの check_suite や check_run イベントを受信する方法と、REST APIを定期ポーリングする方法の2つがあります。
ポーリング方式はセットアップが単純で、CI環境側の設定変更が不要なため導入しやすいです。
Scheduleトリガーで5分おきにポーリングする
新しいワークフローを作成し、Schedule ノードを先頭に配置します。 インターバルは5分に設定します。
次に HTTP Request ノードでオープン中のPR一覧を取得します。
- Method:
GET - URL:
https://api.github.com/repos/{owner}/{repo}/pulls?state=open&per_page=100
取得したPRのSHAを使って、SplitInBatches ノードで1件ずつ処理し、各PRのCheck Runsを確認します。
- Method:
GET - URL:
https://api.github.com/repos/{owner}/{repo}/commits/{{ $json.head.sha }}/check-runs
レスポンスの check_runs 配列を Function ノードでフィルタリングし、全ての conclusion が success かつ status が completed になっているPRだけを次のノードに渡します。
まだCIが実行中のPRは次回のポーリングサイクルまで自動的に待機します。
承認依頼メッセージをSlackに送る
条件を満たしたPRがある場合、Slackの #dev-review チャンネルに承認依頼メッセージを送ります。
この時点でレビュアーのApprovalがまだ揃っていない場合は、Pull Request Reviews APIで確認してからメッセージを送るようにすると二重通知を防げます。
- Method:
GET - URL:
https://api.github.com/repos/{owner}/{repo}/pulls/{pull_number}/reviews
全レビュアーから APPROVED ステータスが揃っている場合のみSlackへ承認依頼を送ります。
こうすることで「CIが通った、かつレビューも完了した」というタイミングで正確にマージ準備完了を伝えられます。
同じPRへの重複送信を防ぐために、n8nの Static Data 機能を使って「既に通知済みのPR番号セット」をワークフロー内に保持しておくとよいです。
STEP 4: squash mergeとブランチの自動削除
Slackからの承認操作をn8nで受け取るには、Slack Interactivity(ボタン付きメッセージ)を使います。 n8nのWebhookノードをSlackのInteractivity Request URLに設定することで、ボタンのクリックイベントをn8nに送れます。 Slack API側でInteractivity & Shortcutsの設定画面を開き、Request URLにn8nのWebhook URLを貼り付けます。
承認Webhookを受け取ったら、以下の順序で処理します。
squash mergeの実行
Method: PUT
URL: https://api.github.com/repos/{owner}/{repo}/pulls/{pull_number}/merge
Body (application/json):
{
"merge_method": "squash",
"commit_title": "PRタイトル (#PR番号)",
"commit_message": "PRの本文テキスト"
}
squash mergeにすることで、PR上の細かいコミット履歴をmainブランチに持ち込まず1コミットにまとめられます。
これにより git log がすっきりし、後からの変更追跡や git bisect が容易になります。
n8nのExpression機能を使ってPRのタイトルと番号を動的に埋め込むと、コミットメッセージの統一感を保てます。
ソースブランチの削除
mergeが成功したら、続けてブランチを削除します。
- Method:
DELETE - URL:
https://api.github.com/repos/{owner}/{repo}/git/refs/heads/{{ $json.prHeadRef }}
ブランチ名は前のノードでPRのメタデータ(pull_request.head.ref)から取得しておき、n8nの変数として引き渡します。
ブランチ削除後にSlackへ「マージ完了」通知を送ると、チーム全員が状況をリアルタイムで把握できます。
GitHub側の設定で「Automatically delete head branches」を有効にしている場合はこのステップは不要ですが、n8n経由で削除する場合はGitHubの設定をオフにしておかないと競合が起きる場合があります。
STEP 5: エラーハンドリングとレート制限対策
GitHub REST APIには認証済みリクエストに対してレート制限があります。 認証済みリクエストのコアAPIの上限は1時間あたり5,000リクエストが目安です。 ポーリングワークフローが多数のPRを並列処理する状況や、他のツールが同じPATでAPIを叩いている場合は上限に近づくことがあります。
リトライ設定
n8nの各ノードでは Continue On Fail と Retry on Fail を設定できます。
HTTP Requestノードの設定で Retry on Fail をオンにし、試行回数を 3、待機間隔を 5000ms に設定します。
これにより一時的なネットワークエラーや503レスポンスには自動でリトライします。
リトライ後も失敗が続く場合は後続ノードへエラー情報を渡し、Slackへアラートを送ります。
レート制限への対処
GitHub APIがレート制限エラー(HTTPステータス429)を返した場合、レスポンスヘッダーの X-RateLimit-Reset に次のリセット時刻(Unixタイム)が入っています。
Function ノードで現在時刻と比較して待機時間を計算し、Wait ノードで処理を一時停止する設計にします。
ポーリング間隔を5分から10〜15分に広げることも効果的なレート制限対策になります。
大規模なリポジトリで多数のPRが並行する場合はGitHub Apps(インストールトークン方式)への切り替えも検討に値します。
Error Triggerワークフロー
n8nではワークフローの失敗を検知する Error Trigger ノードを使って、別のワークフローを起動できます。
エラーハンドリング専用のワークフローを作成し、Error Trigger を先頭に配置します。
エラーの詳細をSlackの #dev-alerts チャンネルに送ることで、自動化が止まっている状態に素早く気づけます。
エラーメッセージにはワークフロー名・ノード名・エラー詳細・発生日時を含めるとトラブルシューティングが迅速になります。
n8nのUIから対象ワークフローを開き、Settings → Error Workflow で作成したエラーハンドリングワークフローを紐付けます。
まとめ:まずは1ステップから始める
n8nとGitHub APIの組み合わせで、PRのライフサイクルを次のように自動化できました。
- PRオープン → レビュアー自動アサイン → Slack通知
- CIポーリング → 全チェック完了 → Slack承認依頼
- 承認 → squash merge → ブランチ自動削除
ここからさらに発展させるとすれば、以下のような拡張が考えられます。
- CODEOWNERS ファイルを読み込んでレビュアーをファイルパス別に自動選出する
- PRの変更行数が一定以上の場合はレビュー期限通知インターバルを設けてSlackにリマインドする
- マージ後に自動でリリースノートを生成してGitHub Releasesに登録する
- PR本文のテンプレート準拠チェックをn8nで自動実施しコメントで指摘する
まずはSTEP 1〜2だけを実装してPRオープン時の通知自動化から始めるのが最も導入ハードルが低いです。 動作を確認しながらSTEP 3〜5を順次追加していくと、チームへの展開もスムーズになります。 n8nのGUI上でノードをつなぎ直すだけで試行錯誤できるため、コードを書かずにロジックを変えられる点が大きな強みです。 自動化によって削減されたレビュー待ち時間を、より本質的な設計議論やコードの品質向上に充てていきましょう。