iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Cheatsheet

A printable CI/CD cheatsheet covering pipeline stages, caching, secrets, environments, and the smallest YAML snippet for each. The one-pager you keep open during a CI rewrite.

CI/CD — printable cheatsheet

EXAMPLE
# ===== Stage map =====
# checkout -> install -> lint -> typecheck -> test -> build -> security-scan -> deploy

# ===== GitHub Actions skeleton =====
# .github/workflows/ci.yml
name: ci
on:
  push: { branches: [main] }
  pull_request:
concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: 'npm' }
      - run: npm ci
      - run: npm run lint
      - run: npm test -- --coverage
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with: { name: dist, path: dist/ }

# ===== Matrix builds =====
strategy:
  fail-fast: false
  matrix:
    node: [18, 20, 22]
    os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}

# ===== Caching =====
# Node modules: actions/setup-node cache:'npm' is usually enough
# Custom cache:
- uses: actions/cache@v4
  with:
    path: ~/.cache/foo
    key: foo-${{ hashFiles('**/lock.json') }}

# ===== Secrets =====
# Repo: Settings -> Secrets and variables -> Actions
# Use: ${{ secrets.DEPLOY_KEY }}
# Never echo secrets. Mask with ::add-mask:: if needed.

# ===== Environments + manual approval =====
jobs:
  deploy:
    needs: build
    environment:
      name: production
      url: https://example.com
    steps:
      - run: ./deploy.sh
# Configure 'production' env in Settings to require reviewers.

# ===== Conditional steps =====
- if: github.ref == 'refs/heads/main'
  run: ./deploy.sh
- if: failure()
  run: ./notify-slack.sh
- if: success() && github.event_name == 'pull_request'
  run: ./preview-deploy.sh

# ===== Reusable workflows =====
# .github/workflows/reusable-test.yml
on:
  workflow_call:
    inputs:
      node: { required: true, type: string }
jobs: { ... }

# Call from another workflow:
jobs:
  test:
    uses: ./.github/workflows/reusable-test.yml
    with: { node: '20' }

# ===== GitLab CI skeleton =====
stages: [build, test, deploy]
build:
  stage: build
  script:
    - npm ci
    - npm run build
  artifacts: { paths: [dist/] }
test:
  stage: test
  script: [npm test]
deploy:
  stage: deploy
  rules:
    - if: $CI_COMMIT_BRANCH == 'main'
  script: ./deploy.sh

# ===== Common patterns =====
# - Fail fast: lint + typecheck before test before build
# - Cache deps; never cache build outputs
# - Run tests in parallel via matrix or test sharding
# - Required status checks on main; merge queue for serialised landings
# - Promote artifacts between stages, never rebuild
# - One pipeline per repo by default; split only when stages diverge sharply

# ===== Pitfalls =====
# - Secrets in PRs from forks -> use pull_request_target carefully
# - 'latest' image tags -> non-reproducible builds; pin shas
# - Long-running pipelines -> measure + parallelise + cache
# - Manual deploys after PR merge -> bake into pipeline so reverts are easy
# - No environment promotion -> staging != prod, surprises follow

Why it matters

Pin this above the desk during a pipeline overhaul. The patterns repeat across every CI provider: cached deps, parallel matrix, conditional deploys with manual gates. The provider syntax changes, the shape does not.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
# checkout | setup-* | cache | upload-artifact | docker/build-push | environment | needs
Try it Yourself »

Discussion

Loading…