# .github/workflows/js-tests.yml name: JS Tests on: workflow_call: jobs: workspaces: name: List npm workspaces runs-on: ubuntu-latest timeout-minutes: 20 outputs: checks: ${{ steps.set-matrix.outputs.checks }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 cache: npm - uses: ./.github/actions/retry with: command: npm ci --ignore-scripts - id: set-matrix run: | 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: ${{ matrix.package }} / ${{ matrix.script }} needs: workspaces runs-on: ubuntu-latest timeout-minutes: 20 strategy: matrix: 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 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 cache: npm - uses: ./.github/actions/retry with: command: npm ci - run: npm run --prefix ${{ matrix.package }} ${{ matrix.script }}