GitHub IssueをトリガーにClaude Code GitHub ActionsでPR作成・レビュー・修正まで自動化してみた

GitHub IssueをトリガーにClaude Code GitHub ActionsでPR作成・レビュー・修正まで自動化してみた

2025.08.14

はじめに

データ事業本部のkasamaです。今回はGitHub Issue をトリガーに Claude Code GitHub Actions を起動し、実装から PR レビュー、修正までを AI に任せる開発フローを試します。以下の勉強会のUbieさんの発表の中でClaude Code Base ActionでpromptやMCP設定をカスタマイズできると知ったことがきっかけです。

Ubieさんの発表は29:30あたりからです。
https://www.youtube.com/live/1IfoHU7UEgQ?feature=shared&t=1770

https://github.com/anthropics/claude-code-base-action

前提

今回の処理フローになります。

GitHub Issue を作成し、特定ラベルの追加をトリガーに PR 作成まで実施します。その後のレビューや修正も任せます。本番運用の場合は、自分で修正とかもしますが、今回は実装修正まで全てAIに任せる流れで試します。

私はClaude Max Planに入っているので、API KeyではないSubscription方式でClaude Code Actionsを設定していきます。

https://github.com/anthropics/claude-code-action/issues/4#issuecomment-3046770474
本番運用では以下の記事が参考になりそうです。
https://dev.classmethod.jp/articles/github-organization-level-code-review-by-claude-code-with-github-actions-and-amazon-bedrock/
今回は簡単にLambdaでS3のデータを加工してS3に出力する実装で試します。途中で今回の実装固有の設定があったりすると思いますので使用する際は適宜修正いただければと思います。

実装

今回のディレクトリ構成になります。

@ claude-code-actions-private % tree -la
.
├── .github
│   ├── mcp-servers.json
│   ├── prompts
│   │   ├── implementation-prompt.txt
│   │   └── review-prompt.txt
│   └── workflows
│       ├── claude.yml
│       ├── issue-to-pr.yml
│       └── pr-review.yml
├── CLAUDE.md
├── issue_sample.md
└── README.md

mcp-servers.jsonでは使用するmcp serverを設定します。ここでは、GitHub,aws-documentation,CDK,context7のMCP Serverを設定しています。

mcp-servers.json
{
  "mcpServers": {
    "github": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "GITHUB_PERSONAL_ACCESS_TOKEN",
        "ghcr.io/github/github-mcp-server"
      ],
      "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}" }
    },
    "awslabs.aws-documentation-mcp-server": {
      "command": "uvx",
      "args": ["awslabs.aws-documentation-mcp-server@latest"],
      "env": {
        "FASTMCP_LOG_LEVEL": "ERROR",
        "AWS_DOCUMENTATION_PARTITION": "aws"
      }
    },
    "awslabs.cdk-mcp-server": {
      "command": "uvx",
      "args": ["awslabs.cdk-mcp-server@latest"],
      "env": {
        "FASTMCP_LOG_LEVEL": "ERROR"
      }
    },
    "context7": {
      "type": "sse",
      "url": "https://mcp.context7.com/sse"
    }
  }
}

implementation-prompt.txtは実装するためのpromptです。MCP Server設定などは本プロジェクト固有の設定になっているので適宜prompt修正が必要です。

.github/prompts/implementation-prompt.txt
You are a developer implementing an issue.

Issue Information:
- REPO: ${REPOSITORY}
- ISSUE_NUMBER: ${ISSUE_NUMBER}

WORKFLOW:
1. Use mcp__github__get_issue to understand the issue requirements
2. Checkout and pull the latest 'main' branch
3. Create a new feature branch from 'main': "feature/issue-${ISSUE_NUMBER}"
4. Reference AWS documentation, CDK patterns, and context7 knowledge via MCP as needed for implementation
5. Implement ONLY what is described in the issue
6. Write clean, working code following project conventions
7. Add appropriate tests if the project has a test suite
8. If test code exists in the project, run all tests and ensure they pass before proceeding
9. Create PR targeting the 'main' branch using mcp__github__create_pull_request
10. If tests were run, add a comment to the PR with the test results using mcp__github__create_issue_comment
11. Remove "ready-for-implementation" label and add "implemented" label using mcp__github__update_issue

Available MCP Resources:
- AWS Documentation: Use awslabs.aws-documentation-mcp-server for AWS service documentation
- CDK Patterns: Use awslabs.cdk-mcp-server for CDK best practices and patterns
- Context7: Use context7 for additional coding knowledge and patterns

Focus on:
- Solving the specific problem described
- Writing maintainable code
- Following existing patterns in the codebase
- Leveraging AWS best practices when applicable

Do NOT:
- Add features not requested in the issue
- Refactor unrelated code
- Create documentation unless specifically requested

review-prompt.txtは実装レビューするためのpromptです。

.github/prompts/review-prompt.txt
You are a senior code reviewer. Review this pull request and provide comprehensive feedback.

PR Information:
- REPO: ${REPOSITORY}
- PR_NUMBER: ${PR_NUMBER}

REVIEW PROCESS:
1. Use mcp__github__get_pull_request to understand the PR context
2. Use mcp__github__get_pull_request_diff to examine the code changes
3. Reference AWS documentation, CDK patterns, and context7 knowledge via MCP as needed for review
4. Create a pending review using mcp__github__create_pending_pull_request_review
5. Add inline comments using mcp__github__add_comment_to_pending_review for specific code issues
6. Submit the review using mcp__github__submit_pending_pull_request_review with overall feedback

FOCUS AREAS:
- Code quality and best practices
- Potential bugs or issues
- Performance considerations
- Security implications
- Test coverage
- Documentation updates if needed
- AWS best practices when applicable
- Error handling and edge cases

REVIEW GUIDELINES:
- Provide constructive feedback with specific suggestions for improvement
- Use inline comments to highlight specific areas of concern
- Acknowledge good practices and improvements
- Be respectful and educational in your feedback
- Consider the PR's scope and avoid scope creep suggestions

Available MCP Resources:
- AWS Documentation: Use awslabs.aws-documentation-mcp-server for AWS service documentation
- CDK Patterns: Use awslabs.cdk-mcp-server for CDK best practices and patterns
- Context7: Use context7 for additional coding knowledge and patterns

If the changes look good overall, approve the PR. If there are critical issues, request changes. Otherwise, provide comments for consideration.

claude.ymlは、IssueやPR上でclaudeへのメンションをトリガーに起動します。書き込み権限を与えているので、PR内容の修正なども任せることができます。

.github/workflows/claude.yml
name: Claude Mention Assistant

on:
  issue_comment:
    types: [created]
  pull_request_review_comment:
    types: [created]
  issues:
    types: [opened, assigned]
  pull_request_review:
    types: [submitted]

jobs:
  claude-code-action:
    if: |
      (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
      (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
      (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
      (github.event_name == 'issues' && contains(github.event.issue.body, '@claude'))
    runs-on: ubuntu-latest
    concurrency:
      group: ${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number }}
      cancel-in-progress: false
    permissions:
      contents: write
      pull-requests: write
      issues: write
      id-token: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Run Claude PR Action
        uses: anthropics/claude-code-action@beta
        with:
          # anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          # Or use OAuth token instead:
          claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
          timeout_minutes: "15"
          allowed_tools: |
            Bash,
            Write,
            Edit,
            MultiEdit,
            Read,
            LS,
            Glob,
            Grep,
            mcp__github__get_issue,
            mcp__github__create_branch,
            mcp__github__create_pull_request,
            mcp__github__update_issue
          mcp_config: .github/mcp-servers.json
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          # mode: tag  # Default: responds to @claude mentions
          # Optional: Restrict network access to specific domains only
          # experimental_allowed_domains: |
          #   .anthropic.com
          #   .github.com
          #   api.github.com
          #   .githubusercontent.com
          #   bun.sh
          #   registry.npmjs.org
          #   .blob.core.windows.net

issue-to-pr.ymlは、ready-for-implementationというラベルがIssueに貼られたことをトリガーに起動します。Issueとimplementation-promptの内容を元に実装します。

.github/workflows/issue-to-pr.yml
name: Issue to PR

on:
  issues:
    types: [labeled]

jobs:
  implement:
    if: github.event.label.name == 'ready-for-implementation'
    runs-on: ubuntu-latest
    permissions:
      contents: write
      issues: write
      pull-requests: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Install uv
        run: |
          curl -LsSf https://astral.sh/uv/install.sh | sh
          echo "$HOME/.local/bin" >> $GITHUB_PATH

      - name: Substitute variables in prompt file
        run: |
          sed -e 's|\${REPOSITORY}|${{ github.repository }}|g' \
              -e 's|\${ISSUE_NUMBER}|${{ github.event.issue.number }}|g' \
              .github/prompts/implementation-prompt.txt > ${{ runner.temp }}/implementation-prompt-processed.txt

      - name: Run Implementation
        uses: anthropics/claude-code-base-action@beta
        with:
          prompt_file: ${{ runner.temp }}/implementation-prompt-processed.txt
          allowed_tools: |
            Bash,
            Write,
            Edit,
            MultiEdit,
            Read,
            LS,
            Glob,
            Grep,
            mcp__github__get_issue,
            mcp__github__create_branch,
            mcp__github__create_pull_request,
            mcp__github__update_issue,
            mcp__awslabs.aws-documentation-mcp-server__get_aws_documentation,
            mcp__awslabs.aws-documentation-mcp-server__search_aws_documentation,
            mcp__awslabs.cdk-mcp-server__CDKGeneralGuidance,
            mcp__awslabs.cdk-mcp-server__GetAwsSolutionsConstructPattern,
            mcp__awslabs.cdk-mcp-server__SearchGenAICDKConstructs,
            mcp__awslabs.cdk-mcp-server__GenerateBedrockAgentSchema,
            mcp__awslabs.cdk-mcp-server__LambdaLayerDocumentationProvider,
            mcp__awslabs.cdk-mcp-server__ExplainCDKNagRule,
            mcp__awslabs.cdk-mcp-server__CheckCDKNagSuppressions,
            mcp__context7__resolve-library-id,
            mcp__context7__get-library-docs
          mcp_config: .github/mcp-servers.json
          timeout_minutes: "20"
          claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

pr-review.ymlはPull RequestにReviewerが割り当てられたことをTriggerに起動し、Pull Requestをレビューします。

.github/workflows/pr-review.yml
name: PR Review

on:
  pull_request:
    types: [review_requested]

jobs:
  auto-review:
    # 特定のユーザーが割り当てられた時のみ実行する場合は以下のようなif条件を追加
    # if: github.event.requested_reviewer.login == 'specific-username'
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install uv
        run: |
          curl -LsSf https://astral.sh/uv/install.sh | sh
          echo "$HOME/.local/bin" >> $GITHUB_PATH

      - name: Substitute variables in prompt file
        run: |
          sed -e 's|\${REPOSITORY}|${{ github.repository }}|g' \
              -e 's|\${PR_NUMBER}|${{ github.event.pull_request.number }}|g' \
              .github/prompts/review-prompt.txt > ${{ runner.temp }}/review-prompt-processed.txt

      - name: Automatic PR Review
        uses: anthropics/claude-code-base-action@beta
        with:
          prompt_file: ${{ runner.temp }}/review-prompt-processed.txt
          allowed_tools: |
            mcp__github__get_pull_request,
            mcp__github__get_pull_request_diff,
            mcp__github__create_pending_pull_request_review,
            mcp__github__add_comment_to_pending_review,
            mcp__github__submit_pending_pull_request_review,
            mcp__awslabs.aws-documentation-mcp-server__get_aws_documentation,
            mcp__awslabs.aws-documentation-mcp-server__search_aws_documentation,
            mcp__awslabs.cdk-mcp-server__CDKGeneralGuidance,
            mcp__awslabs.cdk-mcp-server__GetAwsSolutionsConstructPattern,
            mcp__awslabs.cdk-mcp-server__SearchGenAICDKConstructs,
            mcp__awslabs.cdk-mcp-server__ExplainCDKNagRule,
            mcp__awslabs.cdk-mcp-server__CheckCDKNagSuppressions,
            mcp__context7__resolve-library-id,
            mcp__context7__get-library-docs
          mcp_config: .github/mcp-servers.json
          timeout_minutes: "5"
          claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

セットアップ

それではセットアップしていきます。
事前にClaude Codeのセットアップが済んでいる前提で進めます。
以下の記事を参考にしました。
https://docs.anthropic.com/ja/docs/claude-code/github-actions
https://zenn.dev/kazukih/articles/f3f3def174c4dc

Claude Codeで以下のスラッシュコマンドを実行します。

/install-github-app

Enterを押すとGitHub AppのClaudeを導入するかWeb上で聞かれるのでConfigureボタンから特定のリポジトリのみ設定します。
Screenshot 2025-08-13 at 22.10.40

問題なく設定できると、リポジトリの Settings に表示されます。
Screenshot 2025-08-13 at 22.13.11

この後ローカルで作業を進めたところGitHubリポジトリへのアクセスエラーとなったため、直接トークンを設定する方法に切り替えました。
以下のコマンドを実行するとOAuth tokenが発行されますので、値をGitHubのSettingsのActions secrets and variablesRepository secretsに登録します。

claude setup-token

Screenshot 2025-08-13 at 22.44.43

GitHubのSettings > Actions > General > Workflow permissionsで以下2点チェックを入れます。

  • Read and write permissions
  • Allow GitHub Actions to create and approve pull requests

Screenshot 2025-08-14 at 7.57.56

使ってみた

では、実際に使ってみます。
GitHubに実装コードを格納した状態で、Issueを作成します。
簡単にJson→CSVへ変換するLambdaを実装するIssueとしたいと思います。

Issue Sample
# JSON→CSV 変換 Lambda(CDK: TypeScript、Lambda: Python 3.9)

## 目的
- S3内のJSONファイルをCSVに変換し同一バケットに保存するシンプルな実装
- 手動実行を前提とした最小構成
- pytestを使用した包括的なテスト実装

## ディレクトリ構成
```
json-to-csv-converter/
├── bin/
│   └── app.ts                    # CDKエントリーポイント
├── lib/
│   └── json-to-csv-stack.ts      # CDKスタック定義
├── lambda/
│   ├── handler.py                # Lambda関数本体
│   └── requirements.txt          # Python依存関係
├── tests/
│   ├── __init__.py               # テストパッケージ初期化
│   ├── test_handler.py           # Lambda関数のテスト
│   ├── conftest.py               # pytest設定・フィクスチャ
│   └── test_data/
│       ├── valid_data.json       # 正常データテスト用
│       ├── empty_data.json       # 空データテスト用
│       └── invalid_data.txt      # 異常データテスト用
├── README.md                     # プロジェクト説明
├── package.json                  # Node.js依存関係
├── cdk.json                      # CDK設定
├── tsconfig.json                 # TypeScript設定
├── pytest.ini                   # pytest設定
└── .gitignore
```

## 技術仕様

### Lambda設定
- **Runtime**: Python 3.9
- **Memory**: 256MB
- **Timeout**: 3分
- **トリガー**: なし(手動実行)
- **環境変数**: `BUCKET_NAME` (S3バケット名)

### データフロー
- **入力**: `s3://{BUCKET_NAME}/input/data.json`
- **出力**: `s3://{BUCKET_NAME}/output/data.csv`

### 入出力形式
**入力JSON例:**
```json
[
  {"id": 1, "name": "Alice", "age": 30},
  {"id": 2, "name": "Bob", "age": 25}
]
```

**出力CSV例:**
```csv
id,name,age
1,Alice,30
2,Bob,25
```

### IAM権限
- `s3:GetObject` on `input/*`
- `s3:PutObject` on `output/*`

## 実装要件

### Lambda処理フロー
1. S3から入力JSONファイル読み込み
2. JSONパース(配列形式を想定)
3. CSV形式に変換(Python csv module使用)
4. S3に出力CSVファイル保存
5. CloudWatch Logsに処理件数記録

### エラーハンドリング
- [ ] 入力ファイル不存在
- [ ] JSONパースエラー
- [ ] 空配列処理(ヘッダーのみ出力)
- [ ] 環境変数未設定エラー

### テスト要件
- **フレームワーク**: pytest
- **モック**: moto (boto3 S3操作)
- **カバレッジ目標**: 80%以上

**テストケース:**
- [ ] 正常系: 有効JSONデータ変換
- [ ] 異常系: ファイル不存在
- [ ] 異常系: 無効JSON形式
- [ ] 境界値: 空データ
- [ ] 境界値: 特殊文字含むデータ

## タスクリスト

### インフラ構築
- [ ] CDKプロジェクト初期化
- [ ] package.json作成
- [ ] tsconfig.json設定
- [ ] cdk.json設定
- [ ] S3バケット作成(CDK)
- [ ] Lambda関数作成(CDK)
- [ ] IAM権限設定

### Lambda実装
- [ ] handler.py実装
- [ ] requirements.txt作成
- [ ] JSON読み込み処理
- [ ] CSV変換処理
- [ ] S3保存処理
- [ ] エラーハンドリング
- [ ] ログ出力

### テスト実装
- [ ] pytest.ini設定
- [ ] conftest.py作成
- [ ] test_handler.py実装
- [ ] テストデータ作成
  - [ ] valid_data.json
  - [ ] empty_data.json
  - [ ] invalid_data.txt
- [ ] 正常系テスト
- [ ] 異常系テスト
- [ ] エッジケーステスト

### ドキュメント
- [ ] README.md作成
- [ ] テスト実行手順記載
- [ ] デプロイ手順記載
- [ ] .gitignore作成

## 受け入れ基準
- [ ] `cdk deploy`でリソースが正常デプロイされる
- [ ] **`pytest tests/ -v`ですべてのテストが成功する**
- [ ] テストカバレッジが80%以上
- [ ] 実際のS3環境でLambda手動実行が成功する
- [ ] CloudWatch Logsに適切なログが出力される

## テスト実行コマンド
```bash
# 依存関係インストール
pip install -r lambda/requirements.txt
pip install pytest moto pytest-cov

# テスト実行
pytest tests/ -v

# カバレッジ付きテスト実行
pytest --cov=lambda tests/ --cov-report=html
```

## 完了条件**すべてのpytestが成功すること**

ready-for-implementationlabelをつけることで、issue-to-pr.ymlのworkflowが起動します。
Screenshot 2025-08-14 at 9.54.10
Screenshot 2025-08-14 at 7.43.52
8分ほどで処理が終了しました。
Screenshot 2025-08-14 at 10.11.05
指示通りに実装を行い、Testも実行してくれています。
Screenshot 2025-08-14 at 10.13.05
Screenshot 2025-08-14 at 10.13.29

次にレビューもお願いしてみます。Reviewers に任意のユーザーを割り当てると、pr-review.ymlのworkflowが起動します。
Screenshot 2025-08-14 at 10.13.55
Screenshot 2025-08-14 at 10.14.06

処理は2分ほどで終了しました。
Screenshot 2025-08-14 at 10.22.12
複数の指摘コメントをいただきました。
Screenshot 2025-08-14 at 10.23.12

最後にコメント上でClaudeにメンションし、動作するか確認してもらいます。
Screenshot 2025-08-14 at 10.26.56
4分ほどで完了しました。
Screenshot 2025-08-14 at 10.34.32

Claudeいわく、問題なく動作するよとのことなので、localにpullして動作確認してみたいと思います。
Screenshot 2025-08-14 at 10.39.58

Pythonのライブラリinstallしてpytestのcoverage出力しました。95%となっていたので、GitHub上の数値と一致しています。
Screenshot 2025-08-14 at 10.43.45

CDKデプロイコマンドを実行し、CloudFormationスタックの作成にも成功しています。
Screenshot 2025-08-14 at 10.59.42

S3にテストデータを格納し、Lambdaを実行しましたが、こちらも成功しました。
Screenshot 2025-08-14 at 10.58.44
output ディレクトリにファイルが生成されています。
Screenshot 2025-08-14 at 10.58.55

最後に

多くの実装はGitHub Issue Triggerで対応できそうです。ただし、最終段階ではAIレビューに加えて人による確認が重要だと感じました。

この記事をシェアする

facebookのロゴhatenaのロゴtwitterのロゴ

© Classmethod, Inc. All rights reserved.