# .github/workflows/js-tests.yml name: JS Tests on: workflow_call: jobs: check: name: JS & TS checks # One 32-core job replaces a 14-leg matrix. The matrix spread about 612s # of check payload over 4-core runners. It paid about 371s of repeated # setup to do it: 14 checkouts, 14 node installs, 14 node_modules # restores. # # One larger runner installs one time. vitest, tsc and eslint each size # their own worker pool from the core count. runs-on: ubuntu-latest-32-core timeout-minutes: 30 steps: - uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7.0.1 - name: Set up the locked JS build toolchain id: node uses: ./.github/actions/setup-pm with: # Desktop checks also run Python payload and icon build helpers, and # the electron contracts drive real hermes_cli/pm code through # HERMES_PYTHON, which needs the application dependencies. toolchain: all extras: '[]' test-environment: 'true' - name: Install zsh and a virtual display for Electron if: runner.os == 'Linux' run: | sudo apt-get install -y zsh xvfb \ libgtk-3-0 libnotify4 libnss3 libxss1 libxtst6 \ xdg-utils libatspi2.0-0 libdrm2 libgbm1 libasound2t64 # setup-pm caches npm downloads, not the installed workspace tree. # The job then extracts the full workspace node_modules # again and runs the postinstalls again, which includes the Electron # binary fetch. This caches the installed tree itself, keyed on the # lockfile, and skips ``npm ci`` on an exact hit. There are no # restore-keys: a partial hit leaves a stale tree, so anything other # than an exact lockfile match reinstalls from the start. # # This install runs WITH scripts, so the tree holds the postinstall # artifacts. The postinstall of electron unpacks its binary into # node_modules/electron/dist, which is inside the cached tree. # # The ~/.cache/electron download cache stays out of the key on purpose. # ``npm ci`` is skipped on a hit, so nothing reads that cache. It only # makes the archive larger. - name: Restore node_modules id: node-modules-cache uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | node_modules apps/*/node_modules ui-tui/node_modules ui-tui/packages/*/node_modules tests-js/node_modules web/node_modules key: node-modules-scripts-${{ runner.os }}-${{ runner.arch }}-node${{ steps.node.outputs.node-version }}-npm${{ steps.node.outputs.npm-version }}-${{ hashFiles('package-lock.json') }} - uses: ./.github/actions/retry if: steps.node-modules-cache.outputs.cache-hit != 'true' with: command: npm ci # Every check runs at the same time. The step fails only after all of # them finish. There are two reasons this is not ``npm run --ws check``. # # * ``--ws`` is serial and stops at the first workspace that fails. A # run then reports one failure, where the matrix this replaced # reported every failure together. # * The unit of work is a CHECK, and not a workspace. apps/desktop is # most of the payload, and its own ``check`` is a serial && chain. # A spread across workspaces alone leaves that chain as the long # pole. This expands the ``check:*`` sub-scripts of a package, so # its lint, ui, electron and plugin suites all run together. That # is the same selection rule the old matrix job used. # # Discovery is ``npm query .workspace``. A new package or a new # ``check:*`` script needs no change here. An empty list is an error and # not an empty run, because an empty run reports green after it checks # nothing. - name: Run all workspace checks run: node .github/scripts/run-workspace-checks.mjs