AIコーディング 2026.06.14

GitHub ActionsとChatGPT APIでコードレビューを自動化する|プルリクエスト自動コメント実装【2026年版】

タグ:GitHub Actions / ChatGPT API / コードレビュー自動化 / CI/CD / 開発効率化

GitHub ActionsとChatGPT APIでコードレビュー自動化する利点

プルリクエストが作成されるたびにChatGPT APIが自動的にコードを分析し、改善提案をコメントで付与する仕組みを作ると、以下のメリットが得られます。

  • レビュー待機時間の削減: 人間のレビュー到着前に自動で初期チェックが完了
  • スタイル違反・よくあるバグの早期発見: 人間が見落としやすいパターンをAIが指摘
  • チーム全体の開発速度向上: 定型的なレビュー指摘を自動化し、レビュアーは高度なロジック検証に専念可能
  • 夜間・休日のコード投稿にも即座に対応: AIが24時間動作

本記事では、GitHub Actionsのワークフロー設定とChatGPT APIの統合、効果的なプロンプト設計までを実装レベルで解説します。

前提環境・必要なもの

  • GitHubリポジトリ: PublicまたはPrivate(アクセス権あり)
  • ChatGPT API キー: OpenAI社から取得済み
  • GitHub Personal Access Token (PAT): repo スコープを含む
  • 動作確認環境:
    • GitHub Actions ランナー(GitHubが提供する ubuntu-latest で動作確認)
    • ChatGPT API: gpt-4o-mini または gpt-4o 推奨(コスト・精度のバランス)

GitHubアカウントがあり、リポジトリへのコード記述権限があることを前提とします。

手順1. ChatGPT APIキーの取得と保管

ChatGPT APIを利用するにはOpenAIのAPIキーが必要です。

APIキーの取得

  1. OpenAI Platform にアクセス
  2. ログイン後、「API keys」ページに移動
  3. 「Create new secret key」をクリック
  4. 表示されたキーをコピー(再度表示されないため注意)

GitHubシークレットとして登録

  1. リポジトリページで「Settings」→「Secrets and variables」→「Actions」を選択
  2. 「New repository secret」をクリック
  3. 名前: OPENAI_API_KEY、値: 取得したAPIキーを貼り付け
  4. 「Add secret」で保存

GitHub Actionsのワークフローファイルから ${{ secrets.OPENAI_API_KEY }} で参照できます。

手順2. GitHub Actionsワークフローファイルの作成

.github/workflows/ ディレクトリにワークフローファイルを作成します。

ファイルパス

.github/workflows/code-review-ai.yml

ワークフロー設定(YAML)

name: AI Code Review

on:
  pull_request:
    types: [opened, synchronize, reopened]

permissions:
  contents: read
  pull-requests: write

jobs:
  code-review:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Get changed files
        id: changed-files
        run: |
          # base ブランチとの差分を取得
          git diff --name-only origin/${{ github.base_ref }}...HEAD > changed_files.txt
          cat changed_files.txt

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Install dependencies
        run: |
          pip install requests

      - name: Run AI Code Review
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
          REPO_OWNER: ${{ github.repository_owner }}
          REPO_NAME: ${{ github.event.repository.name }}
          BASE_REF: ${{ github.base_ref }}
          HEAD_REF: ${{ github.head_ref }}
        run: |
          python .github/scripts/code_review.py

このワークフローは:

  • プルリクエストが作成・更新されるたびに起動
  • 変更ファイルを取得
  • 後述のPythonスクリプトで分析を実行
  • GitHubコメント権限をセット

手順3. コードレビュー実行スクリプトの作成

.github/scripts/code_review.py を作成します。

import os
import requests
import json
from pathlib import Path

def get_changed_files():
    """変更されたファイルの一覧を取得"""
    with open('changed_files.txt', 'r') as f:
        return [line.strip() for line in f if line.strip() and (line.strip().endswith('.py') or line.strip().endswith('.js') or line.strip().endswith('.ts') or line.strip().endswith('.tsx'))]

def read_file_content(file_path):
    """ファイルの内容を読み込む"""
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            return f.read()
    except Exception as e:
        return f"エラー: ファイルが読み込めません ({str(e)})"

def analyze_code_with_chatgpt(file_path, code_content):
    """ChatGPT APIでコードを分析"""
    openai_api_key = os.getenv('OPENAI_API_KEY')
    
    # プロンプト設計: 具体的な指摘を引き出す
    system_prompt = """あなたはシニアコードレビュアーです。提供されたコードを分析し、以下の観点から指摘してください:

1. **バグの可能性**: 実行時エラーやロジック誤りの危険性
2. **パフォーマンス**: 不要なループや重い処理の指摘
3. **セキュリティ**: APIキーの露出、SQLインジェクション、認証不備など
4. **可読性**: 変数名、関数名、コメント不足
5. **テスト**: テストコードの有無と質

指摘は箇条書き形式で、各項目に「重要度: 高/中/低」を付けてください。改善案があれば具体的なコード例を示してください。"""

    user_message = f"""ファイル: {file_path}

{code_content}


このコードをレビューしてください。"""

    headers = {
        'Authorization': f'Bearer {openai_api_key}',
        'Content-Type': 'application/json'
    }

    payload = {
        'model': 'gpt-4o-mini',
        'messages': [
            {'role': 'system', 'content': system_prompt},
            {'role': 'user', 'content': user_message}
        ],
        'max_tokens': 800,
        'temperature': 0.3  # 安定した出力のため低め
    }

    response = requests.post(
        'https://api.openai.com/v1/chat/completions',
        headers=headers,
        json=payload,
        timeout=30
    )

    if response.status_code != 200:
        return f"APIエラー ({response.status_code}): {response.text}"

    return response.json()['choices'][0]['message']['content']

def post_comment_to_pr(review_content):
    """GitHubプルリクエストにコメントを投稿"""
    github_token = os.getenv('GITHUB_TOKEN')
    pr_number = os.getenv('PR_NUMBER')
    repo_owner = os.getenv('REPO_OWNER')
    repo_name = os.getenv('REPO_NAME')

    url = f'https://api.github.com/repos/{repo_owner}/{repo_name}/issues/{pr_number}/comments'

    headers = {
        'Authorization': f'Bearer {github_token}',
        'Accept': 'application/vnd.github+json'
    }

    # コメント本文を整形
    comment_body = f"""## 🤖 AI自動コードレビュー

{review_content}

---
**注:** このレビューはChatGPT APIによる自動分析です。最終判断は人間のレビュアーにお任せします。"""

    payload = {
        'body': comment_body
    }

    response = requests.post(
        url,
        headers=headers,
        json=payload,
        timeout=10
    )

    if response.status_code != 201:
        print(f"コメント投稿エラー ({response.status_code}): {response.text}")
        return False

    print(f"コメント投稿成功: PR #{pr_number}")
    return True

def main():
    """メイン処理"""
    changed_files = get_changed_files()
    
    if not changed_files:
        print("対象ファイルなし。スキップします。")
        return

    print(f"レビュー対象ファイル数: {len(changed_files)}")

    all_reviews = []

    for file_path in changed_files[:3]:  # API呼び出しコスト削減のため最大3ファイルに制限
        print(f"分析中: {file_path}")
        
        code_content = read_file_content(file_path)
        review = analyze_code_with_chatgpt(file_path, code_content)
        
        all_reviews.append(f"### {file_path}\n\n{review}")

    if all_reviews:
        comment = "\n\n".join(all_reviews)
        post_comment_to_pr(comment)
    else:
        print("レビュー結果なし")

if __name__ == '__main__':
    main()

手順4. ディレクトリ構成の確認

セットアップ完了時、リポジトリの構造は以下のようになります。

your-repo/
├── .github/
│   ├── workflows/
│   │   └── code-review-ai.yml
│   └── scripts/
│       └── code_review.py
├── src/
│   └── ... (業務コード)
└── ...

ファイルをリポジトリに追加してコミット・プッシュします。

git add .github/
git commit -m "Add AI code review workflow"
git push origin main

手順5. テスト実行

新しいブランチを作成し、テスト用のプルリクエストを作ります。

git checkout -b feature/test-ai-review
echo "# Test File" > test.py
git add test.py
git commit -m "Test commit for AI review"
git push origin feature/test-ai-review

GitHub上でプルリクエストを作成します。数秒〜1分後にワークフローが起動し、ChatGPT APIがコードを分析、コメントが自動投稿されます。

つまずきやすいポイントと解決策

問題1: 「API呼び出しエラー 401」が発生

原因: OpenAI APIキーが正しく設定されていない、または無効。

解決方法:

  1. GitHubの Settings → Secrets で OPENAI_API_KEY が正しく登録されているか確認
  2. OpenAI Platform で新しいAPIキーを生成・置き換え
  3. 余分なスペースやタブがないか確認(秘密情報の管理は厳密に)

問題2: 「Permission denied」でコメント投稿失敗

原因: GitHubトークンの権限不足またはワークフローの権限設定が不適切。

解決方法:

  1. ワークフローYAMLの permissions セクションを確認:
permissions:
  contents: read
  pull-requests: write
  1. 必ず pull-requests: write が指定されていることを確認

問題3: 「Timeout」でAPI呼び出しが途中で止まる

原因: 大きなファイルの分析時間が長い、またはネットワーク遅延。

解決方法:

  1. Pythonスクリプトで max_tokens を削減(800から500に)
  2. ファイルサイズ上限を設ける:
max_file_size = 50000  # 50KB以上はスキップ
if len(code_content) > max_file_size:
    continue
  1. GitHub Actions ランナーのタイムアウトを増やす(デフォルト6時間)

問題4: コメントが何度も投稿される

原因: ワークフロー設定で synchronize イベント(新しいコミット投稿時)も対象になり、毎回レビューが実行。

解決方法: 不要であれば、ワークフローYAMLの on セクションを調整:

on:
  pull_request:
    types: [opened]  # 初回作成時のみ

応用:プロンプト設計で精度を上げる

ChatGPT APIの出力品質は、プロンプト(質問文)で大きく変わります。

効果的なシステムプロンプトの例

system_prompt = """あなたはシニアバックエンド開発者です。以下のルールでコードレビューしてください:

【評価基準】
- セキュリティ: 認証・認可・入力検証の問題
- パフォーマンス: N+1クエリ、無駄なループ、メモリリーク
- テスト性: 単体テストを書きやすい構造か
- 保守性: チーム全体で読みやすいか

【指摘形式】
[重要度: 高] 短い指摘タイトル
理由: なぜこれが問題か
改善案: 修正例コード

【指摘数】
最大5件。最も重要な指摘から順に列挙。
"""

ユースケース別プロンプト

フロントエンド特化:

"フロントエンド開発者視点で、React/Vue.jsなどのコンポーネント設計、パフォーマンス(レンダリング最適化)、アクセシビリティを評価してください。"

セキュリティ特化:

"セキュリティ監査の視点で、認証・認可・入力値検証・データ漏洩・インジェクション攻撃のリスクを指摘してください。"

自動改善の工夫

参考ソース「The self-improving prompt engine that learns from your codebase history」にもとづき、プロジェクト独自のコーディング規約をプロンプトに組み込むことで精度が向上します。

# リポジトリのコーディング規約ファイルを読み込み
with open('.github/CODING_STYLE.md', 'r') as f:
    coding_style = f.read()

system_prompt = f"""... 基本プロンプト ...

【このプロジェクトのコーディング規約】
{coding_style}

上記規約への違反を優先的に指摘してください。"""

応用:ファイルタイプ別の条件分岐

コードレビューの対象をプログラミング言語ごとに変えることができます。

def should_review(file_path):
    """レビュー対象ファイルか判定"""
    supported_extensions = {'.py', '.js', '.ts', '.tsx', '.java', '.go', '.rb'}
    return Path(file_path).suffix in supported_extensions

changed_files = [f for f in get_changed_files() if should_review(f)]

また、言語別に異なるシステムプロンプトを使い分けることも可能です:

def get_system_prompt(file_path):
    """ファイル拡張子に応じたプロンプトを選択"""
    if file_path.endswith('.py'):
        return "Pythonコード専門のレビュアーとして..."
    elif file_path.endswith('.ts') or file_path.endswith('.tsx'):
        return "TypeScript/React専門のレビュアーとして..."
    else:
        return "一般的なコードレビュアーとして..."

応用:コスト削減策

ChatGPT APIは使用量に応じて課金されるため、以下の工夫で費用を抑えられます。

モデルの選択

  • gpt-4o: 最高精度(1リクエスト約3〜5円)
  • gpt-4o-mini: 軽い分析向け(1リクエスト約0.2円)

大量のプルリクエストがある場合は gpt-4o-mini で十分です。

ファイルサイズのフィルタ

max_file_size = 30000  # 30KB以上はスキップ
if len(code_content) > max_file_size:
    print(f"スキップ(サイズ超過): {file_path}")
    continue

対象ファイルを制限

# テストファイル・設定ファイルは除外
exclude_patterns = ['test_', '.spec.', '.config.', 'node_modules/', '__pycache__/']
changed_files = [
    f for f in get_changed_files()
    if not any(pattern in f for pattern in exclude_patterns)
]

次のステップ

インラインコメント機能の実装

現在のセットアップはプルリクエスト全体へのコメントですが、特定の行へのインラインコメントも可能です。GitHub APIの「Review Comments」エンドポイントを使い、コード行番号を指定してコメントを付与できます。

参考ソース「Using the System Prompt / Preferences Field」での設定方法も活用すれば、プロジェクト共有のプロンプト設定ファイル(.github/code-review-prompt.mdなど)を管理し、チーム全体で統一した基準を保つことができます。

Slack通知の追加

レビュー完了後、Slackチャネルに通知を送ることで、開発者がすぐに結果を確認できます。

slack_webhook = os.getenv('SLACK_WEBHOOK_URL')
payload = {
    'text': f'PR #{pr_number} のAIレビューが完了しました',
    'blocks': [...]
}
requests.post(slack_webhook, json=payload)

カスタム統計の収集

レビュー指摘の統計を取り、「セキュリティ問題が70%削減された」といった定量評価も可能です。JSON形式で記録し、メトリクスダッシュボードに連携できます。


あわせて読みたい

参考ソース