Merge pull request #14 from jakesterns/feat-local-testing #24
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| jobs: | |
| # ── MVP release gate ───────────────────────────────────────────────────────── | |
| # | |
| # Single authoritative job: sets up Node + Python, then invokes the canonical | |
| # cross-platform release gate script exactly as a local developer would. | |
| # | |
| # Local: node scripts/release-gate.js (or make release-gate / pnpm run release:gate) | |
| # CI: node scripts/release-gate.js (same script, same steps, same exit codes) | |
| # | |
| # The script runs six steps sequentially and exits non-zero on the first | |
| # failure, matching local failure semantics exactly: | |
| # [1/6] pnpm install --frozen-lockfile | |
| # [2/6] pnpm run build | |
| # [3/6] pnpm run typecheck | |
| # [4/6] pnpm run coverage (web lines>=22%, node lines>=55% -- vitest thresholds) | |
| # [5/6] pip install (Python API dependencies) | |
| # [6/6] python -m pytest (API tests + >=64% -- pytest --cov-fail-under) | |
| # | |
| # Coverage artifacts are uploaded after the gate runs. The `if: always()` | |
| # flag on upload steps ensures artifacts are preserved even when the gate | |
| # fails part-way through (e.g. a coverage threshold miss still produces | |
| # the coverage report for inspection). | |
| # | |
| # Branch protection: require this job to pass before merging to main. | |
| release-gate: | |
| name: MVP release gate | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # ── Runtime setup ────────────────────────────────────────────────────── | |
| # Node + pnpm are required by the script for JS/TS steps [1–4]. | |
| # Python is required for API steps [5–6]. | |
| # Both must be available before the script runs. | |
| - name: Set up pnpm | |
| uses: pnpm/action-setup@v4 | |
| # version is read from packageManager field in package.json (pnpm@9.15.0) | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| # ── Canonical release gate ───────────────────────────────────────────── | |
| # This is the single source of truth. No inline gate logic in YAML. | |
| - name: Run release gate | |
| run: node scripts/release-gate.js | |
| # ── Wiring verification ──────────────────────────────────────────────── | |
| # Confirms that local developer entrypoints (make, pnpm) still delegate | |
| # to the same script CI just ran. Fails loudly if either drifts to an | |
| # inline command that could silently drop steps (e.g. omit the Python API). | |
| - name: Verify local entrypoint wiring | |
| run: | | |
| grep -q '"release:gate": "node scripts/release-gate.js"' package.json || \ | |
| (echo "ERROR: pnpm release:gate does not delegate to scripts/release-gate.js" && exit 1) | |
| grep -q 'node scripts/release-gate.js' Makefile || \ | |
| (echo "ERROR: make release-gate does not delegate to scripts/release-gate.js" && exit 1) | |
| echo "✓ pnpm release:gate -> scripts/release-gate.js" | |
| echo "✓ make release-gate -> scripts/release-gate.js" | |
| echo "All entrypoints unified. Repo is in MVP release-candidate shape." | |
| # ── Coverage artifacts ───────────────────────────────────────────────── | |
| # Generated by step [4/6] (pnpm run coverage) and [6/6] (python -m pytest). | |
| # Uploaded with if: always() so they are preserved for inspection even | |
| # when the gate fails — a threshold miss is most useful when you can see | |
| # the actual coverage numbers. | |
| - name: Upload web coverage | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: web-coverage | |
| path: apps/web/coverage/ | |
| if-no-files-found: warn | |
| - name: Upload node coverage | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: node-coverage | |
| path: apps/node/coverage/ | |
| if-no-files-found: warn | |
| - name: Upload API coverage | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: api-coverage | |
| path: apps/api/coverage.xml | |
| if-no-files-found: warn |