コンテンツにスキップ
X

Level 6 実践: PR が来るたびに自動でレビューが走る仕組みを作る

概念・仕組みを先に理解したい方は Level 6 の概念ガイド を参照してください。


PR が届くたびに Claude が自動でコードレビューコメントを投稿する仕組みを構築します。手動でレビュー依頼を送る手間をなくし、レビュー品質をプロジェクト全体で均一化できます。

対象読者: Level 5 まで完了しており、GitHub Actions の基本操作(YAML 編集・シークレット設定)を理解している方。

学習時間の目安: 読了 10分 + 実践 40分


Level 5 で feature/contact-form ブランチの PR が GitHub 上に自動作成された。現在はレビューを手動で依頼しており、これが毎回の作業負荷になっている。


my-portfolio のルートに scripts/ ディレクトリを作成し、ローカルレビュー用のシェルスクリプトを置きます。このスクリプトは .tsx.ts.css ファイルを対象に、TypeScript 型安全性・React ベストプラクティス・アクセシビリティの観点でレビューします。

mkdir -p scripts

scripts/review_pr.sh を以下の内容で作成します。

#!/usr/bin/env bash
# scripts/review_pr.sh
# 現在のブランチと main の差分を Claude でレビューする

set -euo pipefail

BASE_BRANCH="${1:-main}"
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)

echo "=== Claude PR Review ==="
echo "Base  : ${BASE_BRANCH}"
echo "Branch: ${CURRENT_BRANCH}"
echo ""

# 変更ファイルの一覧(.tsx .ts .css のみ)
CHANGED_FILES=$(git diff --name-only "${BASE_BRANCH}...HEAD" \
  | grep -E '\.(tsx|ts|css)$' || true)

if [ -z "${CHANGED_FILES}" ]; then
  echo "レビュー対象のファイルがありません(.tsx/.ts/.css)。"
  exit 0
fi

echo "対象ファイル:"
echo "${CHANGED_FILES}"
echo ""

# 差分を取得してレビュー依頼
DIFF=$(git diff "${BASE_BRANCH}...HEAD" -- ${CHANGED_FILES})

PROMPT="以下は my-portfolio(Next.js 14 + TypeScript)の PR 差分です。
次の観点でレビューしてください。

1. TypeScript 型安全性(any の使用・型推論の活用・型ガードの妥当性)
2. React ベストプラクティス(useEffect の依存配列・メモ化の必要性・コンポーネント設計)
3. アクセシビリティ(aria 属性・フォームラベル・キーボード操作)
4. Tailwind CSS クラスの一貫性

問題があれば「ファイル名 + 行番号の目安 + 問題の説明 + 改善案」の形式で箇条書きしてください。
問題がなければ「LGTM」と返してください。

--- DIFF ---
${DIFF}"

echo "Claude にレビューを依頼しています..."
echo ""
echo "${PROMPT}" | claude --print

実行権限を付与します。

chmod +x scripts/review_pr.sh

feature/contact-form ブランチに切り替えて、スクリプトを実行します。

git checkout feature/contact-form
./scripts/review_pr.sh main

実行例:

=== Claude PR Review ===
Base  : main
Branch: feature/contact-form

対象ファイル:
src/components/Contact.tsx
src/app/contact/page.tsx
src/components/__tests__/Contact.test.tsx

Claude にレビューを依頼しています...

## レビュー結果

### src/components/Contact.tsx

- **L23 — 型安全性**: `e.target.value` を `as string` でキャストしていますが、
  `React.ChangeEvent<HTMLInputElement>` を使えばキャスト不要です。
  ```tsx
  // 修正前
  const value = (e.target as HTMLInputElement).value as string
  // 修正後
  onChange={(e: React.ChangeEvent<HTMLInputElement>) => setValue(e.target.value)}
  • L45 — アクセシビリティ: <input> に対応する <label> が存在しません。 htmlForid で紐付けてください。

問題なし。

2件の指摘があります。いずれも軽微な修正で対応できます。


---

## Step 3: GitHub Actions ワークフローの作成

`.github/workflows/ai-review.yml` を作成します。PR が opened または synchronize されたときに自動でレビューを実行し、結果を PR コメントとして投稿します。

```bash
mkdir -p .github/workflows

.github/workflows/ai-review.yml の内容:

name: AI Code Review

on:
  pull_request:
    types: [opened, synchronize]
    paths:
      - "src/**/*.tsx"
      - "src/**/*.ts"
      - "src/**/*.css"

permissions:
  contents: read
  pull-requests: write

jobs:
  review:
    runs-on: ubuntu-latest
    timeout-minutes: 10

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"

      - name: Install Claude Code
        run: npm install -g @anthropic-ai/claude-code

      - name: Get PR diff
        id: diff
        run: |
          BASE="${{ github.event.pull_request.base.sha }}"
          HEAD="${{ github.event.pull_request.head.sha }}"
          DIFF=$(git diff "${BASE}...${HEAD}" -- 'src/**/*.tsx' 'src/**/*.ts' 'src/**/*.css' || true)
          # 差分を環境変数ファイルに書き出す(改行を含むため)
          echo "DIFF<<EOF" >> $GITHUB_ENV
          echo "${DIFF}" >> $GITHUB_ENV
          echo "EOF" >> $GITHUB_ENV

      - name: Run Claude review
        id: review
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          PROMPT="以下は my-portfolio(Next.js 14 + TypeScript)の PR 差分です。
          次の観点でレビューしてください。

          1. TypeScript 型安全性
          2. React ベストプラクティス(useEffect 依存配列・メモ化)
          3. アクセシビリティ(aria 属性・フォームラベル)
          4. Tailwind CSS クラスの一貫性

          問題があれば「ファイル名 + 行番号の目安 + 問題の説明 + 改善案」の形式で箇条書きにしてください。
          問題がなければ LGTM と返してください。

          --- DIFF ---
          ${{ env.DIFF }}"

          REVIEW=$(echo "${PROMPT}" | claude --print --dangerously-skip-permissions)
          echo "REVIEW<<EOF" >> $GITHUB_ENV
          echo "${REVIEW}" >> $GITHUB_ENV
          echo "EOF" >> $GITHUB_ENV

      - name: Post review comment
        uses: actions/github-script@v7
        with:
          script: |
            const review = process.env.REVIEW;
            const body = [
              '## Claude AI レビュー',
              '',
              review,
              '',
              '---',
              '_このコメントは Claude Code によって自動生成されました。_',
            ].join('\n');

            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body,
            });
        env:
          REVIEW: ${{ env.REVIEW }}

Step 4: —dangerously-skip-permissions の注意事項

Section titled “Step 4: —dangerously-skip-permissions の注意事項”

--dangerously-skip-permissions は、インタラクティブな確認プロンプトをスキップするフラグです。CI 環境では対話が不可能なため必要ですが、以下の点に注意してください。

注意点対策
ファイル書き込み権限も付与される--print と組み合わせて出力のみに限定する
secrets へのアクセスが可能になるGitHub Actions の permissions ブロックを最小権限に絞る
プロンプトインジェクションのリスクがあるPR 差分をそのままプロンプトに含めるため、外部からの悪意ある diff に注意する

本番の公開リポジトリでは、pull_request_target ではなく pull_request を使うことで、fork 先からのシークレット漏洩を防げます。


GitHub リポジトリの Settings > Secrets and variables > Actions で ANTHROPIC_API_KEY を追加します。

Settings
└── Secrets and variables
    └── Actions
        └── New repository secret
            Name: ANTHROPIC_API_KEY
            Value: sk-ant-...(Anthropic Console で発行したキー)

ワークフローファイルをコミットしてプッシュします。

git add scripts/review_pr.sh .github/workflows/ai-review.yml
git commit -m "Add Claude AI auto-review workflow"
git push origin feature/contact-form

GitHub の Pull Requests タブを開き、feature/contact-form の PR を確認します。Actions タブで AI Code Review ジョブが実行され、完了後に PR にコメントが投稿されます。

投稿されるコメントの例:

## Claude AI レビュー

### src/components/Contact.tsx

- **L23 — 型安全性**: `React.ChangeEvent<HTMLInputElement>` を使うと
  型キャストが不要になります。

- **L45 — アクセシビリティ**: `<input id="email">` に対して
  `<label htmlFor="email">` が対応していません。

### src/app/contact/page.tsx

問題なし。

### 総評

2件の指摘があります。いずれも軽微な修正で対応できます。

---
_このコメントは Claude Code によって自動生成されました。_

  • scripts/review_pr.sh が追加され、ローカルで差分レビューを実行できる
  • .github/workflows/ai-review.yml が追加され、すべての PR に自動でレビューコメントが投稿される
  • ANTHROPIC_API_KEY が GitHub シークレットに設定されている
my-portfolio/
├── scripts/
│   └── review_pr.sh          # ← 新規追加
├── .github/
│   └── workflows/
│       └── ai-review.yml     # ← 新規追加
├── src/
│   ├── components/
│   │   ├── About.tsx
│   │   ├── Skills.tsx
│   │   └── Contact.tsx
│   └── app/
│       ├── contact/
│       │   └── page.tsx
│       └── ...
└── ...

Level 7 実践: トレンドからブログネタを自動収集する