Claude Code Actions を使って CI 失敗をしつこく自動で直す
CI失敗自動検知・修正ワークフローの実装
Claude Code Actions (CCA) を使って, CI失敗の検知から修正まで行う自動ワークフローを作ってみました。
- PRのCI失敗は PR 内で成功するまで CCA に直させます
- main ブランチにマージした後に失敗が起こる場合は、それを解決するための issue を作成し、そこから 解決用 PR を作らせます
- ラベルで状態管理します
- これでもかというくらい、CIが失敗したら CC に依頼して直させます
アーキテクチャ概要
このワークフローは3つのYAMLファイルで構成されています:
- ci.yml - メインのCI/CDパイプライン
- ci-result-handler.yml - CI結果の監視とラベル管理
- ci-fix.yml - CI失敗の自動修正
1. メインCI/CDパイプライン (ci.yml)
name: CI/CD Pipeline
on:
push:
branches: [ main, develop, feature/* ]
pull_request:
branches: [ main, develop ]
jobs:
test:
name: Test Suite
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linting
run: npm run lint
- name: Run unit tests
run: npm run test
2. CI結果監視ワークフロー (ci-result-handler.yml)
CI結果を監視し、失敗時に自動的にラベルを付与するワークフローです。
主な機能
- PR用CI結果ハンドラー: PR関連のCI結果を監視
- Mainブランチ用CI失敗ハンドラー: mainブランチでのCI失敗時にIssueを自動作成
name: CI Result Handler
on:
workflow_run:
workflows: ["CI/CD Pipeline"]
types: [completed]
jobs:
handle-pr-ci-result:
name: Handle PR CI Result
runs-on: ubuntu-latest
if: github.event.workflow_run.event == 'pull_request'
permissions:
contents: read
pull-requests: write
issues: write
actions: read
id-token: write
steps:
- name: Handle CI Result
uses: actions/github-script@v7
with:
github-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
script: |
# PR番号の取得ロジック
let prNumber = null;
if (context.payload.workflow_run.pull_requests &&
context.payload.workflow_run.pull_requests.length > 0) {
prNumber = context.payload.workflow_run.pull_requests[0].number;
} else {
# フォールバック: ブランチ名でPRを検索
const headBranch = context.payload.workflow_run.head_branch;
const { data: pullRequests } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
head: `${context.repo.owner}:${headBranch}`,
state: 'open'
});
if (pullRequests.length > 0) {
prNumber = pullRequests[0].number;
}
}
const conclusion = context.payload.workflow_run.conclusion;
if (conclusion === 'failure') {
# CI失敗時: ci-failureラベルを追加
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
labels: ['ci-failure']
});
} else if (conclusion === 'success') {
# CI成功時: ci-passedラベルを追加
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
labels: ['ci-passed']
});
}
Mainブランチ用CI失敗ハンドラー
handle-main-ci-failure:
name: Handle Main CI Failure
runs-on: ubuntu-latest
if: |
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'main' &&
github.event.workflow_run.conclusion == 'failure'
steps:
- name: Create Issue for Main CI Failure
uses: actions/github-script@v7
with:
script: |
const issueTitle = `🚨 Main CI Failure: ${commitMessage}`;
const issueBody = `## Main Branch CI Failure
**失敗時刻**: ${timestamp}
**コミット**: \`${commitSha}\` by ${author}
**ワークフロー**: [実行結果を確認](${runUrl})
@claude この CI 失敗を分析し、修正して, PRを作成してください。`;
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: issueTitle,
body: issueBody,
labels: ['ci-failure', 'main-branch', 'bug']
});
PR自動作成
上記で、CC にPR作成を頼んでも、作成リンクだけつくられてプルリクエストまで作ってくれないことが多いので、PR作成リンクを検知してPRを自動作成する Github Actions も作っています。
name: Create PR from Comment
on:
issue_comment:
types: [edited]
jobs:
create-pr:
name: Create PR from Comment
runs-on: ubuntu-latest
if: contains(github.event.comment.body, 'Create PR')
permissions:
contents: write
pull-requests: write
issues: write
steps:
- name: Extract and Create PR
uses: actions/github-script@v7
with:
github-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
script: |
// Compare URLからブランチ情報を抽出
const comment = context.payload.comment.body;
const urlMatch = comment.match(/https:\/\/github\.com\/[^\/\s]+\/[^\/\s]+\/compare\/[^\s)]+/);
if (!urlMatch) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.issue.number,
body: '❌ Create PR link not found'
});
return;
}
// URLをパースしてbase...head形式を抽出
const url = new URL(urlMatch[0]);
const pathMatch = url.pathname.match(/\/compare\/(.+)\.\.\.(.+)/);
if (!pathMatch) {
throw new Error('Invalid URL format');
}
// PR作成
try {
const newPR = await github.rest.pulls.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: url.searchParams.get('title') || `PR: ${pathMatch[2]} → ${pathMatch[1]}`,
body: url.searchParams.get('body') || `Auto-created from Issue #${context.payload.issue.number}`,
head: pathMatch[2],
base: pathMatch[1]
});
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.issue.number,
body: `PR created: ${newPR.data.html_url}`
});
} catch (error) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.issue.number,
body: `Error: ${error.message}${isInvalidBranch ? '\n\n🔒 Issue closed due to invalid branch.' : ''}`
});
}
3. CI失敗自動修正ワークフロー (ci-fix.yml)
ci-failureラベルが付与されたPRに対して、Claude Codeが自動的に修正を行います。
name: Claude CI Fix
on:
pull_request:
types: [labeled]
jobs:
claude-ci-fix:
name: Claude CI Fix
runs-on: ubuntu-latest
if: github.event.action == 'labeled' && github.event.label.name == 'ci-failure'
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
actions: read
steps:
- name: Remove ci-failure label
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
name: 'ci-failure'
});
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
fetch-depth: 1
- name: Run Claude Code for CI Fix
uses: anthropics/claude-code-action@beta
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
additional_permissions: |
actions: read
direct_prompt: |
CIが失敗しました。PR #${{ github.event.pull_request.number }} の CI 失敗を修正してください:
- ワークフロー結果を確認し、失敗の原因を分析してください
- 必要な修正を行ってください
- 修正後は適切なテストを実行してください
- 修正が完了したらコミットしてください
Claude Codeトリガーワークフロー (claude.yml)
@claudeメンションでClaude Codeをトリガーできるワークフローも用意します。
こちらは、公式の例
を少し改造したものです。
これを bot から起動するためには、bot 自体に PAT トークンを渡す必要があります。つまり、botにユーザとして振る舞わせるということですね。
name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
jobs:
claude:
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') || contains(github.event.issue.title, '@claude')))
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Run Claude Code
uses: anthropics/claude-code-action@beta
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
timeout_minutes: "60"
additional_permissions: |
actions: read
allowed_tools: "Agent,Bash,Edit,MultiEdit,WebFetch,WebSearch,Write"
ワークフローの動作
- PRを作成/更新
- CI/CDパイプラインが実行
- CI結果監視ワークフローが結果を検知
-
失敗時:
ci-failureラベルが自動付与 - ラベル付与: CI修正ワークフローが自動実行
- Claude Code: 失敗原因を分析し、修正を実行
- 修正完了: コミットしてCI再実行
重要な設定ポイント
必要な権限
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
actions: read # CI結果の読み取りに必要
PERSONAL_ACCESS_TOKEN (PAT) で動かす
github actions を動かす際に、通常の GITHUB_TOKEN を使うと、claude 側で権限がたりなかったり、そもそもトリガーされなかったりします。github actions で意図しない無限ループを防ぐための仕様です。そのため、今回のワークフロー構築では claude の起動トリガーとなる label やコメントの投稿などに PAT を使用しています。
必要なシークレット
-
CLAUDE_CODE_OAUTH_TOKEN: Claude Code APIトークン -
PERSONAL_ACCESS_TOKEN: GitHub Personal Access Token
ラベル管理
-
ci-failure: CI失敗時に自動付与 -
ci-passed: CI成功時に自動付与 -
main-branch: mainブランチのCI失敗Issue用
注意点
- Claude Codeの実行タイムアウトは60分に設定
- mainブランチでのCI失敗は24時間以内の重複Issue作成を防止
- 適切な権限設定が必要(特に
actions: read)
終わりに
実は issue 発行からPR作成、マージまでの完全全自動開発ワークフローを作っていて、これはその一部分を切り出したものです。
実際は ci-passed のあとに CCA でレビューを入れたり、そのレビューに基づく修正を入れたり、自動マージしたりしています。完全自動については後日。
Discussion