name: コードレビュー
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
permissions:
pull-requests: write
contents: read
issues: write
jobs:
code-review:
runs-on: ubuntu-latest
# 下書き PR は自動コードレビューをスキップ
if: github.event.pull_request.draft == false
steps:
- name: リポジトリをチェックアウト
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- name: Cursor CLI をインストール
run: |
curl https://cursor.com/install -fsS | bash
echo "$HOME/.cursor/bin" >> $GITHUB_PATH
- name: git のユーザー情報を設定
run: |
git config user.name "Cursor Agent"
git config user.email "cursoragent@cursor.com"
- name: 自動コードレビューを実行
env:
CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }}
MODEL: gpt-5
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BLOCKING_REVIEW: ${{ vars.BLOCKING_REVIEW || 'false' }}
run: |
cursor-agent --force --model "$MODEL" --output-format=text --print 'GitHub Actions のランナー上で自動コードレビューを実行してる。gh CLI は利用可能で、GH_TOKEN で認証済み。pull request にコメントしてOK。
コンテキスト:
- リポジトリ: ${{ github.repository }}
- PR 番号: ${{ github.event.pull_request.number }}
- PR ヘッド SHA: ${{ github.event.pull_request.head.sha }}
- PR ベース SHA: ${{ github.event.pull_request.base.sha }}
- ブロッキングレビュー: ${{ env.BLOCKING_REVIEW }}
目的:
1) 既存のレビューコメントを再チェックし、解決済みなら返信で resolved と記す。
2) 現在の PR の差分をレビューし、明確で重大度の高い問題だけを指摘する。
3) 変更行にのみごく短いインラインコメント(1~2文)を残し、最後に簡潔なサマリーを書く。
手順:
- 既存コメントを取得: gh pr view --json comments
- 差分を取得: gh pr diff
- インライン位置計算用にパッチ付き変更ファイルを取得: gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files --paginate --jq '.[] | {filename,patch}'
- 各問題の正確なインラインアンカーを計算(ファイルパス + 差分位置)。コメントは必ず差分の変更行にインラインで配置し、トップレベルコメントにはしない。
- このボットが作成した過去のトップレベル「問題なし」系コメントを検出(本文が "✅ no issues"、"No issues found"、"LGTM" などに一致)。
- 今回の実行で問題が見つかり、過去に「問題なし」コメントがある場合:
- 混乱を避けるため削除を優先:
- トップレベルの該当コメントを削除: gh api -X DELETE repos/${{ github.repository }}/issues/comments/<comment_id>
- 削除不可なら GraphQL(minimizeComment)で最小化、または本文の先頭に "[Superseded by new findings]" を付与して編集。
- 削除も最小化も不可なら、そのコメントに返信: "⚠️ Superseded: issues were found in newer commits"
- 以前報告した問題が近傍の変更で解決されたと思われる場合は返信: ✅ This issue appears to be resolved by the recent changes
- 次のみを解析対象にする:
- null/undefined 参照
- リソースリーク(未クローズのファイルや接続)
- インジェクション(SQL/XSS)
- 並行性/レースコンディション
- 重要な処理でのエラーハンドリング欠如
- 明白なロジックエラーによる不正な挙動
- 明確なパフォーマンスのアンチパターンで測定可能な影響があるもの
- 明確なセキュリティ脆弱性
- 重複回避: 同一または近接行に類似フィードバックがある場合はスキップ。
コメント規約:
- インラインコメントは最大 10 件まで。重要度の高いものを優先
- コメント 1 件につき問題は 1 つ。正確な変更行に配置
- すべての問題コメントはインライン必須(PR 差分内のファイルと位置に紐付け)
- 口調は自然で、具体的かつ実行可能な内容にする。自動化や確信度には触れない
- 絵文字を使用: 🚨 重大 🔒 セキュリティ ⚡ パフォーマンス ⚠️ ロジック ✅ 解決 ✨ 改善
送信:
- 報告すべき問題がなく、既に「問題なし」を示すトップレベルコメント(例: "✅ no issues"、"No issues found"、"LGTM")が存在する場合は、新たなコメントは送信しない。冗長を避けるためスキップ。
- 報告すべき問題がなく、過去の「問題なし」コメントもない場合は、問題なしを記す短いサマリーコメントを 1 件送信。
- 報告すべき問題があり、過去に「問題なし」コメントがある場合は、新規レビュー送信前にそれを削除/最小化/新発見で上書き済みと明記。
- 報告すべき問題がある場合は、インラインコメントのみで構成されるレビューを 1 件だけ送信し、必要なら簡潔なサマリー本文を付与。GitHub Reviews API を用いてコメントがインラインになるようにする:
- Build a JSON array of comments like: [{ "path": "<file>", "position": <diff_position>, "body": "..." }]
- Submit via: gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews -f event=COMMENT -f body="$SUMMARY" -f comments='[$COMMENTS_JSON]'
- 使用禁止: gh pr review --approve や --request-changes
ブロッキング動作:
- BLOCKING_REVIEW が true で、🚨 または 🔒 の問題を投稿した場合: echo "CRITICAL_ISSUES_FOUND=true" >> $GITHUB_ENV
- それ以外: echo "CRITICAL_ISSUES_FOUND=false" >> $GITHUB_ENV
- 最後に必ず CRITICAL_ISSUES_FOUND を設定
'
- name: ブロッキングレビューの結果を確認
if: env.BLOCKING_REVIEW == 'true'
run: |
echo "重大な問題がないか確認中..."
echo "CRITICAL_ISSUES_FOUND: ${CRITICAL_ISSUES_FOUND:-unset}"
if [ "${CRITICAL_ISSUES_FOUND:-false}" = "true" ]; then
echo "❌ 重大な問題が見つかり、ブロッキングレビューが有効。ワークフローを失敗させる。"
exit 1
else
echo "✅ ブロック対象の問題は見つからなかった。"
fi