Best Practices
CI/CD Pipeline
Pipeline depth — cancellation, required aggregator, matrix — the cal.diy pattern
Status (reconciled 2026-07-02)
Since the original analysis, KwadMarket's CI gained an e2e job and the stale /graphql env var was fixed. Still missing: cancel-in-progress and a required aggregator job. Making the pipeline green again is plan phase 0.
The cal.diy pattern
all-checks.yml is a fan-out orchestrator calling 9+ reusable workflow files:
check-types.yml — tsc --noEmit
lint.yml — biome + eslint
unit-tests.yml — vitest
api-v2-unit-tests.yml — NestJS unit tests
production-build-without-database.yml
integration-tests.yml — DB-backed (needs: lint, build)
e2e.yml — Playwright (needs: lint, build)
...Required aggregator job — blocks PR merge if any job was skipped or cancelled:
required:
if: always()
needs: [lint, type-check, unit-tests, e2e, integration-tests]
runs-on: ubuntu-latest
steps:
- name: Check all required jobs
run: |
results='${{ toJSON(needs) }}'
if echo "$results" | grep -q '"result": "failure"\|"result": "skipped"\|"result": "cancelled"'; then
echo "Required job failed, skipped, or was cancelled" && exit 1
fiConcurrency cancels stale runs:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: trueRemaining gaps in KwadMarket's ci.yml
| Gap | Impact | Fix |
|---|---|---|
No cancel-in-progress | Stale runs waste minutes on every push | 5-minute YAML addition (above) |
No required aggregator | A skipped job doesn't block merge | Aggregator job (above) with needs: [lint, test, build-backend, build-frontend, e2e] |
| Red since 2026-06-28 | Nothing is actually gated | Plan phase 0 — broken e2e selectors + test job |
| No Node matrix | Untested on Node 22 | Optional — add when upgrading Node |
Once green, consider the cal.diy fan-out structure (reusable workflow files) only if the single flat file becomes hard to maintain — it's fine at the current size.