Przejdź do głównej zawartości

Integracja CI/CD i automatyzacja

Integracja CI/CD osadza Claude Code w pipelinie zamiast w sesji interaktywnej, przez akcję GitHuba anthropics/claude-code-action@v1 i tryb headless (claude -p). Automatyczne review pull requestów, triage zgłoszeń, naprawa buildów i nocna dokumentacja wiszą na zdarzeniach, na które zespół i tak reaguje — komentarzach, etykietach, nieudanych przebiegach, cronie — na API Anthropic, AWS Bedrock albo Google Vertex AI.

Trzydzieści pull requestów tygodniowo, każdy czeka godzinami na pierwsze spojrzenie człowieka. Połowa komentarzy w review to wciąż te same wzorce: brak obsługi błędów, niespójne nazewnictwo, testy omijające przypadki brzegowe. W tym czasie niestabilne testy dostają pieczątkę, regresja bezpieczeństwa się prześlizguje, a dokumentacja co noc odpływa od kodu.

Więcej recenzentów niczego nie załatwi. Załatwia to automatyczne pierwsze przejście na każdym PR-ze — i to jest moment, w którym Claude Code przestaje być narzędziem interaktywnym, a staje się częścią pipeline’u.

  • Działający workflow @claude, który odpowiada na komentarze w PR-ach i zgłoszeniach
  • Zadanie review AI na każdym pull requeście, oparte o wbudowaną komendę /review albo o własny prompt nastawiony na bezpieczeństwo
  • Zadanie auto-fix, które czyta logi awarii i wypycha poprawkę, nie zamiatając prawdziwej regresji pod dywan
  • Automatyzacje z harmonogramu: dzienne podsumowanie, auto-etykietowanie zgłoszeń i nocny PR z dokumentacją
  • Konfiguracje Bedrock i Vertex AI dla środowisk korporacyjnych
  • Bramkę kosztową, która wywołuje Claude wyłącznie przy poważniejszych diffach

Najszybsza droga to uruchomienie instalatora z wnętrza Claude Code.

  1. Uruchom REPL i odpal instalator

    Wpisz claude, żeby otworzyć interaktywny REPL, a potem komendę /install-github-app. Przeprowadzi cię przez instalację aplikacji GitHub i utworzenie wymaganych sekretów.

  2. Przejdź przez kreator

    Autoryzuj aplikację Claude GitHub, nadaj uprawnienia do repozytorium i pozwól jej skonfigurować klucz API. Aplikacja potrzebuje Contents, Issues i Pull requests na poziomie Read & Write.

  3. Przetestuj integrację

    Dodaj w zgłoszeniu komentarz wspominający Claude:

    @claude implement this feature based on the issue description

Claude czyta otaczający kontekst — opis zgłoszenia, diff PR-a, historię rozmowy — i odpowiada kodem, wyjaśnieniem albo bezpośrednimi zmianami. Ta sama wzmianka zadziała przy @claude fix the TypeError in the dashboard component czy przy otwartym pytaniu @claude how should I approach refactoring the auth middleware?.

Ręczne podpięcie akcji, łącznie z Bedrockiem i Vertexem

Dział zatytułowany „Ręczne podpięcie akcji, łącznie z Bedrockiem i Vertexem”

Ręczna konfiguracja jest potrzebna przy własnych ustawieniach i u dostawców chmurowych. Dodaj klucz jako sekret repozytorium o nazwie ANTHROPIC_API_KEY, a potem utwórz plik workflow.

.github/workflows/claude.yml
name: Claude Code Actions
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened]
permissions:
contents: write
pull-requests: write
issues: write
jobs:
claude-pr:
if: contains(github.event.comment.body, '@claude')
runs-on: ubuntu-latest
timeout-minutes: 60 # Job-level clock, not an action input
steps:
- uses: actions/checkout@v4
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
trigger_phrase: '@claude'
claude_args: '--max-turns 30'

Co się psuje, gdy konfigurację chmurową pisze się z głowy

Dział zatytułowany „Co się psuje, gdy konfigurację chmurową pisze się z głowy”

AWS_REGION to wymagana zmienna środowiskowa dla Bedrocka. Akcja configure-aws-credentials eksportuje ją z aws-region, ale ustawienie jej wprost na zadaniu chroni konfigurację, gdy ktoś później przestawi kolejność kroków.

Przy Vertexie akcja nie ma wejść vertex_region ani vertex_project_id. Region i projekt podaje się zmiennymi środowiskowymi CLOUD_ML_REGION i ANTHROPIC_VERTEX_PROJECT_ID, a projekt wyliczy się sam z outputu kroku google-github-actions/auth, jeśli go przepniesz tak jak wyżej.

/review to gotowa komenda, a akcja wystawia jej ustalenia jako komentarze review na PR-ze. To najtańsza użyteczna automatyzacja z całej listy:

.github/workflows/claude-review.yml
name: AI Code Review
on:
pull_request:
types: [opened, synchronize]
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for better analysis
- uses: anthropics/claude-code-action@v1
with:
# /review is a built-in command; the action posts review comments to the PR.
prompt: '/review'
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
claude_args: '--max-turns 5'

Review nastawione na bezpieczeństwo, z własnymi instrukcjami

Dział zatytułowany „Review nastawione na bezpieczeństwo, z własnymi instrukcjami”

Wbudowana komenda ogarnia typowe przypadki. Kiedy chcesz przejścia pod kątem bezpieczeństwa i ze sztywnym formatem wyjścia, wpisz własne instrukcje wprost w pole prompt — wejścia prompt_file nie ma.

Słownik wagi problemów znaczy więcej, niż się wydaje. Review, które wszystko zgłasza tym samym tonem, w drugim tygodniu zaczyna być ignorowane, więc każ promptowi porządkować ustalenia i mówić wprost, kiedy nie znalazł nic poważnego.

Oznacz zgłoszenie etykietą i pozwól pipeline’owi otworzyć PR-a:

.github/workflows/issue-to-pr.yml
name: Issue to PR
on:
issues:
types: [labeled]
jobs:
implement-feature:
if: github.event.label.name == 'implement-with-claude'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: anthropics/claude-code-action@v1
with:
prompt: |
Implement the feature described in issue #${{ github.event.issue.number }}:
${{ github.event.issue.title }}
${{ github.event.issue.body }}
Follow our coding standards in CLAUDE.md.
Create comprehensive tests.
Update documentation as needed.
When the change is complete, open a pull request titled
"feat: ${{ github.event.issue.title }}" and reference this issue in the body.
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
claude_args: '--max-turns 30'

Etykieta jest bramką. Nic się nie uruchomi, dopóki człowiek nie uzna, że zgłoszenie jest opisane dość dokładnie, by je przekazać. To właśnie różnica między użyteczną automatyzacją a botem otwierającym dwanaście PR-ów do jednozdaniowego zgłoszenia błędu.

.github/workflows/fix-ci.yml
name: Auto-fix CI Failures
on:
workflow_run:
workflows: ['CI']
types: [completed]
jobs:
fix-failures:
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_branch }}
- name: Get failure logs
uses: actions/github-script@v7
id: logs
with:
script: |
// workflow_run.id is a RUN id, so use downloadWorkflowRunLogs (run_id),
// not downloadJobLogsForWorkflowRun (which expects a job_id).
const logs = await github.rest.actions.downloadWorkflowRunLogs({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }}
});
return logs.data;
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
claude_args: '--max-turns 20'
prompt: |
The CI build failed with these errors:
${{ steps.logs.outputs.result }}
Fix the issues causing the build to fail.
Focus on test failures, linting errors, and type errors.
Commit the fix to the current branch with the message "fix: resolve CI failures".

To wersja naiwna, a wersja naiwna prędzej czy później skasuje test, żeby build zrobił się zielony. Utwardź ją:

name: Daily Report
on:
schedule:
- cron: "0 9 * * 1-5" # 9 AM weekdays
jobs:
report:
runs-on: ubuntu-latest
steps:
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: |
Generate a summary of the last 24 hours:
1. List all merged PRs with a one-line description
2. List all open issues created in the last 24 hours
3. Highlight any CI failures on the main branch
Create this as a comment on issue #1 (our daily log).
claude_args: "--model sonnet --max-turns 5"

Automatyczne poprawianie lintera i błędów typów na nowych PR-ach

Dział zatytułowany „Automatyczne poprawianie lintera i błędów typów na nowych PR-ach”
name: Auto-Fix
on:
pull_request:
types: [opened]
jobs:
fix:
runs-on: ubuntu-latest
steps:
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: |
Run the linter and fix any issues. If there are type errors,
fix those too. Commit the changes with a clear message.
claude_args: "--max-turns 15"

Ta akurat działa w trybie headless, a nie przez akcję, bo łączy kilka przejść, a wynik oddaje akcji tworzącej PR-a:

.github/workflows/update-docs.yml
name: Update Documentation
on:
schedule:
- cron: '0 2 * * *' # 2 AM daily
workflow_dispatch:
jobs:
update-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Update API Documentation
run: |
claude -p "Update API documentation in docs/api.md based on current code in src/api/" \
--allowedTools "Edit" "Read" \
--output-format json > result.json
- name: Update README
run: |
claude -p "Update README.md badges, dependencies list, and examples based on package.json and recent changes" \
--allowedTools "Edit" "Read"
- name: Create PR if changes
uses: peter-evans/create-pull-request@v7
with:
title: 'docs: automated documentation updates'
commit-message: 'docs: update API docs and README'
branch: auto-update-docs

claude -p to ten sam agent bez REPL-a. Przyjmuje prompt, respektuje --allowedTools i potrafi wypluć JSON do sparsowania przez skrypt:

Okno terminala
# Simple one-shot command
claude -p "Update all copyright headers to 2026" --output-format json
# With specific permissions
claude -p "Fix the failing test in auth.test.js" \
--allowedTools "Edit" "Read" "Bash" \
--output-format json
# Pipe data for processing
cat error.log | claude -p "Analyze these errors and suggest fixes"

Przy cat file | claude -p promptem staje się stdin, więc argument pozycyjny jest zbędny. Na tym idiomie stoi oficjalny jednolinijkowiec gh pr diff "$1" | claude -p --append-system-prompt "..." --output-format json i to on sprawia, że długie, wielolinijkowe prompty da się sensownie trzymać w skrypcie powłoki.

Jedno przejście planujące tworzy listę, a pętla uruchamia wąskie przejście na każdy plik. Kontekst każdego wywołania zostaje mały, co wychodzi taniej i celniej niż jeden ogromny prompt migracyjny:

migrate-components.sh
#!/bin/bash
# Generate task list
claude -p "List all React class components that need hooks migration" \
--output-format json > tasks.json
# Process each component
jq -r '.files[]' tasks.json | while read file; do
echo "Migrating $file..."
claude -p "Convert $file from class component to hooks. Preserve all functionality." \
--allowedTools "Edit"
done
Okno terminala
# Code quality pipeline
npm run lint 2>&1 | \
claude -p "Fix all linting errors" --allowedTools "Edit" | \
claude -p "Now run tests and fix any failures" --allowedTools "Bash" "Edit" | \
claude -p "Generate a summary of changes" > changes.md
.git/hooks/pre-commit
#!/bin/bash
# Check for TODO comments
if git diff --cached --name-only | xargs grep -l "TODO" > /dev/null; then
echo "Found TODO comments. Asking Claude to address them..."
git diff --cached --name-only | xargs grep -l "TODO" | while read file; do
claude -p "In $file, implement any TODO comments or convert them to proper issues" \
--allowedTools "Edit"
done
# Re-stage changes
git add -u
fi

Zadanie planujące tworzy listę serwisów, a zadanie macierzowe wprowadza tę samą zmianę w każdym repozytorium:

.github/workflows/coordinated-update.yml
name: Coordinated Service Update
on:
workflow_dispatch:
inputs:
change_description:
description: 'Describe the change to implement'
required: true
jobs:
plan:
runs-on: ubuntu-latest
outputs:
plan: ${{ steps.create-plan.outputs.plan }}
steps:
- uses: actions/checkout@v4
- id: create-plan
run: |
PLAN=$(claude -p "Create an implementation plan for: ${{ github.event.inputs.change_description }}. List affected services and order of updates." --output-format json)
echo "plan=$PLAN" >> $GITHUB_OUTPUT
update-services:
needs: plan
strategy:
matrix:
service: ${{ fromJson(needs.plan.outputs.plan).services }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
repository: myorg/${{ matrix.service }}
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
claude_args: '--max-turns 30'
prompt: |
Implement this change: ${{ github.event.inputs.change_description }}
This is service: ${{ matrix.service }}
Full plan: ${{ needs.plan.outputs.plan }}
Ensure backward compatibility, then open a pull request against this service's
default branch describing the change and its place in the overall plan.

Niech ustalenia produkują istniejące skanery, a Claude zajmie się triage’em i opisem:

.github/workflows/security-scan.yml
name: Security Analysis
on:
pull_request:
branches: [main]
jobs:
security-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Security Scan
run: |
npm audit --json > audit.json
bandit -r . -f json -o bandit.json || true
- name: Analyze and Fix
run: |
claude -p "Analyze security reports and fix critical issues:
NPM Audit: $(cat audit.json)
Bandit: $(cat bandit.json)
Fix only CRITICAL and HIGH severity issues.
Document any issues that require manual review." \
--allowedTools "Edit" "Read"
- name: Generate Security Report
run: |
claude -p "Generate a security assessment report based on the changes made" \
> security-report.md

Trzymaj klucz API z dala od logów i artefaktów, nadaj kluczowi CI własny limit wydatków i ogranicz uprawnienia Claude do minimum, którego zadanie faktycznie potrzebuje. Zmiany wprowadzone automatycznie i tak przechodzą przez review człowieka, zanim trafią na produkcję.

Claude Code działa na runnerach GitHuba, więc każde zadanie zjada zarówno minuty Actions, jak i tokeny API. Cztery dźwignie robią większość roboty:

  • Ogranicz liczbę tur. --max-turns w claude_args nie pozwala zadaniu się rozbiec. Pięć do dziesięciu tur wystarcza przy większości review.
  • Wybieraj model wprost. Domyślne ustawienia konta bywają różne, więc jeśli zależy ci na niższym koszcie, podaj w CI --model claude-sonnet-5, zamiast liczyć na domyślny model środowiska.
  • Ogranicz zegar. timeout-minutes: na poziomie zadania zatrzyma nieskończoną pętlę; wejścia timeout_minutes w akcji nie ma.
  • Ogranicz równoległe przebiegi. Grupa concurrency na PR anuluje nieaktualny przebieg, gdy ktoś wypchnie trzy commity pod rząd.
jobs:
claude:
runs-on: ubuntu-latest
timeout-minutes: 10
concurrency:
group: claude-${{ github.event.pull_request.number }}
cancel-in-progress: true

Wywoływanie Claude tylko przy poważniejszych diffach

Dział zatytułowany „Wywoływanie Claude tylko przy poważniejszych diffach”

Największa oszczędność to nie uruchomić się wcale. Zabramkuj zadanie review tanim sprawdzeniem w powłoce, żeby dwulinijkowa literówka nigdy nie płaciła za wywołanie modelu:

name: Smart Claude Trigger
on:
pull_request:
paths:
- '**.ts'
- '**.tsx'
- '**.js'
- '**.jsx'
jobs:
analyze-complexity:
runs-on: ubuntu-latest
outputs:
should-run-claude: ${{ steps.check.outputs.result }}
steps:
- uses: actions/checkout@v4
- id: check
run: |
# Only run Claude for substantial changes
LINES_CHANGED=$(git diff --numstat origin/main..HEAD | awk '{sum+=$1+$2} END {print sum}')
if [ $LINES_CHANGED -gt 50 ]; then
echo "result=true" >> $GITHUB_OUTPUT
else
echo "result=false" >> $GITHUB_OUTPUT
fi
claude-review:
needs: analyze-complexity
if: needs.analyze-complexity.outputs.should-run-claude == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
prompt: '/review'
claude_args: '--max-turns 5'

Przy przejściach analitycznych, które nie zmieniają się między przebiegami, zapisz wynik w cache’u kluczowanym po plikach źródłowych i przy trafieniu pomiń wywołanie w całości:

- name: Cache Claude Analysis
uses: actions/cache@v4
with:
path: .claude-cache
key: claude-${{ hashFiles('**/*.ts', '**/*.tsx') }}
- name: Run Claude Analysis
run: |
if [ -f .claude-cache/analysis.json ]; then
echo "Using cached analysis"
else
claude -p "Analyze codebase for potential improvements" \
--output-format json > .claude-cache/analysis.json
fi

Claude nie reaguje na @claude. Sprawdź, czy aplikacja Claude GitHub jest zainstalowana i ma właściwe uprawnienia (Contents, Issues, Pull requests — wszystkie Read & Write), czy warunki wyzwalacza faktycznie pasują do zdarzenia i czy nazwa sekretu w workflow zgadza się z tą w repozytorium.

CI nie uruchamia się na commitach Claude. Domyślnie GitHub Actions nie wyzwalają się na commitach tworzonych przez aplikacje GitHub. Jeśli CI ma działać na commitach Claude, użyj własnej aplikacji GitHub z actions/create-github-app-token.

Błędy uwierzytelniania przy Bedrocku albo Vertexie. Odpowiedzi 401 i 403 zwykle oznaczają źle skonfigurowaną wymianę tokenu OIDC. Sprawdź, czy polityka zaufania w koncie chmurowym wskazuje twoje repozytorium i czy rola IAM lub konto serwisowe ma uprawnienie do wywoływania modelu.

Zadania są anulowane po przekroczeniu czasu. Podnieś timeout-minutes: na poziomie zadania — wejścia timeout_minutes w akcji nie ma — i obniż --max-turns, żeby rozbiegane zadanie kończyło się szybciej. Jeśli oba są już rozsądne, zadanie jest po prostu za duże: podziel je na mniejsze kroki z konkretniejszymi promptami.

Actions kosztuje więcej, niż zakładałeś. Długie zadania na Opusie zjadają sporo tokenów. Zacznij od --model claude-sonnet-5 i --max-turns 5, dołóż powyższą bramkę na rozmiar diffa, a limity podnoś dopiero wtedy, gdy jakość review okaże się niewystarczająca.

Po cichu zignorowane wejście. Ustawienie model:, max_turns: czy prompt_file: na akcji nie robi zupełnie nic — żadnego ostrzeżenia, żadnego błędu, po prostu zachowanie domyślne. Kiedy workflow zachowuje się tak, jakby twojej konfiguracji nie było, zestaw ją z siedmioma wejściami, które akcja v1 faktycznie przyjmuje.