← Workflows

阅读中文版本

Set Up CI/CD with GitHub Actions

Configure a continuous integration pipeline with GitHub Actions that runs linting, tests, and builds on every pull request, preventing broken code from merging into main.

beginner~25 mincigithub-actionstestingautomation

Objective

Create a GitHub Actions workflow that lints, type-checks, and tests the codebase on every push and pull request, blocking merges when checks fail.

Environment

  • GitHub repository with Actions enabled
  • Node.js 20+ project with pnpm
  • package.json with scripts: lint, test, build

Steps

1. Create workflow directory

Create .github/workflows/ directory in your repository root

Expected state: Directory .github/workflows/ exists (create with mkdir -p if needed)

2. Write CI workflow YAML

Create .github/workflows/ci.yml with configuration for Node.js setup, dependency installation, and test execution

Expected state: File .github/workflows/ci.yml contains valid YAML with push/PR triggers, Node 20 matrix, and lint/test/build steps

3. Configure branch protection rules

In GitHub repository settings → Branches → Add rule for 'main', enable 'Require status checks to pass' and select the CI workflow

Expected state: Branch protection rule active: PRs cannot merge until CI passes

4. Test the workflow

Push a commit that breaks a test to verify the workflow catches it

Expected state: GitHub Actions shows red X on the commit; PR cannot be merged

5. Test the passing case

Push a valid commit and verify all checks pass

Expected state: GitHub Actions shows green checkmark; PR merge is allowed

Decision points

Should tests run in parallel or sequential?

  • Parallel (faster feedback)
  • Sequential (lower resource usage)

Parallel — use a matrix strategy to run lint, test, and build in separate jobs for faster CI cycles.

Should the workflow use pnpm or npm?

  • pnpm (faster, deterministic)
  • npm (built-in, no setup)

Use pnpm if the project uses it. Add 'pnpm-action/setup' step. Otherwise default to npm ci.

Expected outcome

Every PR triggers lint + typecheck + test. Broken code is blocked from merging. Main branch stays green.

Verification

Open a PR with an intentional lint error. Verify GitHub Actions shows failure and the merge button is greyed out.

Cleanup

Remove the test branch. The CI workflow stays in place for all future PRs.

Why Use GitHub Actions for CI

CI (Continuous Integration) ensures every code change passes quality checks before merging. GitHub Actions runs workflows directly in your repository, free for public repos with generous limits for private ones.

The Workflow File

Create .github/workflows/ci.yml:

name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with:
          version: 9
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile
      - run: pnpm lint

  typecheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with:
          version: 9
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile
      - run: pnpm exec tsc --noEmit

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with:
          version: 9
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile
      - run: pnpm test -- --run

  build:
    runs-on: ubuntu-latest
    needs: [lint, typecheck, test]
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with:
          version: 9
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile
      - run: pnpm build

Key Concepts

Caching for Speed

The cache: 'pnpm' key tells setup-node to cache the ~/.pnpm-store directory between runs. First run: ~60s. Subsequent runs: ~10s.

Job Dependencies with needs

build:
  needs: [lint, typecheck, test]  # build only runs if all 3 pass

If lint or test fails, build is skipped. This saves minutes of compute.

Matrix Strategy for Multiple Node Versions

strategy:
  matrix:
    node-version: [18, 20, 22]

Runs the same job against each Node version in parallel.

Branch Protection Setup

  1. Go to: Repository → Settings → Branches → Add rule
  2. Branch name pattern: main
  3. Check “Require status checks to pass before merging”
  4. Search and select: lint, typecheck, test, build
  5. Save changes

Debugging Failed Workflows

  • Click the failed job in the Actions tab to see the step-by-step log
  • Use continue-on-error: true on non-critical steps during debugging
  • Add ACTIONS_STEP_DEBUG: true as a repository secret for verbose logs

Security Best Practices

  • Never use ${{ secrets.* }} in echo statements (can leak via logs)
  • Pin action versions to SHA commit hashes for supply chain security
  • Use pull_request_target instead of pull_request only if absolutely necessary (security risk)