# CI/CD Integration Integrate Claude Code into development workflows with GitHub Actions and GitLab CI/CD. ## GitHub Actions ### Basic Workflow **.github/workflows/claude.yml:** ```yaml name: Claude Code CI on: [push, pull_request] jobs: claude-review: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: anthropic/claude-code-action@v1 with: command: '/fix:types && /test' env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} ``` ### Code Review Workflow ```yaml name: Code Review on: pull_request: types: [opened, synchronize] jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 with: fetch-depth: 0 - name: Review with Claude uses: anthropic/claude-code-action@v1 with: command: | Review the changes in this PR: - Check for bugs and edge cases - Verify test coverage - Assess performance implications - Review security concerns env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - name: Post Review Comment uses: actions/github-script@v6 with: script: | github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: process.env.CLAUDE_OUTPUT }) ``` ### Test & Fix Workflow ```yaml name: Test and Fix on: [push] jobs: test-fix: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Run Tests id: test continue-on-error: true run: npm test - name: Fix Failures if: steps.test.outcome == 'failure' uses: anthropic/claude-code-action@v1 with: command: '/fix:test check test output and fix failures' env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - name: Commit Fixes if: steps.test.outcome == 'failure' run: | git config user.name "Claude Bot" git config user.email "claude@anthropic.com" git add . git commit -m "fix: auto-fix test failures" git push ``` ### Documentation Update ```yaml name: Update Docs on: push: branches: [main] jobs: docs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Update Documentation uses: anthropic/claude-code-action@v1 with: command: '/docs:update' env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - name: Commit Docs run: | git config user.name "Claude Bot" git config user.email "claude@anthropic.com" git add docs/ git commit -m "docs: auto-update documentation" || echo "No changes" git push ``` ## GitLab CI/CD ### Basic Pipeline **.gitlab-ci.yml:** ```yaml stages: - review - test - deploy claude-review: stage: review image: node:18 script: - npm install -g @anthropic-ai/claude-code - claude login --api-key $ANTHROPIC_API_KEY - claude '/fix:types && /test' only: - merge_requests ``` ### Advanced Pipeline ```yaml variables: CLAUDE_MODEL: "claude-sonnet-4-5-20250929" stages: - lint - test - review - deploy before_script: - npm install -g @anthropic-ai/claude-code - claude login --api-key $ANTHROPIC_API_KEY lint: stage: lint script: - claude '/fix:types' artifacts: paths: - src/ expire_in: 1 hour test: stage: test script: - npm test || claude '/fix:test analyze failures and fix' coverage: '/Coverage: \d+\.\d+%/' review: stage: review script: - | claude "Review this merge request: - Check code quality - Verify tests - Review security - Assess performance" > review.md artifacts: reports: codequality: review.md only: - merge_requests deploy: stage: deploy script: - claude '/deploy-check' - ./deploy.sh only: - main ``` ### Automated Fixes ```yaml fix-on-failure: stage: test script: - npm test retry: max: 2 when: - script_failure after_script: - | if [ $CI_JOB_STATUS == 'failed' ]; then claude '/fix:test analyze CI logs and fix issues' git add . git commit -m "fix: auto-fix from CI" git push origin HEAD:$CI_COMMIT_REF_NAME fi ``` ## Common Patterns ### PR Comment Bot Post Claude reviews as PR comments: ```yaml # GitHub Actions - name: Comment PR uses: actions/github-script@v6 with: script: | const review = process.env.CLAUDE_REVIEW github.rest.pulls.createReview({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.issue.number, body: review, event: 'COMMENT' }) ``` ### Conditional Execution Run Claude only on certain conditions: ```yaml # Run on large PRs only - name: Review Large PRs if: ${{ github.event.pull_request.changed_files > 10 }} uses: anthropic/claude-code-action@v1 with: command: '/review:codebase analyze changes' ``` ### Cost Control Limit CI usage to control costs: ```yaml # Skip for draft PRs - name: Claude Review if: ${{ !github.event.pull_request.draft }} uses: anthropic/claude-code-action@v1 # Run only on specific branches - name: Claude Check if: startsWith(github.ref, 'refs/heads/release/') uses: anthropic/claude-code-action@v1 ``` ## Security Best Practices ### API Key Management **GitHub:** ``` Settings → Secrets and variables → Actions Add: ANTHROPIC_API_KEY ``` **GitLab:** ``` Settings → CI/CD → Variables Add: ANTHROPIC_API_KEY (Protected, Masked) ``` ### Restricted Permissions **GitHub Actions:** ```yaml permissions: contents: read pull-requests: write issues: write ``` **GitLab CI:** ```yaml variables: GIT_STRATEGY: clone GIT_DEPTH: 1 ``` ### Secrets Scanning Prevent API key exposure: ```yaml - name: Scan for Secrets run: | if git diff | grep -i "ANTHROPIC_API_KEY"; then echo "API key detected in diff!" exit 1 fi ``` ## Monitoring & Debugging ### Workflow Logs **GitHub Actions:** ```yaml - name: Debug Info run: | echo "Workflow: ${{ github.workflow }}" echo "Event: ${{ github.event_name }}" echo "Ref: ${{ github.ref }}" ``` **GitLab CI:** ```yaml debug: script: - echo "Pipeline ID: $CI_PIPELINE_ID" - echo "Job ID: $CI_JOB_ID" - echo "Branch: $CI_COMMIT_BRANCH" ``` ### Artifacts Save Claude outputs: ```yaml # GitHub - name: Save Claude Output uses: actions/upload-artifact@v3 with: name: claude-results path: claude-output.md # GitLab artifacts: paths: - claude-output.md expire_in: 1 week ``` ### Error Handling ```yaml - name: Claude Task continue-on-error: true id: claude uses: anthropic/claude-code-action@v1 - name: Handle Failure if: steps.claude.outcome == 'failure' run: | echo "Claude task failed, continuing anyway" ``` ## Performance Optimization ### Caching **GitHub Actions:** ```yaml - uses: actions/cache@v3 with: path: ~/.claude/cache key: claude-cache-${{ hashFiles('package-lock.json') }} ``` **GitLab CI:** ```yaml cache: key: claude-cache paths: - .claude/cache ``` ### Parallel Execution ```yaml # GitHub - Matrix builds strategy: matrix: task: [lint, test, review] steps: - run: claude "/${{ matrix.task }}" # GitLab - Parallel jobs test: parallel: 3 script: - claude "/test --shard $CI_NODE_INDEX/$CI_NODE_TOTAL" ``` ## See Also - GitHub Actions docs: https://docs.github.com/actions - GitLab CI/CD docs: https://docs.gitlab.com/ee/ci/ - Claude Code Actions: https://github.com/anthropics/claude-code-action - Best practices: `references/best-practices.md`