ci(sonar): fold the four coverage jobs into one, on the root scripts (#2039)

Review feedback on #2038: the root already has a script that does all of this,
so the five jobs and the artifact shuffling between them were doing by hand what
`npm run test:cov` does on its own. It ends with `--prefix plugin-sdk`, so all
four packages are covered, and each writes its lcov to <pkg>/coverage/ — exactly
where sonar.javascript.lcov.reportPaths looks. 131 lines become 28.

Three things the plain root sequence still needs on a runner, kept as their own
steps so the reason stays visible:
- plugin-sdk is not a root workspace (workspaces = client, server, shared), so
  the root npm ci never reaches it and it needs its own.
- The lockfile was generated on Windows and omits @swc/core's Linux optional
  binary, so the server's SWC transform cannot load. test.yml carries the same
  step for the same reason.
- Only shared is built, not the root `build`. server and client run their suites
  from source through vitest, so building them adds a tsc pass and a full vite
  bundle that nothing here reads.

The cost is wall-clock. The first run of the parallel version took 16 minutes,
with client (11) and server (9) overlapping; sequentially that is closer to 25.
Nobody waits on this job, so the simpler file is the better trade — but it is a
trade, not a free win.
This commit is contained in:
Maurice
2026-08-25 16:34:08 +02:00
committed by GitHub
parent 616b39a9f0
commit 6fe5009c20
+37 -112
View File
@@ -16,103 +16,9 @@ on:
workflow_dispatch:
jobs:
# The four suites mirror the jobs in test.yml — same setup, same
# `test:coverage` scripts — because Sonar needs the lcov each package emits.
# Without them every line reports as uncovered and the dashboard shows a
# collapse that did not happen. They run in parallel and hand their reports to
# the scan job as artifacts.
shared-coverage:
name: Coverage (shared)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24
cache: npm
cache-dependency-path: package-lock.json
- run: npm ci --workspace shared
- run: cd shared && npm run test:coverage
- uses: actions/upload-artifact@v6
with:
name: sonar-shared-coverage
path: shared/coverage/
retention-days: 1
plugin-sdk-coverage:
name: Coverage (plugin-sdk)
runs-on: ubuntu-latest
defaults:
run:
working-directory: plugin-sdk
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
cache-dependency-path: plugin-sdk/package-lock.json
- run: npm ci
- run: npm run test:coverage
- uses: actions/upload-artifact@v6
with:
name: sonar-plugin-sdk-coverage
path: plugin-sdk/coverage/
retention-days: 1
server-coverage:
name: Coverage (server)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24
cache: npm
cache-dependency-path: package-lock.json
- run: npm ci
- name: Ensure @swc/core's Linux binary for unplugin-swc
# Same reason as test.yml: the lockfile was generated on Windows and
# omits the Linux optional native binary, so the server's SWC transform
# cannot load without this.
run: |
SWC_VERSION=$(node -p "require('@swc/core/package.json').version")
npm install --no-save --legacy-peer-deps "@swc/core-linux-x64-gnu@$SWC_VERSION"
- name: Build shared
run: npm run build --workspace=shared
- run: cd server && npm run test:coverage
- uses: actions/upload-artifact@v6
with:
name: sonar-server-coverage
path: server/coverage/
retention-days: 1
client-coverage:
name: Coverage (client)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24
cache: npm
cache-dependency-path: package-lock.json
- run: npm ci --workspace shared && npm ci --workspace client
- name: Build shared
run: npm run build --workspace=shared
- run: cd client && npm run test:coverage
- uses: actions/upload-artifact@v6
with:
name: sonar-client-coverage
path: client/coverage/
retention-days: 1
scan:
name: SonarQube Scan
name: Coverage & Scan
runs-on: ubuntu-latest
needs: [shared-coverage, plugin-sdk-coverage, server-coverage, client-coverage]
steps:
- uses: actions/checkout@v6
with:
@@ -120,24 +26,43 @@ jobs:
# new code. A shallow clone leaves it blind to both.
fetch-depth: 0
# Restored to the exact paths sonar-project.properties names in
# sonar.javascript.lcov.reportPaths.
- uses: actions/download-artifact@v6
- uses: actions/setup-node@v6
with:
name: sonar-shared-coverage
path: shared/coverage/
- uses: actions/download-artifact@v6
with:
name: sonar-plugin-sdk-coverage
path: plugin-sdk/coverage/
- uses: actions/download-artifact@v6
with:
name: sonar-server-coverage
path: server/coverage/
- uses: actions/download-artifact@v6
with:
name: sonar-client-coverage
path: client/coverage/
node-version: 24
cache: npm
cache-dependency-path: package-lock.json
- name: Install dependencies
run: npm ci
- name: Install plugin-sdk dependencies
# plugin-sdk is not a root workspace (workspaces = client, server, shared)
# — it ships as its own npm package with its own lockfile, so the root
# npm ci does not reach it. Its coverage is part of test:cov all the same.
run: cd plugin-sdk && npm ci
- name: Ensure @swc/core's Linux binary for unplugin-swc
# Same reason as test.yml: the lockfile was generated on Windows and omits
# @swc/core's Linux optional native binary, so npm ci skips it on the
# runner and the server's SWC transform cannot load.
run: |
SWC_VERSION=$(node -p "require('@swc/core/package.json').version")
npm install --no-save --legacy-peer-deps "@swc/core-linux-x64-gnu@$SWC_VERSION"
- name: Build shared
# Only shared, not the root `build`. server and client run their suites
# from source through vitest, so building them would add a tsc pass and a
# full vite bundle that nothing here reads.
run: npm run build --workspace=shared
- name: Run tests with coverage
# One script for all four packages — it already ends with
# `--prefix plugin-sdk`. Each writes lcov to <pkg>/coverage/, which is
# where sonar.javascript.lcov.reportPaths looks. Without those files every
# line reports as uncovered and the dashboard shows a collapse that did
# not happen, so this step failing has to stop the scan rather than let it
# publish a false number.
run: npm run test:cov
- name: Scan
uses: SonarSource/sonarqube-scan-action@v8