do-ci-pipeline
When to use
You need to build a CI/CD pipeline from scratch, diagnose a slow or flaky one, or add gates before a risky change ships. Works for GitHub Actions, GitLab CI, CircleCI, Jenkins, or Buildkite.
Not for: application code changes, local build scripts, one-off deploy commands, or infra provisioning (use do-terraform), container image authoring (use do-dockerfile), or the release runbook itself (use do-release-checklist).
Method
- Map the delivery graph: list triggers (push, PR, tag, schedule), what must pass before merge, and what promotes to each environment.
- Split work into ordered stages — lint/typecheck, unit test, build, integration test, package, deploy. Decision: if two stages share no inputs, run them in parallel to cut wall-clock time; if one consumes another's output, chain them.
- Add caching keyed on lockfile hashes (deps, build layers, fixtures) with a documented cache-bust path. Decision: cache only deterministic, non-secret, non-environment-specific output — never credentials or per-env config.
- Define gates: required status checks, coverage threshold, security scan (SAST + dependency audit), and manual approval before prod. Decision: block merge on gates that protect correctness; warn-only on advisory ones.
- Build the artifact once, version it immutably, and promote the same artifact across environments. Decision: never rebuild per stage — rebuilding breaks the "tested == shipped" guarantee.
- Instrument the pipeline: surface duration, flake rate, and failure cause; fail fast and report clearly.
Example
# .github/workflows/ci.yml (excerpt)
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm } # key: package-lock.json
- run: npm ci
- run: npm test -- --coverage
build:
needs: test # gate: tests must pass first
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- uses: actions/upload-artifact@v4 # build once, promote later
with: { name: dist, path: dist/ }
Pitfalls
- Rebuilding the artifact in the deploy stage — you then ship something CI never tested.
- Caching on a branch name or timestamp instead of a lockfile hash, so the cache never invalidates correctly (stale deps) or never hits (slow).
- Treating flaky tests as "retry until green" — retries hide real races and erode trust in the gate.
- Baking secrets into cached layers or logs; anything cached or echoed is effectively public.
Output format
Pipeline: <platform> config file (valid syntax)
Stage table:
| stage | depends-on | cache key | gate | artifact |
|-------|-----------|-----------|------|----------|
Top 3 risks:
1. <flake source> -> mitigation
2. <cache staleness> -> mitigation
3. <secret exposure> -> mitigation
1---2name: do-ci-pipeline3description: Design or repair a CI/CD pipeline with well-ordered parallel stages, lockfile-keyed caching, quality gates, and build-once artifact promotion.4---56# do-ci-pipeline78## When to use910You need to build a CI/CD pipeline from scratch, diagnose a slow or flaky one, or add gates before a risky change ships. Works for GitHub Actions, GitLab CI, CircleCI, Jenkins, or Buildkite.1112**Not for:** application code changes, local build scripts, one-off deploy commands, or infra provisioning (use do-terraform), container image authoring (use do-dockerfile), or the release runbook itself (use do-release-checklist).1314## Method15161. Map the delivery graph: list triggers (push, PR, tag, schedule), what must pass before merge, and what promotes to each environment.172. Split work into ordered stages — lint/typecheck, unit test, build, integration test, package, deploy. Decision: if two stages share no inputs, run them in parallel to cut wall-clock time; if one consumes another's output, chain them.183. Add caching keyed on lockfile hashes (deps, build layers, fixtures) with a documented cache-bust path. Decision: cache only deterministic, non-secret, non-environment-specific output — never credentials or per-env config.194. Define gates: required status checks, coverage threshold, security scan (SAST + dependency audit), and manual approval before prod. Decision: block merge on gates that protect correctness; warn-only on advisory ones.205. Build the artifact once, version it immutably, and promote the same artifact across environments. Decision: never rebuild per stage — rebuilding breaks the "tested == shipped" guarantee.216. Instrument the pipeline: surface duration, flake rate, and failure cause; fail fast and report clearly.2223## Example2425```yaml26# .github/workflows/ci.yml (excerpt)27jobs:28 test:29 runs-on: ubuntu-latest30 steps:31 - uses: actions/checkout@v432 - uses: actions/setup-node@v433 with: { node-version: 20, cache: npm } # key: package-lock.json34 - run: npm ci35 - run: npm test -- --coverage36 build:37 needs: test # gate: tests must pass first38 runs-on: ubuntu-latest39 steps:40 - uses: actions/checkout@v441 - run: npm ci && npm run build42 - uses: actions/upload-artifact@v4 # build once, promote later43 with: { name: dist, path: dist/ }44```4546## Pitfalls4748- Rebuilding the artifact in the deploy stage — you then ship something CI never tested.49- Caching on a branch name or timestamp instead of a lockfile hash, so the cache never invalidates correctly (stale deps) or never hits (slow).50- Treating flaky tests as "retry until green" — retries hide real races and erode trust in the gate.51- Baking secrets into cached layers or logs; anything cached or echoed is effectively public.5253## Output format5455```56Pipeline: <platform> config file (valid syntax)5758Stage table:59| stage | depends-on | cache key | gate | artifact |60|-------|-----------|-----------|------|----------|6162Top 3 risks:631. <flake source> -> mitigation642. <cache staleness> -> mitigation653. <secret exposure> -> mitigation66```