From 5be99b6fce16e7d5304196bc9faf3f0cdfc3031f Mon Sep 17 00:00:00 2001 From: ethernet Date: Thu, 23 Jul 2026 18:45:16 -0400 Subject: [PATCH] ci(js-tests): split check into parallel matrix shards per workspace (#70252) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every npm workspace package now defines check:* scripts (check:unit, check:lint, check:bundle, check:typecheck, etc.) that fan out to separate matrix runners in CI. The check umbrella script chains all shards for local dev. The matrix discovery in the workspaces job queries npm workspaces, finds check:* scripts (in package.json insertion order), falls back to check when none exist, and emits an include matrix. No hardcoded package names — the workflow is fully auto-derived from workspace metadata. Previously every package ran a single check script on one worker, and the fix step (lint:fix + prettier) ran as a separate CI step with special-cased run_fix gating to avoid running on every shard. Now that lint is just another check:lint shard, the run_fix field and the fix step are gone entirely — lint runs in its own runner like everything else. --- .github/workflows/js-tests.yml | 40 +++++++++++++++++++-------- apps/bootstrap-installer/package.json | 2 +- apps/desktop/package.json | 6 +++- apps/shared/package.json | 2 +- tests-js/package.json | 2 +- ui-tui/package.json | 2 +- web/package.json | 2 +- 7 files changed, 39 insertions(+), 17 deletions(-) diff --git a/.github/workflows/js-tests.yml b/.github/workflows/js-tests.yml index 4e4622f72d04..25786b1c95b6 100644 --- a/.github/workflows/js-tests.yml +++ b/.github/workflows/js-tests.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 20 outputs: - packages: ${{ steps.set-matrix.outputs.packages }} + checks: ${{ steps.set-matrix.outputs.checks }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 @@ -22,21 +22,40 @@ jobs: command: npm ci --ignore-scripts - id: set-matrix run: | - PACKAGES=$(npm query .workspace | jq -c '[.[].location]') - if [ "$PACKAGES" = "[]" ] || [ -z "$PACKAGES" ]; then - echo "::error::Workspace discovery produced an empty package list — refusing to emit a zero-length matrix (would skip all JS/TS checks silently)." - exit 1 - fi - echo "packages=$PACKAGES" >> "$GITHUB_OUTPUT" + node -e ' + const { execSync } = require("child_process"); + const pkgs = JSON.parse(execSync("npm query .workspace", { encoding: "utf-8" })); + if (pkgs.length === 0) { + console.error("::error::Workspace discovery produced an empty package list — refusing to emit a zero-length matrix (would skip all JS/TS checks silently)."); + process.exit(1); + } + const checks = []; + for (const pkg of pkgs) { + const scripts = pkg.scripts || {}; + const subs = Object.keys(scripts).filter(s => /^check:.+$/.test(s)); + if (subs.length > 0) { + for (const script of subs) { + checks.push({ package: pkg.location, script }); + } + } else if (scripts.check) { + checks.push({ package: pkg.location, script: "check" }); + } + } + if (checks.length === 0) { + console.error("::error::No check scripts found in any workspace package."); + process.exit(1); + } + process.stdout.write("checks=" + JSON.stringify(checks) + "\n"); + ' >> "$GITHUB_OUTPUT" check: - name: Typecheck & Test + name: ${{ matrix.package }} / ${{ matrix.script }} needs: workspaces runs-on: ubuntu-latest timeout-minutes: 20 strategy: matrix: - package: ${{ fromJson(needs.workspaces.outputs.packages) }} + include: ${{ fromJson(needs.workspaces.outputs.checks) }} fail-fast: false # report all failures, not just the first one steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -47,5 +66,4 @@ jobs: - uses: ./.github/actions/retry with: command: npm ci - - run: npm run --prefix ${{ matrix.package }} check - - run: npm run --prefix ${{ matrix.package }} fix + - run: npm run --prefix ${{ matrix.package }} ${{ matrix.script }} diff --git a/apps/bootstrap-installer/package.json b/apps/bootstrap-installer/package.json index ba231432350b..32c3e7f8c3e7 100644 --- a/apps/bootstrap-installer/package.json +++ b/apps/bootstrap-installer/package.json @@ -13,7 +13,7 @@ "tauri:build": "tauri build", "tauri:build:debug": "tauri build --debug", "typecheck": "tsc -p . --noEmit", - "check": "npm run typecheck", + "check": "npm run typecheck && npm run lint", "lint": "eslint src/", "lint:fix": "eslint src/ --fix", "fix": "npm run lint:fix" diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 643126546507..e40be3df8181 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -54,7 +54,11 @@ "test:desktop:platforms": "vitest run --project electron", "test": "vitest run", "preview": "node scripts/assert-root-install.mjs && vite preview --host 127.0.0.1 --port 4174", - "check": "npm run typecheck && npm run test && npm run test:desktop:all", + "check:test:desktop:platforms": "npm run test:desktop:platforms", + "check:test:ui": "npm run test:ui", + "check:test:desktop:all": "npm run test:desktop:all", + "check:lint": "npm run typecheck && npm run lint", + "check": "npm run check:lint && npm run check:test:ui && npm run test:desktop:platforms && npm run test:desktop:all", "test:e2e": "npm run build && playwright test e2e/", "test:e2e:visual": "npm run build && WLR_BACKENDS=headless WLR_NO_HARDWARE_CURSORS=1 cage -- npx playwright test e2e/ --reporter=list", "test:e2e:update-snapshots": "npm run build && WLR_BACKENDS=headless WLR_NO_HARDWARE_CURSORS=1 cage -- npx playwright test e2e/ --reporter=list --update-snapshots" diff --git a/apps/shared/package.json b/apps/shared/package.json index beb2340f4f75..2a2f46ef73d5 100644 --- a/apps/shared/package.json +++ b/apps/shared/package.json @@ -16,7 +16,7 @@ "lint:fix": "eslint src/ --fix", "fix": "npm run lint:fix", "typecheck": "tsc -p . --noEmit", - "check": "npm run typecheck" + "check": "npm run typecheck && npm run lint" }, "devDependencies": { "@eslint/js": "^9.39.4", diff --git a/tests-js/package.json b/tests-js/package.json index bc125f319808..908eeff0df4e 100644 --- a/tests-js/package.json +++ b/tests-js/package.json @@ -5,7 +5,7 @@ "scripts": { "typecheck": "tsc --noEmit -p tsconfig.json", "test": "vitest run", - "check": "npm run typecheck && npm run test", + "check": "npm run typecheck && npm run test && npm run lint", "lint": "eslint .", "lint:fix": "eslint . --fix", "fix": "npm run lint:fix" diff --git a/ui-tui/package.json b/ui-tui/package.json index 3dbcb758d2cc..581d6014220b 100644 --- a/ui-tui/package.json +++ b/ui-tui/package.json @@ -14,7 +14,7 @@ "lint:fix": "eslint src/ packages/ --fix", "fmt": "prettier --write 'src/**/*.{ts,tsx}' 'packages/**/*.{ts,tsx}'", "fix": "npm run lint:fix && npm run fmt", - "check": "npm run build:ink && npm run typecheck && npm run test", + "check": "npm run build:ink && npm run typecheck && npm run test && npm run lint", "test": "vitest run", "test:watch": "vitest" }, diff --git a/web/package.json b/web/package.json index 43ac160fe1d9..fca8c393399c 100644 --- a/web/package.json +++ b/web/package.json @@ -12,7 +12,7 @@ "preview": "vite preview", "typecheck": "tsc -p . --noEmit", "test": "vitest run", - "check": "npm run typecheck && npm run test" + "check": "npm run typecheck && npm run test && npm run lint" }, "dependencies": { "@hermes/shared": "file:../apps/shared",