From ci-cd
Use when setting up, debugging, or optimizing GitHub Actions CI/CD workflows. Covers workflow syntax, caching strategies, matrix builds, secrets management, release automation, and diagnosing failing checks.
npx claudepluginhub sagargupta16/claude-skills --plugin ci-cdThis skill uses the workspace's default tool permissions.
| Task | Approach |
Creates isolated Git worktrees for feature branches with prioritized directory selection, gitignore safety checks, auto project setup for Node/Python/Rust/Go, and baseline verification.
Executes implementation plans in current session by dispatching fresh subagents per independent task, with two-stage reviews: spec compliance then code quality.
Dispatches parallel agents to independently tackle 2+ tasks like separate test failures or subsystems without shared state or dependencies.
| Task | Approach |
|---|---|
| New workflow | Choose template below by project type |
| CI failing | Check logs -> match common failure patterns below |
| Slow builds | Add caching, use matrix for parallelism |
| Release | Tag-triggered workflow with changelog |
| Secrets | Repository secrets + environment protection rules |
| Reusable logic | Composite actions or reusable workflows |
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup runtime
# Language-specific setup
- name: Install dependencies
# Package manager install
- name: Lint
# Linter run
- name: Test
# Test suite
- name: Build
# Build step (if applicable)
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22 # Check https://nodejs.org for current LTS
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm lint
- run: pnpm test
- run: pnpm build
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- uses: actions/setup-python@v5
with:
python-version: "3.13" # Check https://python.org for current stable
- run: uv sync
- run: uv run ruff check .
- run: uv run pytest
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.13" # Check https://python.org for current stable
cache: pip
- run: pip install -r requirements.txt
- run: ruff check .
- run: pytest
jobs:
docker:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
push: ${{ github.event_name != 'pull_request' }}
tags: ghcr.io/${{ github.repository }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max
| Package Manager | Cache Key |
|---|---|
| pnpm | pnpm/action-setup + setup-node with cache: pnpm |
| npm | setup-node with cache: npm |
| pip | setup-python with cache: pip |
| uv | setup-uv handles caching automatically |
| cargo | actions/cache with target/ and Cargo.lock hash |
| go | setup-go with cache: true |
| Docker | cache-from: type=gha in build-push-action |
Custom cache example:
- uses: actions/cache@v4
with:
path: ~/.cache/custom
key: ${{ runner.os }}-custom-${{ hashFiles('**/lockfile') }}
restore-keys: ${{ runner.os }}-custom-
jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node-version: [20, 22]
exclude:
- os: windows-latest
node-version: 20
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
Use fail-fast: false to see all failures, not just the first.
# Use repository or environment secrets - never hardcode
env:
API_KEY: ${{ secrets.API_KEY }}
# Protect production deployments with environments
jobs:
deploy:
environment: production # Requires approval
steps:
- run: deploy --token ${{ secrets.DEPLOY_TOKEN }}
Rules:
environment protection for production deploymentsGITHUB_TOKEN for GitHub API calls (auto-provided)name: Release
on:
push:
tags: ["v*"]
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
run: gh release create ${{ github.ref_name }} --generate-notes
| Symptom | Likely Cause | Fix |
|---|---|---|
| "Permission denied" | Missing permissions block | Add required permissions to job |
| "Resource not accessible" | GITHUB_TOKEN scope too narrow | Add permissions: contents: write etc. |
| "Cache not found" | Changed lockfile or wrong cache key | Check hashFiles() pattern matches lockfile |
| "Out of disk space" | Large build artifacts or Docker layers | Add cleanup step or use larger runner |
| Flaky tests (pass/fail randomly) | Race conditions or timing deps | Add retries or fix test isolation |
| "Node.js version not found" | Version string format | Use quotes: node-version: "22" |
| Different behavior on PR vs push | Different trigger contexts | Check github.event_name conditions |
ACTIONS_STEP_DEBUG secret set to true for verbose logging# .github/workflows/reusable-test.yml
on:
workflow_call:
inputs:
node-version:
type: string
default: "22"
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- run: npm ci && npm test
# .github/workflows/ci.yml
jobs:
test:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: "22"
| Don't | Do Instead |
|---|---|
Use actions/checkout@v2 | Use @v4 (latest major) |
npm install in CI | npm ci (clean install from lockfile) |
Skip permissions block | Always declare minimum required permissions |
Cache node_modules/ directly | Let setup-node cache the package manager store |
| Run deploys on every push | Use tag triggers or environment protection |
Use continue-on-error: true to hide failures | Fix the underlying issue |
| Duplicate steps across workflows | Extract to reusable workflow or composite action |