Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 45 additions & 19 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,40 @@ jobs:
- uses: pnpm/action-setup@v6
with:
version: 11.5.2
# Self-hosted runners share one $HOME, so the default install path
# (~/setup-pnpm/node_modules) is shared by every job on the box. Two
# jobs from different refs starting together race on it and leave it
# half-removed, after which every later job fails at setup — first as
# `ENOTEMPTY ... rmdir`, then permanently as `self-installer exits
# with code 254`, before a single test runs.
# Self-hosted runners share one $HOME, and the action clears its
# install dir before writing to it. With the default ~/setup-pnpm that
# `rmdir` is shared by every job on the box, so two jobs from
# different refs starting together race and leave it half-removed —
# `ENOTEMPTY ... rmdir .../store/v11/files/03` — after which later
# jobs fail at setup or, once store files are gone, at `pnpm install`
# with ERR_PNPM_ENOENT. All of it before a single test runs.
#
# `standalone` fetches a self-contained pnpm binary instead, skipping
# the node_modules layout that races. See #125.
# The workflow's concurrency group is keyed on github.ref, so it
# serialises one branch and does nothing across branches — exactly the
# case that collides.
#
# runner.temp is per-job and cleaned up by the runner, so there is no
# shared directory left to race on. `standalone` additionally avoids
# building the node_modules layout. See #125.
dest: ${{ runner.temp }}/setup-pnpm
standalone: true

# No `cache: pnpm` on purpose. The runner is self-hosted, so the pnpm
# store already persists in $HOME between jobs — actions/cache would
# store already persists in $HOME between jobs (see --store-dir below) — actions/cache would
# round-trip a tarball over the network for zero benefit. Measured cost
# when it was enabled: up to 79s in the post-job cache save, longer than
# the test step it was meant to speed up.
- uses: actions/setup-node@v7
with:
node-version: 24

- run: pnpm install --frozen-lockfile
# --store-dir keeps the package cache on a stable path. The install dir
# above is per-job and disposable; the store must not be, or every job
# re-downloads ~1100 packages. A shared content-addressed store is
# pnpm's normal mode and is safe for concurrent readers — it was only
# fragile here because it happened to sit inside the directory the
# action clears.
- run: pnpm install --frozen-lockfile --store-dir ~/.pnpm-store

- run: pnpm typecheck

Expand Down Expand Up @@ -79,23 +92,36 @@ jobs:
- uses: pnpm/action-setup@v6
with:
version: 11.5.2
# Self-hosted runners share one $HOME, so the default install path
# (~/setup-pnpm/node_modules) is shared by every job on the box. Two
# jobs from different refs starting together race on it and leave it
# half-removed, after which every later job fails at setup — first as
# `ENOTEMPTY ... rmdir`, then permanently as `self-installer exits
# with code 254`, before a single test runs.
# Self-hosted runners share one $HOME, and the action clears its
# install dir before writing to it. With the default ~/setup-pnpm that
# `rmdir` is shared by every job on the box, so two jobs from
# different refs starting together race and leave it half-removed —
# `ENOTEMPTY ... rmdir .../store/v11/files/03` — after which later
# jobs fail at setup or, once store files are gone, at `pnpm install`
# with ERR_PNPM_ENOENT. All of it before a single test runs.
#
# The workflow's concurrency group is keyed on github.ref, so it
# serialises one branch and does nothing across branches — exactly the
# case that collides.
#
# `standalone` fetches a self-contained pnpm binary instead, skipping
# the node_modules layout that races. See #125.
# runner.temp is per-job and cleaned up by the runner, so there is no
# shared directory left to race on. `standalone` additionally avoids
# building the node_modules layout. See #125.
dest: ${{ runner.temp }}/setup-pnpm
standalone: true

# No `cache: pnpm` — see the test job for why.
- uses: actions/setup-node@v7
with:
node-version: 24

- run: pnpm install --frozen-lockfile
# --store-dir keeps the package cache on a stable path. The install dir
# above is per-job and disposable; the store must not be, or every job
# re-downloads ~1100 packages. A shared content-addressed store is
# pnpm's normal mode and is safe for concurrent readers — it was only
# fragile here because it happened to sit inside the directory the
# action clears.
- run: pnpm install --frozen-lockfile --store-dir ~/.pnpm-store

- name: Mutation test changed files
env:
Expand Down