ci: run the coverage gate in a parallel job (#2159)
`build` ran `npm run validate` and `npm run coverage` back to back, and on a recent green run those two steps were 84% of a 17m9s wall clock (7m41 + 6m50). They are serial for no reason: `coverage` consumes nothing `validate` produces. Every client's `test:coverage` is self-sufficient — web and cli build the test servers themselves (cli its own bin too), tui and launcher run from source — and the only consumers of `clients/*/build` are the smokes, which stay in `build` alongside the `validate` that produces them. So split `coverage` into a sibling job. Both publish jobs become `needs: [build, coverage]`: that is the safety property, not a side effect — left as `needs: build` a release could publish with the coverage gate red. Deliberately NOT backgrounding the two inside one job: that puts two vitest fleets on one 4-core runner, which already times tests out at the 5s default. Wall clock ~17m -> ~10m, for one extra runner and a duplicated ~24s install. Splitting `coverage` per client is the next lever and stays out of scope. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0177mPHAdECD18nLLCTwR5rh Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
6c9c149406
commit
9cd06598a4
1 changed files with 53 additions and 22 deletions
71
.github/workflows/main.yml
vendored
71
.github/workflows/main.yml
vendored
|
|
@ -43,27 +43,15 @@ jobs:
|
|||
# self-validation: format:check + lint + typecheck + build + test (no
|
||||
# coverage instrumentation — fast). This also builds every client bundle
|
||||
# (web dist, cli/tui/launcher) that the smokes below need. The heavier
|
||||
# per-file coverage gate runs in its own step below. Unit tests run in
|
||||
# both steps (fast here, instrumented under coverage); the double unit
|
||||
# run is an accepted trade-off for keeping this fast build step intact.
|
||||
# A future optimization could split coverage into per-client parallel
|
||||
# per-file coverage gate runs in the parallel `coverage` job below
|
||||
# (#2159), which consumes nothing this job produces — every client's
|
||||
# `test:coverage` builds whatever it needs itself. Unit tests run in
|
||||
# both jobs (fast here, instrumented there); now that the two run in
|
||||
# parallel that duplication costs no wall clock at all.
|
||||
# A future optimization could split `coverage` into per-client parallel
|
||||
# jobs, but that's a larger restructure and deliberately out of scope.
|
||||
run: npm run validate
|
||||
|
||||
- name: Enforce per-file coverage gate (≥90% on all four dimensions)
|
||||
# CI-ENFORCED coverage gate (#1550): runs `npm run coverage`, which
|
||||
# chains every client's `test:coverage` (v8-instrumented) and fails the
|
||||
# job if ANY file drops below 90% on lines, statements, functions, or
|
||||
# branches. This is the whole point of the step — a PR that regresses
|
||||
# coverage below the threshold now blocks merge instead of relying on a
|
||||
# contributor remembering to run the gate locally.
|
||||
#
|
||||
# This also covers the web integration project: web's `test:coverage`
|
||||
# runs `--project=unit --project=integration --coverage`, so the former
|
||||
# standalone `Run web integration tests` step was removed to avoid
|
||||
# running the integration suite twice.
|
||||
run: npm run coverage
|
||||
|
||||
- name: Verify the browser-externalized-builtin build gate (#1769)
|
||||
# Runs a real `vite build` with a Node built-in forced into the browser
|
||||
# graph and asserts the build FAILS via the #1769 gate. The unit tests
|
||||
|
|
@ -115,6 +103,49 @@ jobs:
|
|||
working-directory: ./clients/web
|
||||
run: npm run test:storybook
|
||||
|
||||
# The per-file coverage gate, in its own job so it runs in PARALLEL with
|
||||
# `build` rather than serially after it (#2159). The two together were 84% of
|
||||
# a ~17m wall clock; split, the workflow finishes in roughly the length of
|
||||
# `build` alone.
|
||||
#
|
||||
# This is safe because `coverage` consumes nothing `build` produces: every
|
||||
# client's `test:coverage` is self-sufficient (web and cli build the test
|
||||
# servers — and cli its own bin — themselves; tui and launcher run from
|
||||
# source). The only consumers of `clients/*/build` are the smokes, which stay
|
||||
# in `build` alongside the `validate` that produces them.
|
||||
#
|
||||
# Do NOT "optimize" this back into one job by backgrounding the two commands:
|
||||
# that puts two vitest fleets on one 4-core runner, which is already known to
|
||||
# time tests out at the 5s default. Separate jobs get separate runners.
|
||||
coverage:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: '22.x'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies (root + all clients)
|
||||
run: npm install
|
||||
|
||||
- name: Enforce per-file coverage gate (≥90% on all four dimensions)
|
||||
# CI-ENFORCED coverage gate (#1550): runs `npm run coverage`, which
|
||||
# chains every client's `test:coverage` (v8-instrumented) and fails the
|
||||
# job if ANY file drops below 90% on lines, statements, functions, or
|
||||
# branches. This is the whole point of the job — a PR that regresses
|
||||
# coverage below the threshold blocks merge instead of relying on a
|
||||
# contributor remembering to run the gate locally.
|
||||
#
|
||||
# This also covers the web integration project: web's `test:coverage`
|
||||
# runs `--project=unit --project=integration --coverage`, so there is no
|
||||
# separate integration step anywhere in this workflow.
|
||||
run: npm run coverage
|
||||
|
||||
# Publish the single `@modelcontextprotocol/inspector` package to npm on a
|
||||
# published GitHub release. v2 is not an npm workspace, so there is no
|
||||
# `publish-all` / `--workspaces` (v1) — just one `npm publish`, whose `prepack`
|
||||
|
|
@ -127,7 +158,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'release'
|
||||
environment: release
|
||||
needs: build
|
||||
needs: [build, coverage]
|
||||
# Serialize publishes so two releases cut in quick succession can't run
|
||||
# overlapping `npm publish`es. Never cancel an in-flight publish.
|
||||
concurrency:
|
||||
|
|
@ -220,7 +251,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'release'
|
||||
environment: release
|
||||
needs: build
|
||||
needs: [build, coverage]
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
|
|
|||
Loading…
Reference in a new issue