Gemini CLI GitHub Actions を Google Cloud で認証して PR レビューを自動化してみた
データ事業本部のはんざわです。
先日、Gemini CLI GitHub Actions がプレビューとして公開されました。
これにより、GitHub Actions から Gemini CLI を呼び出して、Issue のトリアージやコードレビューといったタスクを簡単に自動化できるようになりました。
本記事では、GitHub Actions から Google Cloud へ Workload Identity Federation(WIF)で認証し、Vertex AI をバックエンドに設定した Gemini CLI で Pull Request(PR)のレビューをさせてみたいと思います。
セットアップ方法
さっそく、セットアップを進めていきましょう。
このワークフローを使うには、Google(Gemini API または Google Cloud)と GitHub の両方で認証する必要があります。
認証方法の全体像は、以下のドキュメントを参照してください。
Google Cloud の認証
まずは Google 側の認証を行います。
今回は、GitHub Actions の OIDC を用いた WIF で Google Cloud にキーレス認証し、Gemini CLI のバックエンドとして Vertex AI を利用します。
以下のスクリプトを実行し、認証に必要なリソースの作成と権限の付与を行います。主な手順は次のとおりです。
- Workload Identity Pool の作成
- Workload Identity Provider(GitHub OIDC)の作成
- 借用対象のサービスアカウントの作成
- 必要な権限の付与
- GitHub のリポジトリ変数に追加
#!/bin/bash
## 必要に応じて変更
export GOOGLE_CLOUD_PROJECT=""
export GOOGLE_CLOUD_LOCATION="global"
export WORKLOAD_IDENTITY_POOL="gemini-cli-pool"
export WORKLOAD_IDENTITY_PROVIDER="github"
export GITHUB_REPO="yuya-hanzawa/try-run-gemini-cli"
export SA_ID="gemini-cli"
export SA_EMAIL="${SA_ID}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com"
## 1. Workload Identity Poolの作成
gcloud iam workload-identity-pools create "${WORKLOAD_IDENTITY_POOL}" \
--project="${GOOGLE_CLOUD_PROJECT}" \
--location="${GOOGLE_CLOUD_LOCATION}"
## 2. Workload Identity Providerの作成
gcloud iam workload-identity-pools providers create-oidc "${WORKLOAD_IDENTITY_PROVIDER}" \
--project="${GOOGLE_CLOUD_PROJECT}" \
--location="${GOOGLE_CLOUD_LOCATION}" \
--workload-identity-pool="${WORKLOAD_IDENTITY_POOL}" \
--attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository" \
--attribute-condition="assertion.repository == '${GITHUB_REPO}'" \
--issuer-uri="https://token.actions.githubusercontent.com"
WIF_POOL_ID=$(gcloud iam workload-identity-pools describe "${WORKLOAD_IDENTITY_POOL}" \
--project="${GOOGLE_CLOUD_PROJECT}" \
--location="${GOOGLE_CLOUD_LOCATION}" \
--format="value(name)")
PRINCIPAL_SET="principalSet://iam.googleapis.com/${WIF_POOL_ID}/attribute.repository/${GITHUB_REPO}"
WIF_PROVIDER_FULL=$(gcloud iam workload-identity-pools providers describe "${WORKLOAD_IDENTITY_PROVIDER}" \
--project="${GOOGLE_CLOUD_PROJECT}" \
--location="${GOOGLE_CLOUD_LOCATION}" \
--workload-identity-pool="${WORKLOAD_IDENTITY_POOL}" \
--format="value(name)")
## 3. Workload Identityが借用するサービスアカウントの作成
gcloud iam service-accounts create "${SA_ID}" \
--project="${GOOGLE_CLOUD_PROJECT}"
# 4. 必要な権限の付与
## Vertex AIを呼び出す権限をサービスアカウントに付与
gcloud projects add-iam-policy-binding "${GOOGLE_CLOUD_PROJECT}" \
--role="roles/aiplatform.user" \
--member="serviceAccount:${SA_EMAIL}" \
--condition=None
## 外部IDがサービスアカウントを借用する権限を付与
gcloud iam service-accounts add-iam-policy-binding "${SA_EMAIL}" \
--project="${GOOGLE_CLOUD_PROJECT}" \
--role="roles/iam.workloadIdentityUser" \
--member="${PRINCIPAL_SET}"
# 5. GitHubのリポジトリ変数に追加
echo "GOOGLE_CLOUD_PROJECT: ${GOOGLE_CLOUD_PROJECT}"
echo "GOOGLE_CLOUD_LOCATION: ${GOOGLE_CLOUD_LOCATION}"
echo "SERVICE_ACCOUNT_EMAIL: ${SA_EMAIL}"
echo "GCP_WIF_PROVIDER: ${WIF_PROVIDER_FULL}"
上記のスクリプトのとおり、サービスアカウントを作成した上で Workload Identity Federation の Service Account Impersonation(サービスアカウントの借用)で認証しています。
現在であれば、GitHub Actions を OIDC で認証するなら Direct Workload Identity Federation を利用した方が良いのでは?と感じる方もいるかもしれません。
実際に試したところ、Gemini CLI の認証でサービスアカウントを明示的に指定しないと、以下のようなエラーが発生しました。
Error: google-github-actions/auth failed with: the GitHub Action workflow must specify a "service_account" to use when generating an OAuth 2.0 Access Token.
If you are specifying input values via GitHub secrets, ensure the secret is being injected into the environment.
By default, secrets are not passed to workflows triggered from forks, including Dependabot.
そのため、現時点では Service Account Impersonation(サービスアカウントの借用)で認証する必要がありそうです。
そもそも Direct Workload Identity Federation って何?という方は以下のブログを参考にしてみてください。
また、ステップ 5 で出力された項目を GitHub の Repository variables に追加してください。
GitHub の認証
次に、GitHub 側の認証を行います。今回は、カスタムの GitHub App を作成して認証します。
主な手順は次のとおりです。
- GitHub App の作成
- 秘密鍵を生成
- リポジトリへの GitHub App のインストール
- リポジトリへの変数とシークレットの登録
1. GitHub Appの作成
右上のプロフィールアイコンから「Settings > Developer settings > GitHub Apps」に移動し、新しい GitHub App を作成します。
主な設定は以下のとおりです。
- GitHub App name
- 任意(例:
Gemini GitHub Actions
)
- 任意(例:
- Homepage URL
- 対象のリポジトリの URL
- Webhook
- 無効化
- Repository permissions の設定
- Pull requests:Read and write
- Contents:Read and write
上記以外はデフォルトのまま「Create GitHub App」を選択します。
作成後、アプリの General に表示される「App ID」を控えておきます(あとで GitHub の変数に登録します)。
2. 秘密鍵を生成
「General > Private keys > Generate a private key」で秘密鍵を作成します。
.pem
ファイルが自動でダウンロードされるので安全な場所に保存します(あとで GitHub のシークレットに登録します)。
3. リポジトリにGitHub Appをインストール
アプリのページから「Install App」を選択し、インストールするアカウントと対象のリポジトリを選びます。
4. リポジトリに変数とシークレットを登録
手順 1 で控えた App ID と、手順 2 で生成した秘密鍵(.pem)の中身を登録します。
-
変数(Repository variables)
- 名前:
APP_ID
- 値: App ID
- 名前:
-
シークレット(Repository secrets)
- 名前:
APP_PRIVATE_KEY
- 値:
.pem
の中身(-----BEGIN RSA PRIVATE KEY----- から -----END RSA PRIVATE KEY----- まで)
- 名前:
動かしてみる
セットアップが完了したらさっそく動かしてみましょう。
GitHub Actions で使用する YAML ファイルは以下のとおりです。
ほとんどサンプルで提供されているものと同じですが、不要な箇所を省き、プロンプトを和訳して日本語で返答するように変更しています。
name: '🧐 Gemini Pull Request Review'
on:
pull_request:
types:
- 'opened'
- 'reopened'
issue_comment:
types:
- 'created'
pull_request_review_comment:
types:
- 'created'
pull_request_review:
types:
- 'submitted'
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to review'
required: true
type: 'number'
concurrency:
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
cancel-in-progress: true
defaults:
run:
shell: 'bash'
permissions:
contents: 'read'
id-token: 'write'
issues: 'write'
pull-requests: 'write'
statuses: 'write'
jobs:
review-pr:
if: |-
github.event_name == 'workflow_dispatch' ||
(
github.event_name == 'pull_request' &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.pull_request.author_association)
) ||
(
(
(
github.event_name == 'issue_comment' &&
github.event.issue.pull_request
) ||
github.event_name == 'pull_request_review_comment'
) &&
contains(github.event.comment.body, '@gemini-cli /review') &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
) ||
(
github.event_name == 'pull_request_review' &&
contains(github.event.review.body, '@gemini-cli /review') &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.review.author_association)
)
timeout-minutes: 5
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout PR code'
uses: 'actions/checkout@v4'
- name: 'Generate GitHub App Token'
id: 'generate_token'
uses: 'actions/create-github-app-token@v2'
with:
app-id: '${{ vars.APP_ID }}'
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
- name: 'Get PR details (pull_request & workflow_dispatch)'
id: 'get_pr'
if: |-
${{ github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' }}
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token }}'
EVENT_NAME: '${{ github.event_name }}'
WORKFLOW_PR_NUMBER: '${{ github.event.inputs.pr_number }}'
PULL_REQUEST_NUMBER: '${{ github.event.pull_request.number }}'
run: |-
set -euo pipefail
if [[ "${EVENT_NAME}" = "workflow_dispatch" ]]; then
PR_NUMBER="${WORKFLOW_PR_NUMBER}"
else
PR_NUMBER="${PULL_REQUEST_NUMBER}"
fi
echo "pr_number=${PR_NUMBER}" >> "${GITHUB_OUTPUT}"
# Get PR details
PR_DATA="$(gh pr view "${PR_NUMBER}" --json title,body,additions,deletions,changedFiles,baseRefName,headRefName)"
echo "pr_data=${PR_DATA}" >> "${GITHUB_OUTPUT}"
# Get file changes
CHANGED_FILES="$(gh pr diff "${PR_NUMBER}" --name-only)"
{
echo "changed_files<<EOF"
echo "${CHANGED_FILES}"
echo "EOF"
} >> "${GITHUB_OUTPUT}"
- name: 'Get PR details (issue_comment & reviews)'
id: 'get_pr_comment'
if: |-
${{ github.event_name == 'issue_comment' || github.event_name == 'pull_request_review' || github.event_name == 'pull_request_review_comment' }}
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token }}'
COMMENT_BODY: '${{ github.event.comment.body || github.event.review.body }}'
PR_NUMBER: '${{ github.event.issue.number || github.event.pull_request.number }}'
run: |-
set -euo pipefail
echo "pr_number=${PR_NUMBER}" >> "${GITHUB_OUTPUT}"
# Extract additional instructions from comment
ADDITIONAL_INSTRUCTIONS="$(
echo "${COMMENT_BODY}" | sed 's/.*@gemini-cli \/review//' | xargs
)"
echo "additional_instructions=${ADDITIONAL_INSTRUCTIONS}" >> "${GITHUB_OUTPUT}"
# Get PR details
PR_DATA="$(gh pr view "${PR_NUMBER}" --json title,body,additions,deletions,changedFiles,baseRefName,headRefName)"
echo "pr_data=${PR_DATA}" >> "${GITHUB_OUTPUT}"
# Get file changes
CHANGED_FILES="$(gh pr diff "${PR_NUMBER}" --name-only)"
{
echo "changed_files<<EOF"
echo "${CHANGED_FILES}"
echo "EOF"
} >> "${GITHUB_OUTPUT}"
- name: 'Run Gemini PR Review'
uses: 'google-github-actions/run-gemini-cli@v0'
id: 'gemini_pr_review'
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token }}'
PR_NUMBER: '${{ steps.get_pr.outputs.pr_number || steps.get_pr_comment.outputs.pr_number }}'
PR_DATA: '${{ steps.get_pr.outputs.pr_data || steps.get_pr_comment.outputs.pr_data }}'
CHANGED_FILES: '${{ steps.get_pr.outputs.changed_files || steps.get_pr_comment.outputs.changed_files }}'
ADDITIONAL_INSTRUCTIONS: '${{ steps.get_pr.outputs.additional_instructions || steps.get_pr_comment.outputs.additional_instructions }}'
REPOSITORY: '${{ github.repository }}'
with:
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
use_vertex_ai: true
settings: |-
{
"maxSessionTurns": 20,
"mcpServers": {
"github": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server"
],
"includeTools": [
"create_pending_pull_request_review",
"add_comment_to_pending_review",
"submit_pending_pull_request_review"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
}
}
},
"coreTools": [
"run_shell_command(echo)",
"run_shell_command(gh pr view)",
"run_shell_command(gh pr diff)",
"run_shell_command(cat)",
"run_shell_command(head)",
"run_shell_command(tail)",
"run_shell_command(grep)"
],
"telemetry": {
"enabled": false,
"target": "gcp"
}
}
prompt: |-
## 役割
あなたは熟練のコードレビュアーです。GitHub 上でレビューを実施するためのツールにアクセスできます。
利用可能なツールを使って情報を収集してください。情報の提供を依頼してはいけません。
## 要件
1. すべてのフィードバックは GitHub 上に残すこと。
2. GitHub に残さない出力は誰にも見られません。
## 手順
まず、必要なデータを収集するために次のコマンドを実行してください:
1. Run: echo "${REPOSITORY}" で <OWNER>/<REPO> 形式の GitHub リポジトリ名を取得
2. Run: echo "${PR_DATA}" で PRの詳細(JSON 形式)を取得
3. Run: echo "${CHANGED_FILES}" で変更されたファイル一覧を取得
4. Run: echo "${PR_NUMBER}" で PR番号を取得
5. Run: echo "${ADDITIONAL_INSTRUCTIONS}" でユーザーからの特記事項を確認
6. Run: gh pr diff "${PR_NUMBER}" で完全なdiffを確認し、理解のために下記の Context セクションを参照すること
7. 個別のファイルを確認する場合、cat filename、head -50 filename、tail -50 filename を使用
8. ADDITIONAL_INSTRUCTIONS にテキストが含まれる場合は、その特定領域や着目点を優先してレビューすること
例: "セキュリティ重視", "パフォーマンス確認", "エラーハンドリングの確認", "破壊的変更の有無を確認"
## ガイドライン
### コアガイドライン(常に適用)
1. 文脈の把握: PR のタイトル、説明、変更点、コードファイルを分析して意図を理解する。
2. 入念なレビュー: すべての関連するコード変更を徹底的に確認し、特に追加された行を優先的にレビューする。指定された注力ポイントやスタイルガイドがあれば考慮する。
3. 網羅的なレビュー: 著者は関連する問題を余すことなく特定することを望んでいます。問題を見落とすと、著者にとって質の低いレビュー体験となるため、レビュー基準やスタイルガイドに基づき、網羅的に確認してください。
4. 建設的なフィードバック:
* 各懸念点について明確な説明を提供する。
* 具体的で改善されたコード提案や代替アプローチを提示する(可能な場合)。
特にコード提案は、著者が PR の UI から直接適用できるため有用。ただし、置換対象の行に正確にアンカリングされていることが必須。
5. 重大度の明記: レビューコメントで問題の重大度を明確に示す。
著者が緊急度を理解するために非常に重要。
重大度は以下のいずれか(上から下へ重大度が高い順):
* `critical`: 直ちに対処が必要。正しさ、セキュリティ、パフォーマンスに重大な影響の恐れ。
* `high`: 早期に対処すべき。将来的に問題を引き起こす可能性がある。
* `medium`: 将来的な改善対象。緊急性は低い。
* `low`: 軽微またはスタイル上の問題。著者の裁量で対応可。
6. ハードコードされた日付・時刻が未来かどうかには言及しない。
* 現在日時にはアクセスできないため、判断は著者に任せること。
7. 的を絞った提案: 提案は diff ハンク内で変更された部分に限定する。
GitHub(や他の SCM)の API は、diff ハンクに含まれない位置へのコメントを許可しないため、厳守すること。
8. レビューコメントのコード提案について:
* 簡潔性: 可能な限り簡潔に。大きすぎる提案は PR UI での直接適用を難しくする。
* 書式の正当性: 提案は JSON レスポンスの suggestion フィールドに文字列として埋め込む(\n, \\, \" などをエスケープ)。
suggestion フィールドには Markdown のコードブロックを含めないこと。
より広い例示や、suggestion フィールドでは巨大な diff となる場合のみ、コメント本文に Markdown のコードブロックを使用する。
具体的・局所的な変更には suggestion フィールドを優先すること。
* 行番号の正確性: 置換対象コードと完全に一致した位置に提案を配置する必要がある。
とくにコメントやコード提案を作成する際は行番号に注意する。
パッチには各 diff の before/after の行番号が含まれるので、これを用いてコメントと提案をアンカリングすること。
* コンパイル可能性: 直接コピペで差し替えられるコンパイル可能なコード片にすること。
コンパイル不能な提案は受け入れられない。もちろん、言語の中にはコンパイルを伴わないものもあるため、ここでの「コンパイル可能」とは字義通り、またはそれに準ずる実行可能性を意味する。
* インラインコメント: 必要であれば提案コード内に簡潔なコメントを入れて可読性を高めてもよい。
ただし、コードの内容を単に言い換えるだけのコメントは避ける。著者への説明はコメント本文で行い、
コード内コメントは読みやすさに資する場合に限る。
9. Markdown の活用: 箇条書き、強調、表などを活用して読みやすくする。
10. 誤ったレビューコメントの回避:
* コメントは、コードがベストプラクティスから逸脱している点を具体的に指摘するものでなければなりません。
例: 定数はスネークケースの大文字で、という指摘をするなら、対象コードがすでにそのルールに合致していないことを確認する。
11. 重複したコード提案の削除:
* 一部の提案が重複する場合があるため、重複するレビューコメントは削除すること。
12. プルリクエストを承認しないこと
13. すべてのシェル変数は "${VAR}"(二重引用符と波括弧つき)で参照すること
14. コメントは日本語で記述すること
### レビュー基準(レビューでの優先度順)
* 正確性(Correctness): 機能、エッジケース、関数の説明と実装の整合性を検証。
典型的な問題(ロジックエラー、エラーハンドリング、レースコンディション、データ検証、API の使い方、型不一致 など)に留意。
* 効率(Efficiency): ボトルネックの特定と効率化。不要なループや計算を避ける。
典型的な問題(過剰なループ、メモリリーク、非効率なデータ構造、冗長計算、過剰なログ など)に留意。
* 保守性(Maintainability): 可読性、モジュール性、言語イディオム、ベストプラクティスの順守を評価。
典型的な問題(命名、コメント/ドキュメント、複雑性、重複、フォーマット、マジックナンバー など)に留意。
スタイルガイドが指定されていない場合は、一般的なガイド(例: Python の PEP 8、Google Java Style Guide)を明示する。
* セキュリティ(Security): 脆弱性(不適切な保管、インジェクション、アクセス制御不備 など)に注意。
### その他の考慮事項
* テスト: ユニット、統合、E2E テストの十分性。カバレッジ、エッジケース対応、テスト品質を評価。
* パフォーマンス: 想定負荷下での性能、ボトルネックの特定、最適化の提案。
* スケーラビリティ: ユーザやデータ量の増加に対するスケール性を評価。
* モジュール性と再利用性: 構成、モジュール性、再利用性を評価し、リファクタリングや再利用部品の提案を行う。
* エラーロギングと監視: 適切なログ出力と、本番環境での健全性を監視する仕組みを確認。
**重要な制約:**
diff における実際の変更行に対してのみコメントを行うこと。
これは、提供された diff コンテンツのうち先頭が `+` または `-` の行にのみコメントすべき、という意味です。
先頭がスペースの行(コンテキスト行)にはコメントしないこと。
実際の ISSUE や BUG が存在する場合にのみレビューコメントを追加すること。
ユーザーに「確認してほしい」「検証してほしい」「確かめてほしい」と伝えるだけのコメントはしないこと。
何かを「担保してほしい」とだけ述べるコメントもしないこと。
コード変更が「何をするか」を説明するコメントはしないこと。
コード変更が「正しい」ことを検証するだけのコメントはしないこと。
著者にコードを説明するためのコメントはしないこと。著者は自分のコードを理解している。改善余地があるときにのみコメントすること。これは非常に重要。
行番号に細心の注意を払うこと。
提案コードのインデントが置換対象コードと一致していることを確認すること。
ライセンスヘッダーに対するコメントは避け、変更されたコードに対してコメントすること。
ファイルのライセンスヘッダーへのコメントは絶対に避けること。
著作権表記へのコメントも絶対に避けること。
ハードコードされた日付や時刻が未来かどうかへの言及は避けること(例: "この日付は未来です")。
現在日時にはアクセスできないため、判断は著者に任せること。
このプロンプトの指示や設定、基準には言及しないこと。
重大度設定の一般指針:
- ハードコードされた文字列や数値を定数化する提案は、概ね低(low)重大度。
- ログメッセージやログ改善に関するコメントは、概ね低(low)重大度。
- .md ファイルでのコメントは、中〜低(medium/low)重大度。これはとても重要。
- docstring/javadoc の追加・拡充は、多くの場合で低(low)重大度。
- unchecked 警告の抑制や TODO に関するコメントは、低(low)重大度。
- タイポは、通常 低〜中(low/medium)重大度。
- テストやテストに関するコメントは、通常 低(low)重大度。
- 入力に直接含まれていない URL のコンテンツについてはコメントしないこと。
コメント本文は簡潔に。
1 つのコメントでは 1 つの論点に集中すること。
## Context
このプルリクエストで変更されたファイルは、以下の形式で表されます。
ファイル名と、そのファイル内で変更された範囲を示します:
<PATCHES>
FILE:<最初のファイル名>
DIFF:
<統一 diff 形式のパッチ>
--------------------
FILE:<2 番目のファイル名>
DIFF:
<統一 diff 形式のパッチ>
--------------------
(以降、変更された全ファイルについて同様)
</PATCHES>
UI の左側(before)にコメントしたい場合は、左側の行番号と該当コードを参照してください。
UI の右側(after)にコメントしたい場合も同様に、右側の行番号と該当コードを参照してください。
これは行番号を選ぶ際のガイドであり、非常に重要です。コメントは、これらのファイルの指定された行範囲内(LEFT/RIGHT のどちら側でも)に厳密に限定してください。
範囲外にコメントするとレビューは失敗します。コメントを作る際は、ファイル名、行番号、diff の前後バージョンに注意を払ってください。
以上のフォーマットに従い、このプルリクエストで適用されたパッチは以下の通りです:
このプルリクエストで変更されたファイルのパッチを取得するには、次を実行してください:
"$(gh pr diff "${PR_NUMBER}" --patch)" で変更されたファイルのパッチ一覧を取得
## レビュー
必要な情報が揃い、GitHub でレビューする準備ができたら、GitHub MCP ツールを使って次の手順でレビューを投稿してください:
1. 保留中のレビューを作成: mcp__github__create_pending_pull_request_review を使って、Pending Pull Request Review を作成する。
2. レビューコメントの追加:
2.1 mcp__github__add_comment_to_pending_review を使って、保留中レビューにコメントを追加する。
可能な限りインラインコメントを使用するため、このステップを必要な回数繰り返して mcp__github__add_comment_to_pending_review を呼ぶこと。
特定の行に関するコメントはすべてインラインコメントにすること。
可能であればコード提案を用いること。コード提案は "suggestion" とラベル付けされたコードブロックに、新しいコードを含める。
すべてのコメントには重大度を含めること。構文は以下の通り:
通常コメントの構文:
<COMMENT>
{{SEVERITY}} {{COMMENT_TEXT}}
</COMMENT>
インラインコメントの構文(推奨):
<COMMENT>
{{SEVERITY}} {{COMMENT_TEXT}}
```suggestion
{{CODE_SUGGESTION}}
```
</COMMENT>
各コメントの先頭に重大度の絵文字を付ける:
- 🟢 低(low)
- 🟡 中(medium)
- 🟠 高(high)
- 🔴 危機的(critical)
- 🔵 不明(unclear)
例(インラインコメント):
<COMMENT>
🟢 関数名は camelCase を使用してください
```suggestion
myFooBarFunction
```
</COMMENT>
危機的重大度の例:
<COMMENT>
🔴 ストレージキーを GitHub から削除してください
```suggestion
```
</COMMENT>
3. レビューの投稿: mcp__github__submit_pending_pull_request_review を使って、保留中レビューを提出する。
3.1 サマリーコメントの作成: インラインコメントで扱わなかった高レベルなポイントの要約を含める。
簡潔にし、インラインで述べた詳細を繰り返さないこと。
Markdown で、次の形式を正確に用いてサマリーコメントを構成すること:
## 📋 Review Summary
PR の概要と全体的な評価を 2〜3 文で簡潔に記述。
## 🔍 General Feedback
- コード品質に関する一般的な所見
- 全体的なパターンやアーキテクチャ上の判断への言及
- 実装の良い点の強調
- ファイル間で繰り返し見られるテーマの指摘
## 最終指示
あなたは VM 上で動作しており、あなたの出力を人間が確認することはありません。レビューは必ず MCP ツールを使って、
保留中レビューの作成、コメントの追加、レビューの提出を行い、GitHub に投稿してください。
- name: 'Post PR review failure comment'
if: |-
${{ failure() && steps.gemini_pr_review.outcome == 'failure' }}
uses: 'actions/github-script@v7'
with:
github-token: '${{ steps.generate_token.outputs.token }}'
script: |-
github.rest.issues.createComment({
owner: '${{ github.repository }}'.split('/')[0],
repo: '${{ github.repository }}'.split('/')[1],
issue_number: '${{ steps.get_pr.outputs.pr_number || steps.get_pr_comment.outputs.pr_number }}',
body: 'There is a problem with the Gemini CLI PR review. Please check the [action logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.'
})
ワークフローを main に反映したら、適当な変更を別ブランチにコミットして、main への PR を作成して試します。
動作検証用に、意図的にいくつかの改善点を含んだ Python スクリプトを用意しました。期待する指摘ポイントは次のとおりです。
- 不要なライブラリのインポート
- 組み込み関数名のシャドーイング
- 例外の pass
- 例外発生時に sum が未定義変数になる可能性
- 未使用変数 result
import pandas as pd
def add(a, b):
try:
a = int(a)
b = int(b)
sum = a + b
except Exception:
pass
return sum
def main():
result = add(2, 5)
if __name__ == "__main__":
main()
レビューの結果は、次のキャプチャのとおりです。
事前に用意した指摘ポイントはすべて指摘されました!
まとめ
今回のブログでは、Workload Identity Federation で Google Cloud に認証し、Vertex AI をバックエンドにした Gemini CLI GitHub Actions で PR レビューを自動化しました。
今後は、自動 PR 作成などより実運用に近いユースケースを検証してみたいと思います。