Compare commits

..

30 Commits

Author SHA1 Message Date
Eric Nemchik 0977fd9972 docs: Update README to include devEngines.packageManager (#273)
Support added in #211 and #256
2026-08-03 13:44:13 +02:00
Jamie Tanna 48261aca05 fix: update pnpm to v11.19.0 (#283)
* fix: update pnpm to v11.19.0

Via `scripts/update-bootstrap.mjs 11.19.0`

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>

* fixup! fix: update pnpm to v11.19.0

As it needs to be rebuilt on Linux.

---------

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-08-03 11:54:52 +02:00
Jamie Tanna 75677f717d ci: use pnpm 11 for pr-check (#284)
Noticed while working on #283.
2026-08-03 11:02:17 +02:00
Sukka 769ae71fb3 refactor: introduce restore keys for cache (#280) 2026-08-03 10:32:23 +02:00
Kevin Cui 6fed91f804 docs(README): point users to the successor pnpm/setup action (#282)
* docs(README): point users to the successor pnpm/setup action

The pnpm setup action has moved to `pnpm/setup`, which installs
pnpm v11+ as a self-contained native executable and can install a
JavaScript runtime (Node.js, Bun, or Deno) in the same step,
replacing `actions/setup-node`.

Add a notice at the top of the README, a migration section with a
before/after workflow example and an input/output mapping table,
and mention the successor in the Notes section. The rest of the
docs stay intact since `pnpm/action-setup` remains the way to
install pnpm v10 and older.

Signed-off-by: Kevin Cui <bh@bugs.cc>

* docs(README): address review feedback on migration section

Add an explicit version: 11 to the migration example and note when the
input can be omitted, since pnpm/setup requires pnpm v11+ and a repo
migrating from version: 10 may have no packageManager field or one that
pins v10.

Move the v2 upgrade warning below the page title so the two callouts
are no longer adjacent blockquotes (markdownlint MD028), keeping the
successor notice and the legacy warning as separate blocks.

Fix the comma splice and use "set up" as the verb in the Notes
section.

Signed-off-by: Kevin Cui <bh@bugs.cc>

---------

Signed-off-by: Kevin Cui <bh@bugs.cc>
2026-08-02 22:56:56 -04:00
Zoltan Kochan 0ebf47130e fix: update pnpm to v11.7.0 (#267)
* fix: update pnpm to v11.7.0

* fix: update bundle
2026-06-15 14:04:13 +02:00
mungodewar 0e279bb959 fix: update pnpm to 11.1.1 (#248)
* fix: update pnpm to v11.1.1

* fix: update bundle

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-05-12 14:32:25 +02:00
Zoltan Kochan 3e835812ef fix: drop patchPnpmEnv so standalone+self-update works on Windows (#258)
`patchPnpmEnv` prepended `dest/node_modules/.bin` to PATH before
spawning `pnpm install` / `pnpm store prune`. On Windows in standalone
mode, `.bin/pnpm.cmd` is an npm-created shim that always points at the
BOOTSTRAP pnpm (currently 11.0.4) — the binary npm linked when it
installed `@pnpm/exe` into `node_modules`. The self-updated pnpm
written by `pnpm self-update` lives at `$PNPM_HOME/bin`, which is
separately added to PATH via `addPath()` in install-pnpm.

When the user requested a pnpm version different from the bootstrap
under `standalone: true` on Windows, patchPnpmEnv's `.bin` entry
shadowed the self-updated `$PNPM_HOME/bin` and the action's internal
`pnpm install` ran on the bootstrap. On a pnpm 11.0.x bootstrap this
broke any 11.1+ install flag (e.g. `--no-runtime`), reporting:

    ERROR  Unknown option: 'runtime'

POSIX standalone got lucky because `.bin` and `$PNPM_HOME` resolve to
the same directory there. Non-standalone never tripped on this since
the `.bin/pnpm` symlink for a regular `pnpm` package keeps working
across self-updates.

Removed `patchPnpmEnv` and the now-empty `src/utils/` module.
`spawnSync` now inherits `process.env`, whose PATH is already
correctly fronted by `$PNPM_HOME/bin` and `$PNPM_HOME` via the
`addPath` calls in install-pnpm.

Added `standalone_windows_self_update` to test.yaml as a regression
guard: standalone on Windows + target 11.1.0 + `run_install` with
`--no-runtime`. With the previous code, the install would have run
under the bootstrap (11.0.4) and errored on the unknown flag.

Originally found while building pnpm/setup (the new combined
pnpm + runtime action).
2026-05-11 22:48:51 +02:00
Andrew Haines 551b42e879 docs(README): fix cache_dependency_path type (#257)
* docs(README): fix `cache_dependency_path` type

* docs(README): add multiple lockfile example

* docs: update input description to match README
2026-05-11 16:41:41 +02:00
Zoltan Kochan 739bfe42ca fix: self-update bootstrap to packageManager-pinned version (#233) (#256)
* fix: self-update bootstrap to packageManager-pinned version (#233)

When package.json pins pnpm via `packageManager` or an exact
`devEngines.packageManager.version`, self-update the bootstrap up
front. The bootstrap's `pnpm store path` skips pnpm's auto-switch
(the `store` command sets `skipPackageManagerCheck = true`), so it
reports the bootstrap's `STORE_VERSION` while the user's actual
install runs under the pinned version and writes to a different
STORE_VERSION — breaking `cache: true` and `setup-node`'s
`cache: pnpm` on cold caches.

* fix: check bin/ dir instead of pnpm.exe for self-update detection

On Windows pnpm self-update writes `.bin/bin/pnpm` (a JS launcher),
not `.bin/bin/pnpm.exe`, so the previous existsSync probe always
fell back to pnpmHome and the bin_dest output pointed at the
bootstrap pnpm. Check whether the `bin` directory itself exists.

* fix: self-update accepts ranges; drop exact-semver gate

`pnpm self-update` resolves semver ranges to a specific version, so
`devEngines.packageManager.version: ">=10 <11"` can also go through
the self-update path. That makes readTargetVersion total — it always
returns a string or throws — so the runtime auto-switch fallback (and
the `pnpm_config_pm_on_fail=download` export from #252) is no longer
reachable and gets removed.

Adds a range case to the cache_store_path matrix.
2026-05-11 14:06:33 +02:00
Zoltan Kochan f61705d907 chore: add CODEOWNERS 2026-05-11 12:46:12 +02:00
Andrew Haines 7a5507b117 fix: restore inputs from state in post (#255) 2026-05-11 12:44:49 +02:00
Zoltan Kochan 1155470f3e fix: honor devEngines.packageManager.onFail=error (#252) (#254)
## Summary
- Export `pnpm_config_pm_on_fail=download` from the action so the bootstrap pnpm switches versions via `manage-package-manager-versions` instead of throwing `BAD_PM_VERSION` when a project pins `devEngines.packageManager.onFail = "error"` without supplying a `version:` input.
- Adds a `test_dev_engines_on_fail_error` workflow job (Linux/macOS/Windows, exact + range) that reproduces #252.

Fixes #252.
2026-05-11 01:51:30 +02:00
Zoltan Kochan 91ab88e261 fix: bin_dest output points to self-updated pnpm, not bootstrap (#249)
* fix: bin_dest output points to self-updated pnpm, not bootstrap (#247)

`pnpm self-update <version>` writes the target binary to
`${PNPM_HOME}/bin/`, leaving the bootstrap symlink at `${PNPM_HOME}/pnpm`
untouched. The `bin_dest` output was set to `${PNPM_HOME}`, so consumers
invoking `${{ steps.pnpm.outputs.bin_dest }}/pnpm` got the bootstrap
version (currently 11.0.4) instead of the version they requested.

PATH lookup hid the bug: `${PNPM_HOME}/bin` was prepended ahead of
`${PNPM_HOME}`, so `pnpm` resolved from PATH was the right one. Existing
version-respect tests only checked `pnpm --version`, not `bin_dest`.

Resolve `binDest` inside `runSelfInstaller` (target lives in
`${PNPM_HOME}/bin` after self-update, otherwise stays at `${PNPM_HOME}`)
and plumb it through to `setOutputs`. Add a regression test that invokes
`${bin_dest}/pnpm --version` directly across Linux/macOS/Windows.

* test(ci): pass bin_dest via env to survive Windows backslashes

Direct GitHub-expression interpolation of `${{ steps.pnpm.outputs.bin_dest }}`
into the bash script let bash eat the backslashes in the Windows path
(`C:Usersrunneradminsetup-pnpmnode_modules.binbin/pnpm`), failing with
"No such file or directory". Forward the value via env so the path
reaches bash unmangled.

* build: rebuild dist with clean lockfile-matched deps
2026-05-07 12:58:58 +02:00
Zoltan Kochan e578e19d19 fix: update pnpm to 11.0.4 2026-05-04 12:08:02 +02:00
Zoltan Kochan 8912a9102a fix: append (not prepend) action node dir to PATH for npm bootstrap (#241) 2026-05-02 16:10:46 +02:00
Ben Quarmby 26f6d4f2c5 fix: use npm co-located with the action node binary (#239)
* fix: use npm co-located with the action node binary

* fix: resolve npm by absolute path; guard against unset PATH

Follow-up to 5a9e198. Two refinements to the GHE self-hosted runner fix:

- Spawn npm via `path.join(dirname(process.execPath), 'npm[.cmd]')`
  instead of relying on PATH lookup. This matches the original PR
  description and is robust against PATH-shadowed npm installations.
- Avoid `"<dir>:undefined"` leaking into PATH when `process.env.PATH`
  is unset (rare, but possible in stripped environments).

PATH still has the node directory prepended so npm's
`#!/usr/bin/env node` shebang can resolve node on Linux/macOS.

* fix: revert npm to PATH lookup; runner externals lacks npm

Revert 42e75a1's switch to absolute-path npm resolution. The premise
that npm is co-located with the action's node binary is false on
GitHub-hosted runners: `process.execPath` points into
`runner/externals/node24/bin/`, which contains node only — not npm.
The absolute-path spawn produced ENOENT on Linux/macOS and
"not recognized" on Windows.

Go back to spawning `'npm'` and relying on PATH lookup, which works
on standard runners (npm is on PATH from the runner image) and on
the GHE self-hosted setup that motivated the original fix. Keep the
node-directory prepend so npm's `#!/usr/bin/env node` shebang
resolves, and keep the unset-PATH guard.

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-04-30 22:28:41 +02:00
Zoltan Kochan 903f9c1a6e fix: update pnpm to 11.0.0-rc.5 2026-04-21 20:27:39 +02:00
Zoltan Kochan bdf0af2a9d test: add strict version-match jobs to reproduce #225 / #227
The existing version tests only check output format via regex, which is
why the PATH-shadowing bug (#230) slipped through — the bootstrap pnpm's
version string matched the regex just as well as the requested version.

- test_version_respects_request: runs the action with `version: 9.15.5`
  and `version: 10.33.0` (both differ from the bootstrap) and asserts
  that `pnpm --version` matches exactly. Regression test for #225/#230.

- test_package_manager_field: writes a `packageManager: pnpm@<v>` entry
  into package.json, runs the action with no `version:` input, and
  asserts exact match. Reproduces #227; currently expected to fail
  since `packageManager` extraction was intentionally not added.
2026-04-18 15:20:30 +02:00
oniani1 71c92474e7 fix: pnpm self-update binary shadowed by bootstrap on PATH (#230)
Problem
pnpm self-update installs the target version to PNPM_HOME/bin/pnpm, but the bootstrap binary at PNPM_HOME/pnpm has higher PATH precedence because addPath(pnpmHome) was called after addPath(pnpmHome/bin). @actions/core's addPath prepends, so the later call wins — the bootstrap version shadows the self-updated binary.

Fix
Swap the addPath call order so PNPM_HOME/bin (where self-update puts the target binary) has higher PATH precedence. The bootstrap pnpm is invoked via absolute path, so this doesn't affect the bootstrap step.
2026-04-18 15:00:23 +02:00
Zoltan Kochan 078e9d4164 fix: update pnpm to 11.0.0-rc.2 2026-04-18 00:36:06 +02:00
Zoltan Kochan 08c4be7e2e docs(README): update action-setup version 2026-04-10 23:08:33 +02:00
Zoltan Kochan 579891461a chore: update .gitignore 2026-04-10 23:03:10 +02:00
Zoltan Kochan ddffd66754 fix: remove accidentally committed file 2026-04-10 23:02:48 +02:00
Zoltan Kochan b43f991918 fix: update pnpm to 11.0.0-rc.0 2026-04-10 23:00:38 +02:00
Andreas Deininger 3852509c9e README.md: bring versions up-to-date (#222) 2026-04-10 22:48:51 +02:00
Zoltan Kochan 6e7bdbda5f chore: bump bootstrap pnpm to 11.0.0-beta.4-1 and add update script
Add `pnpm run update-bootstrap [version]` to regenerate the bootstrap
lockfiles. Bumps from 11.0.0-beta.3 to 11.0.0-beta.4-1.
2026-03-30 00:09:19 +02:00
Zoltan Kochan 6b87c4621a fix: Windows standalone mode — bypass broken npm shims (#217)
* fix: overwrite npm .cmd wrappers for @pnpm/exe on Windows

npm creates .cmd wrappers that invoke bin entries through `node`,
but @pnpm/exe bins are native executables, not JavaScript files.
This causes pnpm commands to silently fail on Windows.

* fix: copy pnpm.exe to .bin/ on Windows for standalone mode

The .cmd wrapper approach didn't work because CMD doesn't properly
wait for extensionless PE binaries. Instead, copy the actual .exe
(and .cmd for pnpx) from @pnpm/exe into .bin/ so PATHEXT finds
pnpm.exe directly, bypassing npm's broken node-wrapping shim.

* fix: add @pnpm/exe dir to PATH on Windows instead of .bin shims

On Windows, npm's .bin shims can't properly execute the extensionless
native binaries from @pnpm/exe. Instead of trying to fix the shims,
add the @pnpm/exe directory directly to PATH where pnpm.exe lives.

* test: validate pnpm --version output in CI

All version checks now capture output and assert it matches a semver
pattern. Previously, a silently failing pnpm (exit 0, no output)
would pass the tests.

* debug: log pnpm --version output during setup

* fix: remove duplicate addPath in setOutputs that shadowed pnpm.exe

setOutputs called addPath(node_modules/.bin) AFTER installPnpm had
already added the correct path (@pnpm/exe on Windows). Since
GITHUB_PATH entries are prepended, .bin ended up first in PATH,
causing PowerShell to find npm's broken shims instead of pnpm.exe.

* fix: add PNPM_HOME/bin to PATH on all platforms

* fix: address review feedback — PATH ordering and regex anchoring

- Swap addPath order so pnpmHome (with pnpm.exe) is prepended last
  and has highest precedence over pnpmHome/bin.
- Anchor version regex with $ and allow prerelease suffixes.
2026-03-27 20:42:10 +01:00
Zoltan Kochan 994d756a33 feat: read pnpm version from devEngines.packageManager (#211)
* feat: read pnpm version from devEngines.packageManager field

When no version is specified in the action config or the packageManager
field of package.json, fall back to devEngines.packageManager.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: skip self-update for devEngines.packageManager and add CI tests

pnpm auto-switches to the right version when devEngines.packageManager
is set, so self-update is unnecessary. This also enables range support
(e.g. ">=9.15.0") which self-update doesn't handle.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 11:10:47 +01:00
Zoltan Kochan 738f428026 docs: upgrade pnpm/action-setup from v4 to v5 2026-03-26 22:31:06 +01:00
22 changed files with 952 additions and 1387 deletions
+1
View File
@@ -0,0 +1 @@
* @zkochan
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
with:
run_install: true
version: 9
version: 11
- name: Update dist/index.js
run: pnpm run build
+246 -64
View File
@@ -1,39 +1,76 @@
name: Test Action
on:
- push
- pull_request
- workflow_dispatch
pull_request:
push:
branches:
- master
workflow_dispatch:
jobs:
test_default_inputs:
name: Test with default inputs
smoke:
# Cross-OS coverage. Exercises the bootstrap install + PATH on each platform,
# the version-respects-request regression (#225 / #230 — Windows PATH shadow),
# and the bin_dest output regression (#247). Multi-version coverage on Linux
# so we don't pay 3x for major-version differences.
name: 'Smoke (${{ matrix.name }})'
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
pnpm:
- 9.15.5
os:
- ubuntu-latest
- macos-latest
- windows-latest
include:
- name: 'ubuntu / v9.15.5'
os: ubuntu-latest
version: '9.15.5'
- name: 'ubuntu / v10.33.0'
os: ubuntu-latest
version: '10.33.0'
- name: 'ubuntu / v9.15.5 / custom-dest'
os: ubuntu-latest
version: '9.15.5'
dest: '~/test/pnpm'
- name: 'macos / v9.15.5'
os: macos-latest
version: '9.15.5'
- name: 'windows / v9.15.5'
os: windows-latest
version: '9.15.5'
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Run the action
- id: pnpm
name: Run the action
uses: ./
with:
version: 9.15.5
version: ${{ matrix.version }}
dest: ${{ matrix.dest || '~/setup-pnpm' }}
- name: 'Test: which'
run: which pnpm; which pnpx
- name: 'Test: version'
run: pnpm --version
- name: 'Test: pnpm/pnpx on PATH report the requested version (incl. via bin_dest)'
# Pass paths via env, not template interpolation, so Windows
# backslashes in `bin_dest` aren't eaten by bash's escape handling.
env:
BIN_DEST: ${{ steps.pnpm.outputs.bin_dest }}
REQUIRED: ${{ matrix.version }}
run: |
set -e
which pnpm
which pnpx
actual="$(pnpm --version)"
echo "pnpm --version: ${actual}"
if [ "${actual}" != "${REQUIRED}" ]; then
echo "Expected pnpm version ${REQUIRED}, but got ${actual}"
exit 1
fi
bin_dest_version="$("$BIN_DEST/pnpm" --version)"
echo "bin_dest pnpm --version: ${bin_dest_version}"
if [ "${bin_dest_version}" != "${REQUIRED}" ]; then
echo "Expected ${REQUIRED} via bin_dest, but got ${bin_dest_version}"
exit 1
fi
shell: bash
- name: 'Test: install in a fresh project'
run: |
@@ -43,47 +80,95 @@ jobs:
pnpm add is-odd
shell: bash
test_dest:
name: Test with dest
manifest_pin:
# Folds the old test_package_manager_field, test_dev_engines, and
# test_dev_engines_on_fail_error jobs. The action's manifest handling is
# OS-independent, so ubuntu-only is sufficient.
name: 'Manifest pin: ${{ matrix.label }}'
runs-on: ${{ matrix.os }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
pnpm:
- 9.15.5
os:
- ubuntu-latest
- macos-latest
- windows-latest
include:
- label: 'packageManager pnpm@9.15.5 (#227)'
manifest: '{"packageManager":"pnpm@9.15.5"}'
version: '9.15.5'
- label: 'packageManager pnpm@10.33.0'
manifest: '{"packageManager":"pnpm@10.33.0"}'
version: '10.33.0'
- label: 'devEngines onFail=download, exact'
manifest: '{"devEngines":{"packageManager":{"name":"pnpm","version":"9.15.5","onFail":"download"}}}'
version: '9.15.5'
- label: 'devEngines onFail=download, range'
manifest: '{"devEngines":{"packageManager":{"name":"pnpm","version":">=9.15.0","onFail":"download"}}}'
version: '>=9.15.0'
- label: 'devEngines onFail=error, exact (#252)'
manifest: '{"devEngines":{"packageManager":{"name":"pnpm","version":"9.15.5","onFail":"error"}}}'
version: '9.15.5'
- label: 'devEngines onFail=error, range (#252)'
manifest: '{"devEngines":{"packageManager":{"name":"pnpm","version":">=9.15.0","onFail":"error"}}}'
version: '>=9.15.0'
- label: 'explicit version: pnpm_config_pm_on_fail not exported'
# Regression guard for the af8e203 scope fix: when the user passes an
# explicit `version:` input, the action must NOT export
# pnpm_config_pm_on_fail=download, so the user's strict onFail policy
# is preserved. Asserted directly on the env var rather than pnpm
# runtime behavior — different pnpm majors read devEngines
# differently (v10 ignores it, v11+ honors it).
manifest: '{"devEngines":{"packageManager":{"name":"pnpm","version":"9.15.5","onFail":"error"}}}'
explicit_version: '10.33.0'
expect_pm_on_fail_unset: true
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Set up package.json
run: echo '${{ matrix.manifest }}' > package.json
shell: bash
- name: Run the action
uses: ./
with:
version: 9.15.5
dest: ~/test/pnpm
version: ${{ matrix.explicit_version }}
- name: 'Test: which'
run: which pnpm && which pnpx
- name: 'Test: pnpm reports the pinned version'
if: ${{ !matrix.expect_pm_on_fail_unset }}
env:
REQUIRED: ${{ matrix.version }}
run: |
set -e
actual="$(pnpm --version)"
echo "pnpm version: ${actual}"
if [ "${REQUIRED}" = ">=9.15.0" ]; then
min="9.15.0"
if [ "$(printf '%s\n' "${min}" "${actual}" | sort -V | head -n1)" != "${min}" ]; then
echo "Expected pnpm version >= ${min}, but got ${actual}"
exit 1
fi
else
if [ "${actual}" != "${REQUIRED}" ]; then
echo "Expected pnpm version ${REQUIRED}, but got ${actual}"
exit 1
fi
fi
shell: bash
- name: 'Test: version'
run: pnpm --version
- name: 'Test: pnpm_config_pm_on_fail not exported (explicit version preserves strict policy)'
if: ${{ matrix.expect_pm_on_fail_unset }}
run: |
if [ -n "${pnpm_config_pm_on_fail:-}" ]; then
echo "Expected pnpm_config_pm_on_fail to be unset, but got: '${pnpm_config_pm_on_fail}'"
exit 1
fi
echo "pnpm_config_pm_on_fail is unset, as expected"
shell: bash
test_standalone:
name: Test with standalone
standalone:
name: Standalone mode
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
@@ -94,34 +179,125 @@ jobs:
version: 9.15.0
standalone: true
- name: 'Test: which'
run: which pnpm
- name: 'Test: version'
run: pnpm --version
- name: 'Test: install in a fresh project'
- name: 'Test: pnpm works'
run: |
set -e
which pnpm
actual="$(pnpm --version)"
if [ "${actual}" != "9.15.0" ]; then
echo "Expected 9.15.0, got ${actual}"
exit 1
fi
mkdir /tmp/test-standalone
cd /tmp/test-standalone
pnpm init
pnpm add is-odd
shell: bash
test_run_install:
name: 'Test with run_install (${{ matrix.run_install.name }}, ${{ matrix.os }})'
standalone_windows_self_update:
# Regression guard for the patchPnpmEnv PATH-shadow bug. When
# standalone: true on Windows AND the requested pnpm differs from the
# bootstrap, the previous patchPnpmEnv prepended node_modules/.bin to
# PATH; that directory contains an npm-created pnpm.cmd shim pointing
# at the BOOTSTRAP pnpm, which shadowed the self-updated pnpm at
# $PNPM_HOME/bin and caused `pnpm install` inside the action to run
# under the bootstrap version. Exercising a newer-pnpm-only flag
# (`--no-runtime`, added in 11.1.0) makes the regression assertable:
# if the bootstrap (11.0.4) handles the install, it errors with
# "Unknown option: 'runtime'".
name: 'Standalone Windows self-update (PATH regression)'
runs-on: windows-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
runs-on: ${{ matrix.os }}
- name: Set up package.json with a minimal manifest
# run_install needs a manifest to install against. Removing the
# repo's existing pnpm-lock.yaml avoids frozen-lockfile mismatch.
run: |
rm -f pnpm-lock.yaml
echo '{"name":"sw","private":true,"packageManager":"pnpm@11.1.0"}' > package.json
shell: bash
- name: Run the action
uses: ./
with:
version: 11.1.0
standalone: true
run_install: |
args: ['--no-runtime']
- name: 'Test: pnpm install completed under the self-updated pnpm'
# If the bug recurs, the previous step's run_install will have failed
# the job with "Unknown option: 'runtime'", so reaching this step
# implies success. Still verify the version on PATH matches request.
env:
REQUIRED: '11.1.0'
run: |
set -e
actual="$(pnpm --version)"
echo "pnpm --version: ${actual}"
if [ "${actual}" != "${REQUIRED}" ]; then
echo "Expected pnpm ${REQUIRED}, got ${actual}"
exit 1
fi
shell: bash
cache_store_path:
# Regression guard for #233. When package.json pins a pnpm major that
# differs from the bootstrap pnpm's major, the bootstrap reports its
# own STORE_VERSION from `pnpm store path` (the `store` command skips
# pnpm's auto-switch). The user's actual `pnpm install` runs under the
# pinned version and writes to a different STORE_VERSION, so the post
# step's saveCache then fails with "Path Validation Error". The fix is
# to self-update the bootstrap to the pinned version up front.
name: 'Cache store path matches install (#233): ${{ matrix.label }}'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- label: 'packageManager pnpm@10.33.0'
manifest: '{"packageManager":"pnpm@10.33.0","dependencies":{"is-odd":"3.0.1"}}'
- label: 'devEngines exact pnpm@10.33.0'
manifest: '{"devEngines":{"packageManager":{"name":"pnpm","version":"10.33.0"}},"dependencies":{"is-odd":"3.0.1"}}'
- label: 'devEngines range >=10 <11'
manifest: '{"devEngines":{"packageManager":{"name":"pnpm","version":">=10 <11"}},"dependencies":{"is-odd":"3.0.1"}}'
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Set up package.json
run: echo '${{ matrix.manifest }}' > package.json
shell: bash
- id: pnpm
uses: ./
with:
cache: true
run_install: |
- args: [--no-frozen-lockfile]
- name: 'Test: store path computed by the action exists on disk'
run: |
set -e
actual="$(pnpm store path --silent)"
echo "pnpm store path: ${actual}"
if [ ! -d "${actual}" ]; then
echo "Expected store path to exist on disk; cache save would fail"
exit 1
fi
shell: bash
run_install:
name: 'run_install (${{ matrix.run_install.name }})'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
pnpm:
- 9.15.5
os:
- ubuntu-latest
- macos-latest
- windows-latest
run_install:
- name: 'null'
value: 'null'
@@ -142,8 +318,14 @@ jobs:
version: 9.15.5
run_install: ${{ matrix.run_install.value }}
- name: 'Test: which'
run: which pnpm; which pnpx
- name: 'Test: version'
run: pnpm --version
- name: 'Test: pnpm works'
run: |
set -e
which pnpm
which pnpx
actual="$(pnpm --version)"
if [ "${actual}" != "9.15.5" ]; then
echo "Expected 9.15.5, got ${actual}"
exit 1
fi
shell: bash
+1
View File
@@ -9,3 +9,4 @@ temp
tmp.*
temp.*
.pnpm-store
.claude
+92 -15
View File
@@ -1,20 +1,70 @@
> ## :warning: Upgrade from v2!
> [!IMPORTANT]
> **This action has a successor: [`pnpm/setup`](https://github.com/pnpm/setup).**
>
> The v2 version of this action [has stopped working](https://github.com/pnpm/action-setup/issues/135) with newer Node.js versions. Please, upgrade to the latest version to fix any issues.
> For pnpm v11 and newer, use [`pnpm/setup`](https://github.com/pnpm/setup) instead. It downloads pnpm's self-contained release binary (no Node.js or npm required) and can install a JavaScript runtime (Node.js, Bun, or Deno) in the same step, replacing `actions/setup-node`.
>
> `pnpm/action-setup` remains the action to use for installing pnpm v10 and older. See [Migrating to pnpm/setup](#migrating-to-pnpmsetup) below.
# Setup pnpm
Install pnpm package manager.
> ## :warning: Upgrade from v2!
>
> The v2 version of this action [has stopped working](https://github.com/pnpm/action-setup/issues/135) with newer Node.js versions. Please, upgrade to the latest version to fix any issues.
## Migrating to pnpm/setup
[`pnpm/setup`](https://github.com/pnpm/setup) installs pnpm v11+ as a native standalone executable and can install Node.js, Bun, or Deno in the same step, so a typical workflow no longer needs `actions/setup-node` or an explicit `pnpm install` step:
```yaml
steps:
- uses: actions/checkout@v6
# Before:
# - uses: pnpm/action-setup@v6
# with:
# version: 10
# cache: true
# - uses: actions/setup-node@v4
# with:
# node-version: 22
# - run: pnpm install
# After:
- uses: pnpm/setup@v1
with:
version: 11
runtime: node@22
cache: true
```
The `version` input can be omitted only when `packageManager` (or `devEngines.packageManager`) in `package.json` declares pnpm v11 or newer; otherwise keep it explicit, since `pnpm/setup` requires pnpm v11+.
Input and output changes:
| `pnpm/action-setup` | `pnpm/setup` | Notes |
| ------------------- | ------------ | ----- |
| `version` | `version` | Must resolve to pnpm v11 or newer. As before, it can be omitted when `packageManager` (or `devEngines.packageManager`) is set in `package.json`. |
| `dest` | `dest` | Unchanged. |
| `run_install` | `install` | `pnpm/setup` runs `pnpm install` automatically when a `package.json` is present (`install: true` by default); set `install: false` to skip it. The object/array form (`recursive`, `cwd`, `args`) is not supported — run those commands in separate steps. |
| `cache` | `cache` | Unchanged. |
| `cache_dependency_path` | `cache-dependency-path` | Renamed to kebab-case. |
| `package_json_file` | `package-json-file` | Renamed to kebab-case. |
| `standalone` | removed | `pnpm/setup` always installs the standalone native executable. |
| n/a | `runtime` | New: installs Node.js, Bun, or Deno (e.g. `node@22`, `bun@latest`, `deno@2`), or reads `devEngines.runtime` from `package.json`. |
| n/a | `token` | New: GitHub token for release lookup; defaults to `${{ github.token }}` and rarely needs to be set. |
| `bin_dest` (output) | `bin-dest` (output) | Renamed to kebab-case. New outputs `runtime-name` and `runtime-version` describe the installed runtime. |
## Inputs
### `version`
Version of pnpm to install.
**Optional** when there is a [`packageManager` field in the `package.json`](https://nodejs.org/api/corepack.html).
**Optional** when there is a [`packageManager` or `devEngines.packageManager` field in the `package.json`](https://nodejs.org/api/corepack.html).
otherwise, this field is **required** It supports npm versioning scheme, it could be an exact version (such as `6.24.1`), or a version range (such as `6`, `6.x.x`, `6.24.x`, `^6.24.1`, `*`, etc.), or `latest`.
otherwise, this field is **required** It supports npm versioning scheme, it could be an exact version (such as `10.9.8`), or a version range (such as `10`, `10.x.x`, `10.9.x`, `^10.9.8`, `*`, etc.), or `latest`.
### `dest`
@@ -48,11 +98,11 @@ If `run_install` is a YAML string representation of either an object or an array
### `cache_dependency_path`
**Optional** (_type:_ `string|string[]`, _default:_ `pnpm-lock.yaml`) File path to the pnpm lockfile, which contents hash will be used as a cache key.
**Optional** (_type:_ `string`, _default:_ `pnpm-lock.yaml`) File path to the pnpm lockfile, whose contents hash will be used as a cache key. Accepts multiple paths delimited by newlines.
### `package_json_file`
**Optional** (_type:_ `string`, _default:_ `package.json`) File path to the `package.json`/[`package.yaml`](https://github.com/pnpm/pnpm/pull/1799) to read "packageManager" configuration.
**Optional** (_type:_ `string`, _default:_ `package.json`) File path to the `package.json`/[`package.yaml`](https://github.com/pnpm/pnpm/pull/1799) to read `packageManager` or `devEngines.packageManager` configuration.
### `standalone`
@@ -74,7 +124,7 @@ Location of `pnpm` and `pnpx` command.
### Install only pnpm without `packageManager`
This works when the repo either doesn't have a `package.json` or has a `package.json` but it doesn't specify `packageManager`.
This works when the repo either doesn't have a `package.json` or has a `package.json` but it doesn't specify `packageManager` or `devEngines.packageManager`.
```yaml
on:
@@ -86,14 +136,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: pnpm/action-setup@v4
- uses: pnpm/action-setup@v6
with:
version: 10
```
### Install only pnpm with `packageManager`
Omit `version` input to use the version in the [`packageManager` field in the `package.json`](https://nodejs.org/api/corepack.html).
Omit `version` input to use the version in the [`packageManager` or `devEngines.packageManager` field in the `package.json`](https://nodejs.org/api/corepack.html).
```yaml
on:
@@ -105,7 +155,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: pnpm/action-setup@v4
- uses: pnpm/action-setup@v6
```
### Install pnpm and a few npm packages
@@ -120,9 +170,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: pnpm/action-setup@v6
with:
version: 10
run_install: |
@@ -144,9 +194,9 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10
@@ -158,9 +208,36 @@ jobs:
**Note:** You don't need to run `pnpm store prune` at the end; post-action has already taken care of that.
### Cache dependencies from multiple lockfiles
```yaml
on:
- push
- pull_request
jobs:
cache-and-install-multiple:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
with:
version: 10
cache: true
cache_dependency_path: |
one/pnpm-lock.yaml
two/pnpm-lock.yaml
run_install: |
- cwd: one
- cwd: two
```
## Notes
This action does not setup Node.js for you, use [actions/setup-node](https://github.com/actions/setup-node) yourself.
This action does not set up Node.js. Use [actions/setup-node](https://github.com/actions/setup-node) yourself. If you are on pnpm v11 or newer, [`pnpm/setup`](https://github.com/pnpm/setup) can install pnpm and Node.js in a single step.
## License
+1 -1
View File
@@ -20,7 +20,7 @@ inputs:
required: false
default: 'false'
cache_dependency_path:
description: File path to the pnpm lockfile, which contents hash will be used as a cache key
description: File path to the pnpm lockfile, whose contents hash will be used as a cache key. Accepts multiple paths delimited by newlines.
required: false
default: 'pnpm-lock.yaml'
package_json_file:
+156 -162
View File
File diff suppressed because one or more lines are too long
+3 -4
View File
@@ -3,8 +3,8 @@
"scripts": {
"build:bundle": "esbuild src/index.ts --bundle --platform=node --target=node24 --format=cjs --minify --outfile=dist/index.js --loader:.json=json",
"build": "pnpm run build:bundle",
"test": "vitest run",
"start": "pnpm run build && sh ./run.sh"
"start": "pnpm run build && sh ./run.sh",
"update-bootstrap": "node scripts/update-bootstrap.mjs"
},
"dependencies": {
"@actions/cache": "^4.1.0",
@@ -19,7 +19,6 @@
},
"devDependencies": {
"esbuild": "^0.27.4",
"typescript": "^5.3.3",
"vitest": "^4.1.2"
"typescript": "^5.3.3"
}
}
-727
View File
@@ -42,9 +42,6 @@ importers:
typescript:
specifier: ^5.3.3
version: 5.7.3
vitest:
specifier: ^4.1.2
version: 4.1.2(@types/node@22.19.11)(vite@8.0.3(@types/node@22.19.11)(esbuild@0.27.4)(yaml@2.7.0))
packages:
@@ -124,15 +121,6 @@ packages:
resolution: {integrity: sha512-IQjj9RIzAKatmNca3D6bT0qJ+Pkox1WZGOg2esJF2YLHb45pQKOwGPIAV+w3rfgkj7zV3RMxpn/c6iftzSOZJQ==}
engines: {node: '>=18.0.0'}
'@emnapi/core@1.9.1':
resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==}
'@emnapi/runtime@1.9.1':
resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==}
'@emnapi/wasi-threads@1.2.0':
resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==}
'@esbuild/aix-ppc64@0.27.4':
resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==}
engines: {node: '>=18'}
@@ -293,134 +281,12 @@ packages:
resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
engines: {node: '>=14'}
'@jridgewell/sourcemap-codec@1.5.5':
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
'@napi-rs/wasm-runtime@1.1.1':
resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==}
'@oxc-project/types@0.122.0':
resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==}
'@protobuf-ts/runtime-rpc@2.11.1':
resolution: {integrity: sha512-4CqqUmNA+/uMz00+d3CYKgElXO9VrEbucjnBFEjqI4GuDrEQ32MaI3q+9qPBvIGOlL4PmHXrzM32vBPWRhQKWQ==}
'@protobuf-ts/runtime@2.11.1':
resolution: {integrity: sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ==}
'@rolldown/binding-android-arm64@1.0.0-rc.12':
resolution: {integrity: sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [android]
'@rolldown/binding-darwin-arm64@1.0.0-rc.12':
resolution: {integrity: sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [darwin]
'@rolldown/binding-darwin-x64@1.0.0-rc.12':
resolution: {integrity: sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [darwin]
'@rolldown/binding-freebsd-x64@1.0.0-rc.12':
resolution: {integrity: sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [freebsd]
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12':
resolution: {integrity: sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [linux]
'@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12':
resolution: {integrity: sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.12':
resolution: {integrity: sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12':
resolution: {integrity: sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12':
resolution: {integrity: sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.12':
resolution: {integrity: sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-x64-musl@1.0.0-rc.12':
resolution: {integrity: sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [musl]
'@rolldown/binding-openharmony-arm64@1.0.0-rc.12':
resolution: {integrity: sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [openharmony]
'@rolldown/binding-wasm32-wasi@1.0.0-rc.12':
resolution: {integrity: sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==}
engines: {node: '>=14.0.0'}
cpu: [wasm32]
'@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12':
resolution: {integrity: sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [win32]
'@rolldown/binding-win32-x64-msvc@1.0.0-rc.12':
resolution: {integrity: sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [win32]
'@rolldown/pluginutils@1.0.0-rc.12':
resolution: {integrity: sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==}
'@standard-schema/spec@1.1.0':
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
'@tybys/wasm-util@0.10.1':
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
'@types/chai@5.2.3':
resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
'@types/deep-eql@4.0.2':
resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
'@types/expand-tilde@2.0.2':
resolution: {integrity: sha512-wlsMYiapmIR4Eq/Z0qysN8xaDMjSkO6AIDNFx9oxgWGeKVA1jU+NzwPRZErBNP5z6/dx6QNkNpKglBGPO9OkTA==}
@@ -431,35 +297,6 @@ packages:
resolution: {integrity: sha512-sOx1PKSuFwnIl7z4RN0Ls7N9AQawmR9r66eI5rFCzLDIs8HTIYrIpH9QjYWoX0lkgGrkLxXhi4QnK7MizPRrIg==}
engines: {node: '>=20.0.0'}
'@vitest/expect@4.1.2':
resolution: {integrity: sha512-gbu+7B0YgUJ2nkdsRJrFFW6X7NTP44WlhiclHniUhxADQJH5Szt9mZ9hWnJPJ8YwOK5zUOSSlSvyzRf0u1DSBQ==}
'@vitest/mocker@4.1.2':
resolution: {integrity: sha512-Ize4iQtEALHDttPRCmN+FKqOl2vxTiNUhzobQFFt/BM1lRUTG7zRCLOykG/6Vo4E4hnUdfVLo5/eqKPukcWW7Q==}
peerDependencies:
msw: ^2.4.9
vite: ^6.0.0 || ^7.0.0 || ^8.0.0
peerDependenciesMeta:
msw:
optional: true
vite:
optional: true
'@vitest/pretty-format@4.1.2':
resolution: {integrity: sha512-dwQga8aejqeuB+TvXCMzSQemvV9hNEtDDpgUKDzOmNQayl2OG241PSWeJwKRH3CiC+sESrmoFd49rfnq7T4RnA==}
'@vitest/runner@4.1.2':
resolution: {integrity: sha512-Gr+FQan34CdiYAwpGJmQG8PgkyFVmARK8/xSijia3eTFgVfpcpztWLuP6FttGNfPLJhaZVP/euvujeNYar36OQ==}
'@vitest/snapshot@4.1.2':
resolution: {integrity: sha512-g7yfUmxYS4mNxk31qbOYsSt2F4m1E02LFqO53Xpzg3zKMhLAPZAjjfyl9e6z7HrW6LvUdTwAQR3HHfLjpko16A==}
'@vitest/spy@4.1.2':
resolution: {integrity: sha512-DU4fBnbVCJGNBwVA6xSToNXrkZNSiw59H8tcuUspVMsBDBST4nfvsPsEHDHGtWRRnqBERBQu7TrTKskmjqTXKA==}
'@vitest/utils@4.1.2':
resolution: {integrity: sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==}
abort-controller@3.0.0:
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
engines: {node: '>=6.5'}
@@ -468,10 +305,6 @@ packages:
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
engines: {node: '>= 14'}
assertion-error@2.0.1:
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
engines: {node: '>=12'}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
@@ -485,10 +318,6 @@ packages:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
chai@6.2.2:
resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==}
engines: {node: '>=18'}
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
@@ -496,9 +325,6 @@ packages:
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
debug@4.4.1:
resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
engines: {node: '>=6.0'}
@@ -512,10 +338,6 @@ packages:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'}
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
@@ -528,9 +350,6 @@ packages:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
es-module-lexer@2.0.0:
resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==}
es-object-atoms@1.1.1:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
@@ -544,9 +363,6 @@ packages:
engines: {node: '>=18'}
hasBin: true
estree-walker@3.0.3:
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
event-target-shim@5.0.1:
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
engines: {node: '>=6'}
@@ -559,32 +375,14 @@ packages:
resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==}
engines: {node: '>=0.10.0'}
expect-type@1.3.0:
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
engines: {node: '>=12.0.0'}
fast-xml-parser@5.2.5:
resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==}
hasBin: true
fdir@6.5.0:
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
engines: {node: '>=12.0.0'}
peerDependencies:
picomatch: ^3 || ^4
peerDependenciesMeta:
picomatch:
optional: true
form-data@2.5.5:
resolution: {integrity: sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A==}
engines: {node: '>= 0.12'}
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
@@ -624,83 +422,6 @@ packages:
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
engines: {node: '>= 14'}
lightningcss-android-arm64@1.32.0:
resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [android]
lightningcss-darwin-arm64@1.32.0:
resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [darwin]
lightningcss-darwin-x64@1.32.0:
resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [darwin]
lightningcss-freebsd-x64@1.32.0:
resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [freebsd]
lightningcss-linux-arm-gnueabihf@1.32.0:
resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==}
engines: {node: '>= 12.0.0'}
cpu: [arm]
os: [linux]
lightningcss-linux-arm64-gnu@1.32.0:
resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
lightningcss-linux-arm64-musl@1.32.0:
resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
lightningcss-linux-x64-gnu@1.32.0:
resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
lightningcss-linux-x64-musl@1.32.0:
resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
lightningcss-win32-arm64-msvc@1.32.0:
resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [win32]
lightningcss-win32-x64-msvc@1.32.0:
resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [win32]
lightningcss@1.32.0:
resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
engines: {node: '>= 12.0.0'}
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
@@ -719,11 +440,6 @@ packages:
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
node-fetch@2.7.0:
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
engines: {node: 4.x || >=6.0.0}
@@ -733,32 +449,10 @@ packages:
encoding:
optional: true
obug@2.1.1:
resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==}
parse-passwd@1.0.0:
resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==}
engines: {node: '>=0.10.0'}
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
picomatch@4.0.4:
resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
engines: {node: '>=12'}
postcss@8.5.8:
resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==}
engines: {node: ^10 || ^12 || >=14}
rolldown@1.0.0-rc.12:
resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
@@ -769,37 +463,9 @@ packages:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
std-env@4.0.0:
resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==}
strnum@2.1.1:
resolution: {integrity: sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==}
tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
tinyexec@1.0.4:
resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==}
engines: {node: '>=18'}
tinyglobby@0.2.15:
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
engines: {node: '>=12.0.0'}
tinyrainbow@3.1.0:
resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==}
engines: {node: '>=14.0.0'}
tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
@@ -829,95 +495,12 @@ packages:
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
hasBin: true
vite@8.0.3:
resolution: {integrity: sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
'@types/node': ^20.19.0 || >=22.12.0
'@vitejs/devtools': ^0.1.0
esbuild: ^0.27.0
jiti: '>=1.21.0'
less: ^4.0.0
sass: ^1.70.0
sass-embedded: ^1.70.0
stylus: '>=0.54.8'
sugarss: ^5.0.0
terser: ^5.16.0
tsx: ^4.8.1
yaml: ^2.4.2
peerDependenciesMeta:
'@types/node':
optional: true
'@vitejs/devtools':
optional: true
esbuild:
optional: true
jiti:
optional: true
less:
optional: true
sass:
optional: true
sass-embedded:
optional: true
stylus:
optional: true
sugarss:
optional: true
terser:
optional: true
tsx:
optional: true
yaml:
optional: true
vitest@4.1.2:
resolution: {integrity: sha512-xjR1dMTVHlFLh98JE3i/f/WePqJsah4A0FK9cc8Ehp9Udk0AZk6ccpIZhh1qJ/yxVWRZ+Q54ocnD8TXmkhspGg==}
engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@opentelemetry/api': ^1.9.0
'@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0
'@vitest/browser-playwright': 4.1.2
'@vitest/browser-preview': 4.1.2
'@vitest/browser-webdriverio': 4.1.2
'@vitest/ui': 4.1.2
happy-dom: '*'
jsdom: '*'
vite: ^6.0.0 || ^7.0.0 || ^8.0.0
peerDependenciesMeta:
'@edge-runtime/vm':
optional: true
'@opentelemetry/api':
optional: true
'@types/node':
optional: true
'@vitest/browser-playwright':
optional: true
'@vitest/browser-preview':
optional: true
'@vitest/browser-webdriverio':
optional: true
'@vitest/ui':
optional: true
happy-dom:
optional: true
jsdom:
optional: true
webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
whatwg-url@5.0.0:
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
why-is-node-running@2.3.0:
resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
engines: {node: '>=8'}
hasBin: true
xml2js@0.5.0:
resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==}
engines: {node: '>=4.0.0'}
@@ -1095,22 +678,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@emnapi/core@1.9.1':
dependencies:
'@emnapi/wasi-threads': 1.2.0
tslib: 2.8.1
optional: true
'@emnapi/runtime@1.9.1':
dependencies:
tslib: 2.8.1
optional: true
'@emnapi/wasi-threads@1.2.0':
dependencies:
tslib: 2.8.1
optional: true
'@esbuild/aix-ppc64@0.27.4':
optional: true
@@ -1191,88 +758,12 @@ snapshots:
'@fastify/busboy@2.1.1': {}
'@jridgewell/sourcemap-codec@1.5.5': {}
'@napi-rs/wasm-runtime@1.1.1':
dependencies:
'@emnapi/core': 1.9.1
'@emnapi/runtime': 1.9.1
'@tybys/wasm-util': 0.10.1
optional: true
'@oxc-project/types@0.122.0': {}
'@protobuf-ts/runtime-rpc@2.11.1':
dependencies:
'@protobuf-ts/runtime': 2.11.1
'@protobuf-ts/runtime@2.11.1': {}
'@rolldown/binding-android-arm64@1.0.0-rc.12':
optional: true
'@rolldown/binding-darwin-arm64@1.0.0-rc.12':
optional: true
'@rolldown/binding-darwin-x64@1.0.0-rc.12':
optional: true
'@rolldown/binding-freebsd-x64@1.0.0-rc.12':
optional: true
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12':
optional: true
'@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12':
optional: true
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.12':
optional: true
'@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12':
optional: true
'@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12':
optional: true
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.12':
optional: true
'@rolldown/binding-linux-x64-musl@1.0.0-rc.12':
optional: true
'@rolldown/binding-openharmony-arm64@1.0.0-rc.12':
optional: true
'@rolldown/binding-wasm32-wasi@1.0.0-rc.12':
dependencies:
'@napi-rs/wasm-runtime': 1.1.1
optional: true
'@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12':
optional: true
'@rolldown/binding-win32-x64-msvc@1.0.0-rc.12':
optional: true
'@rolldown/pluginutils@1.0.0-rc.12': {}
'@standard-schema/spec@1.1.0': {}
'@tybys/wasm-util@0.10.1':
dependencies:
tslib: 2.8.1
optional: true
'@types/chai@5.2.3':
dependencies:
'@types/deep-eql': 4.0.2
assertion-error: 2.0.1
'@types/deep-eql@4.0.2': {}
'@types/estree@1.0.8': {}
'@types/expand-tilde@2.0.2': {}
'@types/node@22.19.11':
@@ -1287,55 +778,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@vitest/expect@4.1.2':
dependencies:
'@standard-schema/spec': 1.1.0
'@types/chai': 5.2.3
'@vitest/spy': 4.1.2
'@vitest/utils': 4.1.2
chai: 6.2.2
tinyrainbow: 3.1.0
'@vitest/mocker@4.1.2(vite@8.0.3(@types/node@22.19.11)(esbuild@0.27.4)(yaml@2.7.0))':
dependencies:
'@vitest/spy': 4.1.2
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 8.0.3(@types/node@22.19.11)(esbuild@0.27.4)(yaml@2.7.0)
'@vitest/pretty-format@4.1.2':
dependencies:
tinyrainbow: 3.1.0
'@vitest/runner@4.1.2':
dependencies:
'@vitest/utils': 4.1.2
pathe: 2.0.3
'@vitest/snapshot@4.1.2':
dependencies:
'@vitest/pretty-format': 4.1.2
'@vitest/utils': 4.1.2
magic-string: 0.30.21
pathe: 2.0.3
'@vitest/spy@4.1.2': {}
'@vitest/utils@4.1.2':
dependencies:
'@vitest/pretty-format': 4.1.2
convert-source-map: 2.0.0
tinyrainbow: 3.1.0
abort-controller@3.0.0:
dependencies:
event-target-shim: 5.0.1
agent-base@7.1.4: {}
assertion-error@2.0.1: {}
asynckit@0.4.0: {}
balanced-match@1.0.2: {}
@@ -1350,24 +798,18 @@ snapshots:
es-errors: 1.3.0
function-bind: 1.1.2
chai@6.2.2: {}
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
concat-map@0.0.1: {}
convert-source-map@2.0.0: {}
debug@4.4.1:
dependencies:
ms: 2.1.3
delayed-stream@1.0.0: {}
detect-libc@2.1.2: {}
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
@@ -1378,8 +820,6 @@ snapshots:
es-errors@1.3.0: {}
es-module-lexer@2.0.0: {}
es-object-atoms@1.1.1:
dependencies:
es-errors: 1.3.0
@@ -1420,10 +860,6 @@ snapshots:
'@esbuild/win32-ia32': 0.27.4
'@esbuild/win32-x64': 0.27.4
estree-walker@3.0.3:
dependencies:
'@types/estree': 1.0.8
event-target-shim@5.0.1: {}
events@3.3.0: {}
@@ -1432,16 +868,10 @@ snapshots:
dependencies:
homedir-polyfill: 1.0.3
expect-type@1.3.0: {}
fast-xml-parser@5.2.5:
dependencies:
strnum: 2.1.1
fdir@6.5.0(picomatch@4.0.4):
optionalDependencies:
picomatch: 4.0.4
form-data@2.5.5:
dependencies:
asynckit: 0.4.0
@@ -1451,9 +881,6 @@ snapshots:
mime-types: 2.1.35
safe-buffer: 5.2.1
fsevents@2.3.3:
optional: true
function-bind@1.1.2: {}
get-intrinsic@1.3.0:
@@ -1504,59 +931,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
lightningcss-android-arm64@1.32.0:
optional: true
lightningcss-darwin-arm64@1.32.0:
optional: true
lightningcss-darwin-x64@1.32.0:
optional: true
lightningcss-freebsd-x64@1.32.0:
optional: true
lightningcss-linux-arm-gnueabihf@1.32.0:
optional: true
lightningcss-linux-arm64-gnu@1.32.0:
optional: true
lightningcss-linux-arm64-musl@1.32.0:
optional: true
lightningcss-linux-x64-gnu@1.32.0:
optional: true
lightningcss-linux-x64-musl@1.32.0:
optional: true
lightningcss-win32-arm64-msvc@1.32.0:
optional: true
lightningcss-win32-x64-msvc@1.32.0:
optional: true
lightningcss@1.32.0:
dependencies:
detect-libc: 2.1.2
optionalDependencies:
lightningcss-android-arm64: 1.32.0
lightningcss-darwin-arm64: 1.32.0
lightningcss-darwin-x64: 1.32.0
lightningcss-freebsd-x64: 1.32.0
lightningcss-linux-arm-gnueabihf: 1.32.0
lightningcss-linux-arm64-gnu: 1.32.0
lightningcss-linux-arm64-musl: 1.32.0
lightningcss-linux-x64-gnu: 1.32.0
lightningcss-linux-x64-musl: 1.32.0
lightningcss-win32-arm64-msvc: 1.32.0
lightningcss-win32-x64-msvc: 1.32.0
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
math-intrinsics@1.1.0: {}
mime-db@1.52.0: {}
@@ -1571,76 +945,20 @@ snapshots:
ms@2.1.3: {}
nanoid@3.3.11: {}
node-fetch@2.7.0:
dependencies:
whatwg-url: 5.0.0
obug@2.1.1: {}
parse-passwd@1.0.0: {}
pathe@2.0.3: {}
picocolors@1.1.1: {}
picomatch@4.0.4: {}
postcss@8.5.8:
dependencies:
nanoid: 3.3.11
picocolors: 1.1.1
source-map-js: 1.2.1
rolldown@1.0.0-rc.12:
dependencies:
'@oxc-project/types': 0.122.0
'@rolldown/pluginutils': 1.0.0-rc.12
optionalDependencies:
'@rolldown/binding-android-arm64': 1.0.0-rc.12
'@rolldown/binding-darwin-arm64': 1.0.0-rc.12
'@rolldown/binding-darwin-x64': 1.0.0-rc.12
'@rolldown/binding-freebsd-x64': 1.0.0-rc.12
'@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.12
'@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.12
'@rolldown/binding-linux-arm64-musl': 1.0.0-rc.12
'@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.12
'@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.12
'@rolldown/binding-linux-x64-gnu': 1.0.0-rc.12
'@rolldown/binding-linux-x64-musl': 1.0.0-rc.12
'@rolldown/binding-openharmony-arm64': 1.0.0-rc.12
'@rolldown/binding-wasm32-wasi': 1.0.0-rc.12
'@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.12
'@rolldown/binding-win32-x64-msvc': 1.0.0-rc.12
safe-buffer@5.2.1: {}
sax@1.4.1: {}
semver@6.3.1: {}
siginfo@2.0.0: {}
source-map-js@1.2.1: {}
stackback@0.0.2: {}
std-env@4.0.0: {}
strnum@2.1.1: {}
tinybench@2.9.0: {}
tinyexec@1.0.4: {}
tinyglobby@0.2.15:
dependencies:
fdir: 6.5.0(picomatch@4.0.4)
picomatch: 4.0.4
tinyrainbow@3.1.0: {}
tr46@0.0.3: {}
tslib@1.14.1: {}
@@ -1659,46 +977,6 @@ snapshots:
uuid@8.3.2: {}
vite@8.0.3(@types/node@22.19.11)(esbuild@0.27.4)(yaml@2.7.0):
dependencies:
lightningcss: 1.32.0
picomatch: 4.0.4
postcss: 8.5.8
rolldown: 1.0.0-rc.12
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 22.19.11
esbuild: 0.27.4
fsevents: 2.3.3
yaml: 2.7.0
vitest@4.1.2(@types/node@22.19.11)(vite@8.0.3(@types/node@22.19.11)(esbuild@0.27.4)(yaml@2.7.0)):
dependencies:
'@vitest/expect': 4.1.2
'@vitest/mocker': 4.1.2(vite@8.0.3(@types/node@22.19.11)(esbuild@0.27.4)(yaml@2.7.0))
'@vitest/pretty-format': 4.1.2
'@vitest/runner': 4.1.2
'@vitest/snapshot': 4.1.2
'@vitest/spy': 4.1.2
'@vitest/utils': 4.1.2
es-module-lexer: 2.0.0
expect-type: 1.3.0
magic-string: 0.30.21
obug: 2.1.1
pathe: 2.0.3
picomatch: 4.0.4
std-env: 4.0.0
tinybench: 2.9.0
tinyexec: 1.0.4
tinyglobby: 0.2.15
tinyrainbow: 3.1.0
vite: 8.0.3(@types/node@22.19.11)(esbuild@0.27.4)(yaml@2.7.0)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 22.19.11
transitivePeerDependencies:
- msw
webidl-conversions@3.0.1: {}
whatwg-url@5.0.0:
@@ -1706,11 +984,6 @@ snapshots:
tr46: 0.0.3
webidl-conversions: 3.0.1
why-is-node-running@2.3.0:
dependencies:
siginfo: 2.0.0
stackback: 0.0.2
xml2js@0.5.0:
dependencies:
sax: 1.4.1
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env node
// Usage: node scripts/update-bootstrap.mjs [version]
// If version is omitted, fetches the latest next-11 tag from npm.
// Regenerates the bootstrap lockfiles used by action-setup to install pnpm via npm.
import { execSync } from 'child_process'
import { mkdtempSync, rmSync, readFileSync, writeFileSync } from 'fs'
import { join } from 'path'
import { tmpdir } from 'os'
const BOOTSTRAP_DIR = new URL('../src/install-pnpm/bootstrap/', import.meta.url).pathname
const version = process.argv[2] || resolveLatestVersion()
console.log(`Updating bootstrap lockfiles to pnpm@${version} ...`)
generateLock('pnpm-lock.json', { pnpm: version }, 'bootstrap-pnpm')
generateLock('exe-lock.json', { '@pnpm/exe': version }, 'bootstrap-exe')
console.log('Done!')
function resolveLatestVersion() {
const json = execSync('npm view @pnpm/exe dist-tags --json', { encoding: 'utf8' })
const tags = JSON.parse(json)
const version = tags['next-11'] || tags['latest']
if (!version) {
console.error('Could not determine latest pnpm version from npm dist-tags')
process.exit(1)
}
return version
}
function generateLock(filename, dependencies, name) {
const tmp = mkdtempSync(join(tmpdir(), 'pnpm-bootstrap-'))
try {
writeFileSync(join(tmp, 'package.json'), JSON.stringify({ private: true, dependencies }))
execSync('npm install --package-lock-only --ignore-scripts', { cwd: tmp, stdio: 'pipe' })
const lock = readFileSync(join(tmp, 'package-lock.json'), 'utf8')
const parsed = JSON.parse(lock)
parsed.name = name
writeFileSync(join(BOOTSTRAP_DIR, filename), JSON.stringify(parsed, null, 2) + '\n')
console.log(` ${filename} -> ${Object.values(dependencies)[0]}@${version}`)
} finally {
rmSync(tmp, { recursive: true, force: true })
}
}
+11 -2
View File
@@ -18,9 +18,18 @@ export async function runRestoreCache(inputs: Inputs) {
debug(`Primary key is ${primaryKey}`)
saveState('cache_primary_key', primaryKey)
let cacheKey = await restoreCache([cachePath], primaryKey)
// We don't need to download everything again if only one dependency changed
// We can still re-use previous store to cache the rest of the unchanged dependencies
const restoreKeys = [
`pnpm-cache-${process.env.RUNNER_OS}-${os.arch()}-`
];
setOutput('cache-hit', Boolean(cacheKey))
let cacheKey = await restoreCache([cachePath], primaryKey, restoreKeys)
// A restore-key (prefix) match still restores an older store, but "cache-hit"
// must only report an exact primary-key match, so dependency installation
// is not skipped when the lockfile has changed.
setOutput('cache-hit', cacheKey === primaryKey)
if (!cacheKey) {
info(`Cache is not found`)
+10 -8
View File
@@ -8,28 +8,30 @@ import pnpmInstall from './pnpm-install'
import pruneStore from './pnpm-store-prune'
async function main() {
const inputs = getInputs()
if (getState('is_post') === 'true') {
await runPost(inputs)
await runPost()
} else {
await runMain(inputs)
await runMain()
}
}
async function runMain(inputs: Inputs) {
async function runMain() {
const inputs = getInputs()
saveState('inputs', inputs)
saveState('is_post', 'true')
await installPnpm(inputs)
const binDest = await installPnpm(inputs)
if (binDest === undefined) return
console.log('Installation Completed!')
setOutputs(inputs)
setOutputs(inputs, binDest)
await restoreCache(inputs)
pnpmInstall(inputs)
}
async function runPost(inputs: Inputs) {
async function runPost() {
const inputs = JSON.parse(getState('inputs')) as Inputs
pruneStore(inputs)
await saveCache(inputs)
}
+239 -59
View File
@@ -5,34 +5,42 @@
"packages": {
"": {
"dependencies": {
"@pnpm/exe": "10.32.1"
"@pnpm/exe": "11.19.0"
}
},
"node_modules/@pnpm/exe": {
"version": "10.32.1",
"resolved": "https://registry.npmjs.org/@pnpm/exe/-/exe-10.32.1.tgz",
"integrity": "sha512-baEtwHeZwmZAdBuuDDL6tbdGg5KpxhPxr3QFfYTGXvY6ws+Z1bN0mQ7ZjcaXBSC1HuLpVXnZ6NsBiaZ2DMv4vg==",
"version": "11.19.0",
"resolved": "https://registry.npmjs.org/@pnpm/exe/-/exe-11.19.0.tgz",
"integrity": "sha512-P1mw8BZaNkEpttlyzKsxTj7PVs94bMB4cQ8pJhgbrCTSBP7xCzKS3VlOwIInS7aS5by6KAbfO5Vs9yK/ekugrg==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@reflink/reflink": "0.1.19",
"detect-libc": "^2.1.2"
},
"bin": {
"pnpm": "pnpm"
"pn": "pn",
"pnpm": "pnpm",
"pnpx": "pnpx",
"pnx": "pnx"
},
"funding": {
"url": "https://opencollective.com/pnpm"
},
"optionalDependencies": {
"@pnpm/linux-arm64": "10.32.1",
"@pnpm/linux-x64": "10.32.1",
"@pnpm/macos-arm64": "10.32.1",
"@pnpm/macos-x64": "10.32.1",
"@pnpm/win-arm64": "10.32.1",
"@pnpm/win-x64": "10.32.1"
"@pnpm/linux-arm64": "11.19.0",
"@pnpm/linux-x64": "11.19.0",
"@pnpm/linuxstatic-arm64": "11.19.0",
"@pnpm/linuxstatic-x64": "11.19.0",
"@pnpm/macos-arm64": "11.19.0",
"@pnpm/win-arm64": "11.19.0",
"@pnpm/win-x64": "11.19.0"
}
},
"node_modules/@pnpm/linux-arm64": {
"version": "10.32.1",
"resolved": "https://registry.npmjs.org/@pnpm/linux-arm64/-/linux-arm64-10.32.1.tgz",
"integrity": "sha512-6uB0B+XvunQwHGzIMk2JCkl4Ur6BtM4XbJSwB/mgpWmXDoX/KTJmgx2lodcTjgJSGSySCHfIVuTR9sj/F2D4EA==",
"version": "11.19.0",
"resolved": "https://registry.npmjs.org/@pnpm/linux-arm64/-/linux-arm64-11.19.0.tgz",
"integrity": "sha512-c5AJqnsj0BMqMCOtctOzsCqyfY+afFe1kdM9F2FrNhYwtnQRMHoJy+51qfee4yuTPOVRyk3Yh1dwvyAadiznvA==",
"cpu": [
"arm64"
],
@@ -41,17 +49,14 @@
"os": [
"linux"
],
"bin": {
"pnpm": "pnpm"
},
"funding": {
"url": "https://opencollective.com/pnpm"
}
},
"node_modules/@pnpm/linux-x64": {
"version": "10.32.1",
"resolved": "https://registry.npmjs.org/@pnpm/linux-x64/-/linux-x64-10.32.1.tgz",
"integrity": "sha512-AM2tv23Fg7h+nV+adqA/SkZKUysSIEetHfBwYFl8ArgdgkqbGoQy0rAOdKYQBb920CqfexXfI8OA8kPCzRxYng==",
"version": "11.19.0",
"resolved": "https://registry.npmjs.org/@pnpm/linux-x64/-/linux-x64-11.19.0.tgz",
"integrity": "sha512-KOKpA9o75SvmRQgWO+EqEpQzJg1b9uHk5y61PAx90sSpdYtKDPua2eBXBglzv8YK1xM3DsYXFEf7Scs+3HeDsA==",
"cpu": [
"x64"
],
@@ -60,17 +65,52 @@
"os": [
"linux"
],
"bin": {
"pnpm": "pnpm"
"funding": {
"url": "https://opencollective.com/pnpm"
}
},
"node_modules/@pnpm/linuxstatic-arm64": {
"version": "11.19.0",
"resolved": "https://registry.npmjs.org/@pnpm/linuxstatic-arm64/-/linuxstatic-arm64-11.19.0.tgz",
"integrity": "sha512-Ci9WxgCInZc3F43R6BfaHevi+dYqaI5CLi6421egFsK649eHvYPytvu+zABhTNlYGNJbD8j9w+AUYInz/TPsyQ==",
"cpu": [
"arm64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/pnpm"
}
},
"node_modules/@pnpm/linuxstatic-x64": {
"version": "11.19.0",
"resolved": "https://registry.npmjs.org/@pnpm/linuxstatic-x64/-/linuxstatic-x64-11.19.0.tgz",
"integrity": "sha512-GNMk96vNJ4uEWigekarjHofXNDFsTYRL0Mw2YlDkv/W+u0cn/UAVPHfd5aAfsf6Arel2ZQfxPUTXlpunFujWnA==",
"cpu": [
"x64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/pnpm"
}
},
"node_modules/@pnpm/macos-arm64": {
"version": "10.32.1",
"resolved": "https://registry.npmjs.org/@pnpm/macos-arm64/-/macos-arm64-10.32.1.tgz",
"integrity": "sha512-Zr4JkhRbtGVsYgbuGZO0dq/6FPOn072Pdo0ubmqWtc14cUATKgAJD7efG03yqr3MLgtwFHgdtUzZ1WsaYAtUTA==",
"version": "11.19.0",
"resolved": "https://registry.npmjs.org/@pnpm/macos-arm64/-/macos-arm64-11.19.0.tgz",
"integrity": "sha512-I3Ee/GQlPxEOeBSzqxBNwcTHxVebjMiN2xLdTBS6OK2TAPzbWMIExjU5brxhr8rAk73p7mbv/a/2tFC/3gl6FA==",
"cpu": [
"arm64"
],
@@ -79,36 +119,14 @@
"os": [
"darwin"
],
"bin": {
"pnpm": "pnpm"
},
"funding": {
"url": "https://opencollective.com/pnpm"
}
},
"node_modules/@pnpm/macos-x64": {
"version": "10.32.1",
"resolved": "https://registry.npmjs.org/@pnpm/macos-x64/-/macos-x64-10.32.1.tgz",
"integrity": "sha512-Yk6q3oFDu//OniXJxfTSHo+aew1LX81FcbzJAtEkcCeTQ0SLbQT6J3QiOMNikp8n8IjNhsy+bn2bdkUxaw+akA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"bin": {
"pnpm": "pnpm"
},
"funding": {
"url": "https://opencollective.com/pnpm"
}
},
"node_modules/@pnpm/win-arm64": {
"version": "10.32.1",
"resolved": "https://registry.npmjs.org/@pnpm/win-arm64/-/win-arm64-10.32.1.tgz",
"integrity": "sha512-P8rsP5IUetpYjr2iwggoswL2qUukYrJoToXWuMyo8immn58CsYxaXsHVQ1Oq1R3XMfmGGWTXLsiJuQ7H991MRg==",
"version": "11.19.0",
"resolved": "https://registry.npmjs.org/@pnpm/win-arm64/-/win-arm64-11.19.0.tgz",
"integrity": "sha512-rOiWuJ9wjaFY9ZDVPGVjpvjIQHZNB72rioxvuyzDKJ7dqKQ97VF27a4rmOtjhMB5u83cdDGEJ+OY+H1+TP+frw==",
"cpu": [
"arm64"
],
@@ -117,17 +135,14 @@
"os": [
"win32"
],
"bin": {
"pnpm": "pnpm.exe"
},
"funding": {
"url": "https://opencollective.com/pnpm"
}
},
"node_modules/@pnpm/win-x64": {
"version": "10.32.1",
"resolved": "https://registry.npmjs.org/@pnpm/win-x64/-/win-x64-10.32.1.tgz",
"integrity": "sha512-i24GwbtBO8ojrhp8WWimX7NgZs0UKH1171oRt6qcRL+a+FxE0Eggv2y0KP7ZI7F3+LZMarwr3tnYsZryfciUOg==",
"version": "11.19.0",
"resolved": "https://registry.npmjs.org/@pnpm/win-x64/-/win-x64-11.19.0.tgz",
"integrity": "sha512-l26XeTxoGxfU+mVcZ5jFdP9hNe5yrOlLPSkAlwwpXPI1iyyU4JUSxm6Jdyxu1UAU1FerD/BvLK2vrlR6d9ogag==",
"cpu": [
"x64"
],
@@ -136,12 +151,177 @@
"os": [
"win32"
],
"bin": {
"pnpm": "pnpm.exe"
},
"funding": {
"url": "https://opencollective.com/pnpm"
}
},
"node_modules/@reflink/reflink": {
"version": "0.1.19",
"resolved": "https://registry.npmjs.org/@reflink/reflink/-/reflink-0.1.19.tgz",
"integrity": "sha512-DmCG8GzysnCZ15bres3N5AHCmwBwYgp0As6xjhQ47rAUTUXxJiK+lLUxaGsX3hd/30qUpVElh05PbGuxRPgJwA==",
"license": "MIT",
"engines": {
"node": ">= 10"
},
"optionalDependencies": {
"@reflink/reflink-darwin-arm64": "0.1.19",
"@reflink/reflink-darwin-x64": "0.1.19",
"@reflink/reflink-linux-arm64-gnu": "0.1.19",
"@reflink/reflink-linux-arm64-musl": "0.1.19",
"@reflink/reflink-linux-x64-gnu": "0.1.19",
"@reflink/reflink-linux-x64-musl": "0.1.19",
"@reflink/reflink-win32-arm64-msvc": "0.1.19",
"@reflink/reflink-win32-x64-msvc": "0.1.19"
}
},
"node_modules/@reflink/reflink-darwin-arm64": {
"version": "0.1.19",
"resolved": "https://registry.npmjs.org/@reflink/reflink-darwin-arm64/-/reflink-darwin-arm64-0.1.19.tgz",
"integrity": "sha512-ruy44Lpepdk1FqDz38vExBY/PVUsjxZA+chd9wozjUH9JjuDT/HEaQYA6wYN9mf041l0yLVar6BCZuWABJvHSA==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@reflink/reflink-darwin-x64": {
"version": "0.1.19",
"resolved": "https://registry.npmjs.org/@reflink/reflink-darwin-x64/-/reflink-darwin-x64-0.1.19.tgz",
"integrity": "sha512-By85MSWrMZa+c26TcnAy8SDk0sTUkYlNnwknSchkhHpGXOtjNDUOxJE9oByBnGbeuIE1PiQsxDG3Ud+IVV9yuA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@reflink/reflink-linux-arm64-gnu": {
"version": "0.1.19",
"resolved": "https://registry.npmjs.org/@reflink/reflink-linux-arm64-gnu/-/reflink-linux-arm64-gnu-0.1.19.tgz",
"integrity": "sha512-7P+er8+rP9iNeN+bfmccM4hTAaLP6PQJPKWSA4iSk2bNvo6KU6RyPgYeHxXmzNKzPVRcypZQTpFgstHam6maVg==",
"cpu": [
"arm64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@reflink/reflink-linux-arm64-musl": {
"version": "0.1.19",
"resolved": "https://registry.npmjs.org/@reflink/reflink-linux-arm64-musl/-/reflink-linux-arm64-musl-0.1.19.tgz",
"integrity": "sha512-37iO/Dp6m5DDaC2sf3zPtx/hl9FV3Xze4xoYidrxxS9bgP3S8ALroxRK6xBG/1TtfXKTvolvp+IjrUU6ujIGmA==",
"cpu": [
"arm64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@reflink/reflink-linux-x64-gnu": {
"version": "0.1.19",
"resolved": "https://registry.npmjs.org/@reflink/reflink-linux-x64-gnu/-/reflink-linux-x64-gnu-0.1.19.tgz",
"integrity": "sha512-jbI8jvuYCaA3MVUdu8vLoLAFqC+iNMpiSuLbxlAgg7x3K5bsS8nOpTRnkLF7vISJ+rVR8W+7ThXlXlUQ93ulkw==",
"cpu": [
"x64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@reflink/reflink-linux-x64-musl": {
"version": "0.1.19",
"resolved": "https://registry.npmjs.org/@reflink/reflink-linux-x64-musl/-/reflink-linux-x64-musl-0.1.19.tgz",
"integrity": "sha512-e9FBWDe+lv7QKAwtKOt6A2W/fyy/aEEfr0g6j/hWzvQcrzHCsz07BNQYlNOjTfeytrtLU7k449H1PI95jA4OjQ==",
"cpu": [
"x64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@reflink/reflink-win32-arm64-msvc": {
"version": "0.1.19",
"resolved": "https://registry.npmjs.org/@reflink/reflink-win32-arm64-msvc/-/reflink-win32-arm64-msvc-0.1.19.tgz",
"integrity": "sha512-09PxnVIQcd+UOn4WAW73WU6PXL7DwGS6wPlkMhMg2zlHHG65F3vHepOw06HFCq+N42qkaNAc8AKIabWvtk6cIQ==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@reflink/reflink-win32-x64-msvc": {
"version": "0.1.19",
"resolved": "https://registry.npmjs.org/@reflink/reflink-win32-x64-msvc/-/reflink-win32-x64-msvc-0.1.19.tgz",
"integrity": "sha512-E//yT4ni2SyhwP8JRjVGWr3cbnhWDiPLgnQ66qqaanjjnMiu3O/2tjCPQXlcGc/DEYofpDc9fvhv6tALQsMV9w==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"license": "Apache-2.0",
"engines": {
"node": ">=8"
}
}
}
}
+9 -7
View File
@@ -5,20 +5,22 @@
"packages": {
"": {
"dependencies": {
"pnpm": "latest"
"pnpm": "11.19.0"
}
},
"node_modules/pnpm": {
"version": "10.32.1",
"resolved": "https://registry.npmjs.org/pnpm/-/pnpm-10.32.1.tgz",
"integrity": "sha512-pwaTjw6JrBRWtlY+q07fHR+vM2jRGR/FxZeQ6W3JGORFarLmfWE94QQ9LoyB+HMD5rQNT/7KnfFe8a1Wc0jyvg==",
"version": "11.19.0",
"resolved": "https://registry.npmjs.org/pnpm/-/pnpm-11.19.0.tgz",
"integrity": "sha512-eIHz7VkNRyxKlV4riLISF5ERYGbcyIy8o4SeybYPG7qm0syyIfqR2k4cZb7yvL43k2Wup6xTnHv4be3DobItzg==",
"license": "MIT",
"bin": {
"pnpm": "bin/pnpm.cjs",
"pnpx": "bin/pnpx.cjs"
"pn": "bin/pnpm.mjs",
"pnpm": "bin/pnpm.mjs",
"pnpx": "bin/pnpx.mjs",
"pnx": "bin/pnpx.mjs"
},
"engines": {
"node": ">=18.12"
"node": ">=22.13"
},
"funding": {
"url": "https://opencollective.com/pnpm"
-175
View File
@@ -1,175 +0,0 @@
import { describe, it, expect, beforeEach } from 'vitest'
import { ensureAliasLinks } from './ensureAliasLinks'
import { mkdtemp, mkdir, writeFile, readFile, readlink } from 'fs/promises'
import { existsSync } from 'fs'
import path from 'path'
import os from 'os'
async function createTempDir (): Promise<string> {
return mkdtemp(path.join(os.tmpdir(), 'alias-links-test-'))
}
async function setupStandaloneFixture (binDir: string): Promise<void> {
const exeDir = path.join(binDir, '..', '@pnpm', 'exe')
await mkdir(exeDir, { recursive: true })
// Only the pnpm binary exists — pn/pnpx/pnx may not exist after self-update
await writeFile(path.join(exeDir, 'pnpm'), '#!/bin/sh\necho pnpm\n', { mode: 0o755 })
}
async function setupNonStandaloneFixture (binDir: string): Promise<void> {
const pnpmBinDir = path.join(binDir, '..', 'pnpm', 'bin')
await mkdir(pnpmBinDir, { recursive: true })
await writeFile(path.join(pnpmBinDir, 'pnpm.cjs'), 'console.log("pnpm")\n')
}
describe('ensureAliasLinks', () => {
let binDir: string
beforeEach(async () => {
const tmpDir = await createTempDir()
binDir = path.join(tmpDir, 'node_modules', '.bin')
await mkdir(binDir, { recursive: true })
})
describe('standalone mode', () => {
it('creates pn as symlink to pnpm binary on unix', async () => {
await setupStandaloneFixture(binDir)
await ensureAliasLinks(binDir, true, 'linux')
const pnTarget = await readlink(path.join(binDir, 'pn'))
expect(pnTarget).toBe(path.join('..', '@pnpm', 'exe', 'pnpm'))
})
it('creates pnpx and pnx as shell scripts calling pnpm dlx on unix', async () => {
await setupStandaloneFixture(binDir)
await ensureAliasLinks(binDir, true, 'linux')
for (const name of ['pnpx', 'pnx']) {
const content = await readFile(path.join(binDir, name), 'utf8')
expect(content).toContain('pnpm')
expect(content).toContain('dlx')
expect(content).toContain('exec')
}
})
it('creates .cmd and .ps1 shims on windows', async () => {
await setupStandaloneFixture(binDir)
await ensureAliasLinks(binDir, true, 'win32')
// pn shims
const pnCmd = await readFile(path.join(binDir, 'pn.cmd'), 'utf8')
expect(pnCmd).toContain('pnpm')
expect(pnCmd).toContain('%*')
expect(pnCmd).not.toContain('dlx')
const pnPs1 = await readFile(path.join(binDir, 'pn.ps1'), 'utf8')
expect(pnPs1).toContain('pnpm')
expect(pnPs1).toContain('@args')
// pnpx/pnx shims call pnpm dlx
const pnpxCmd = await readFile(path.join(binDir, 'pnpx.cmd'), 'utf8')
expect(pnpxCmd).toContain('pnpm')
expect(pnpxCmd).toContain('dlx')
// Should not create extensionless files on windows
expect(existsSync(path.join(binDir, 'pn'))).toBe(false)
})
})
describe('non-standalone mode', () => {
it('creates pn as symlink to pnpm.cjs on unix', async () => {
await setupNonStandaloneFixture(binDir)
await ensureAliasLinks(binDir, false, 'linux')
const pnTarget = await readlink(path.join(binDir, 'pn'))
expect(pnTarget).toBe(path.join('..', 'pnpm', 'bin', 'pnpm.cjs'))
})
it('creates pnpx/pnx scripts on unix', async () => {
await setupNonStandaloneFixture(binDir)
await ensureAliasLinks(binDir, false, 'linux')
const content = await readFile(path.join(binDir, 'pnpx'), 'utf8')
expect(content).toContain('pnpm.cjs')
expect(content).toContain('dlx')
})
it('creates .cmd shims on windows', async () => {
await setupNonStandaloneFixture(binDir)
await ensureAliasLinks(binDir, false, 'win32')
const cmdContent = await readFile(path.join(binDir, 'pn.cmd'), 'utf8')
expect(cmdContent).toContain(path.join('pnpm', 'bin', 'pnpm.cjs'))
})
})
describe('skips when pnpm binary does not exist', () => {
it('creates no links on unix', async () => {
await ensureAliasLinks(binDir, true, 'linux')
expect(existsSync(path.join(binDir, 'pn'))).toBe(false)
expect(existsSync(path.join(binDir, 'pnpx'))).toBe(false)
expect(existsSync(path.join(binDir, 'pnx'))).toBe(false)
})
it('creates no shims on windows', async () => {
await ensureAliasLinks(binDir, true, 'win32')
expect(existsSync(path.join(binDir, 'pn.cmd'))).toBe(false)
})
})
describe('self-update bin directory (pnpm shim in same dir)', () => {
it('creates aliases using pnpm shim in the same directory on unix', async () => {
// self-update creates a pnpm shim in $PNPM_HOME/bin/ — no package dir
await writeFile(path.join(binDir, 'pnpm'), '#!/bin/sh\nexec /path/to/real/pnpm "$@"\n', { mode: 0o755 })
await ensureAliasLinks(binDir, true, 'linux')
const pnTarget = await readlink(path.join(binDir, 'pn'))
expect(pnTarget).toBe('pnpm')
const pnxContent = await readFile(path.join(binDir, 'pnx'), 'utf8')
expect(pnxContent).toContain('pnpm')
expect(pnxContent).toContain('dlx')
})
it('creates .cmd shims using pnpm in same dir on windows', async () => {
await writeFile(path.join(binDir, 'pnpm'), 'pnpm binary')
await ensureAliasLinks(binDir, true, 'win32')
const cmdContent = await readFile(path.join(binDir, 'pn.cmd'), 'utf8')
expect(cmdContent).toContain('pnpm')
})
})
describe('overwrites existing broken shims', () => {
it('replaces npm broken shim with symlink on unix', async () => {
await setupStandaloneFixture(binDir)
// Simulate npm's broken shim pointing to .tools/ placeholder
await writeFile(path.join(binDir, 'pn'), '#!/bin/sh\nexec .tools/broken "$@"\n')
await ensureAliasLinks(binDir, true, 'linux')
const target = await readlink(path.join(binDir, 'pn'))
expect(target).toBe(path.join('..', '@pnpm', 'exe', 'pnpm'))
})
it('replaces existing .cmd shims on windows', async () => {
await setupStandaloneFixture(binDir)
await writeFile(path.join(binDir, 'pn.cmd'), 'broken shim')
await ensureAliasLinks(binDir, true, 'win32')
const content = await readFile(path.join(binDir, 'pn.cmd'), 'utf8')
expect(content).toContain('pnpm')
})
})
})
-84
View File
@@ -1,84 +0,0 @@
import { unlink, writeFile, symlink } from 'fs/promises'
import { existsSync } from 'fs'
import path from 'path'
function shScript (command: string): string {
return `#!/bin/sh\nexec ${command} "$@"\n`
}
function cmdShim (command: string): string {
return `@ECHO off\r\n${command} %*\r\n`
}
function pwshShim (command: string): string {
return `#!/usr/bin/env pwsh\n${command} @args\n`
}
async function forceSymlink (target: string, linkPath: string): Promise<void> {
try { await unlink(linkPath) } catch {}
await symlink(target, linkPath)
}
async function forceWriteFile (filePath: string, content: string, mode?: number): Promise<void> {
try { await unlink(filePath) } catch {}
await writeFile(filePath, content, { mode })
}
/**
* Find the pnpm binary/shim relative to binDir.
* Checks the package directory first (node_modules/.bin/../@pnpm/exe/pnpm),
* then falls back to a pnpm shim in binDir itself (e.g. self-update's bin/).
*/
function findPnpmTarget (binDir: string, standalone: boolean): string | undefined {
const packageTarget = standalone
? path.join('..', '@pnpm', 'exe', 'pnpm')
: path.join('..', 'pnpm', 'bin', 'pnpm.cjs')
if (existsSync(path.resolve(binDir, packageTarget))) {
return packageTarget
}
// self-update creates a pnpm shim in $PNPM_HOME/bin/ — use it directly
if (existsSync(path.join(binDir, 'pnpm'))) {
return 'pnpm'
}
return undefined
}
/**
* Create pn/pnpx/pnx alias links in the bin directory.
*
* pn is an alias for pnpm, so it symlinks (or shims) to the pnpm binary.
* pnpx/pnx are aliases for "pnpm dlx", created as shell scripts.
*
* This does NOT rely on the @pnpm/exe package having pn/pnx files, because
* pnpm self-update only replaces the pnpm binary — it doesn't update other
* files in the package. The aliases are created by pointing pn directly to
* the pnpm binary, and pnpx/pnx as scripts that exec "pnpm dlx".
*/
export async function ensureAliasLinks (binDir: string, standalone: boolean, platform: NodeJS.Platform = process.platform): Promise<void> {
const isWindows = platform === 'win32'
const pnpmTarget = findPnpmTarget(binDir, standalone)
if (!pnpmTarget) return
if (isWindows) {
// pn → calls pnpm directly
await writeFile(path.join(binDir, 'pn.cmd'), cmdShim(`"%~dp0\\${pnpmTarget}"`))
await writeFile(path.join(binDir, 'pn.ps1'), pwshShim(`& "$PSScriptRoot\\${pnpmTarget}"`))
// pnpx/pnx → calls pnpm dlx
for (const name of ['pnpx', 'pnx']) {
await writeFile(path.join(binDir, `${name}.cmd`), cmdShim(`"%~dp0\\${pnpmTarget}" dlx`))
await writeFile(path.join(binDir, `${name}.ps1`), pwshShim(`& "$PSScriptRoot\\${pnpmTarget}" dlx`))
}
} else {
// pn → symlink to pnpm binary
await forceSymlink(pnpmTarget, path.join(binDir, 'pn'))
// pnpx/pnx → shell scripts that exec pnpm dlx
for (const name of ['pnpx', 'pnx']) {
const pnpmPath = `"$(dirname "$0")/${pnpmTarget}"`
await forceWriteFile(path.join(binDir, name), shScript(`${pnpmPath} dlx`), 0o755)
}
}
}
+6 -4
View File
@@ -4,13 +4,15 @@ import runSelfInstaller from './run'
export { runSelfInstaller }
export async function install(inputs: Inputs) {
export async function install(inputs: Inputs): Promise<string | undefined> {
startGroup('Running self-installer...')
const status = await runSelfInstaller(inputs)
const { exitCode, binDest } = await runSelfInstaller(inputs)
endGroup()
if (status) {
return setFailed(`Something went wrong, self-installer exits with code ${status}`)
if (exitCode) {
setFailed(`Something went wrong, self-installer exits with code ${exitCode}`)
return undefined
}
return binDest
}
export default install
+106 -42
View File
@@ -8,13 +8,22 @@ import { Inputs } from '../inputs'
import { parse as parseYaml } from 'yaml'
import pnpmLock from './bootstrap/pnpm-lock.json'
import exeLock from './bootstrap/exe-lock.json'
import { ensureAliasLinks } from './ensureAliasLinks'
const BOOTSTRAP_PNPM_PACKAGE_JSON = JSON.stringify({ private: true, dependencies: { pnpm: pnpmLock.packages['node_modules/pnpm'].version } })
const BOOTSTRAP_EXE_PACKAGE_JSON = JSON.stringify({ private: true, dependencies: { '@pnpm/exe': exeLock.packages['node_modules/@pnpm/exe'].version } })
export async function runSelfInstaller(inputs: Inputs): Promise<number> {
const { version, dest, packageJsonFile, standalone } = inputs
export interface SelfInstallerResult {
exitCode: number
binDest: string
}
export async function runSelfInstaller(inputs: Inputs): Promise<SelfInstallerResult> {
const { version, dest, packageJsonFile } = inputs
// pnpm v11 requires Node >= 22.13; use standalone (exe) bootstrap which
// bundles its own Node.js when the system Node is too old
const systemNode = await getSystemNodeVersion()
const standalone = inputs.standalone || systemNode.major < 22 || (systemNode.major === 22 && systemNode.minor < 13)
// Install bootstrap pnpm via npm (integrity verified by committed lockfile)
await rm(dest, { recursive: true, force: true })
@@ -25,83 +34,110 @@ export async function runSelfInstaller(inputs: Inputs): Promise<number> {
await writeFile(path.join(dest, 'package.json'), packageJson)
await writeFile(path.join(dest, 'package-lock.json'), JSON.stringify(lockfile))
const npmExitCode = await runCommand('npm', ['ci'], { cwd: dest })
// Append the action's node directory to PATH so npm's
// `#!/usr/bin/env node` shebang resolves on runners (e.g. GHE
// self-hosted) where node isn't already on PATH. Append (not
// prepend) so a user-installed toolchain on PATH — e.g. from a
// prior `setup-node` step — keeps precedence; otherwise the
// runner-bundled node would shadow it and pair the user's npm
// with a mismatched node version. npm itself is resolved via
// PATH — on the GitHub Actions runner it is not co-located with
// `process.execPath`.
const nodeDir = path.dirname(process.execPath)
// On Windows, the PATH key casing varies; search case-insensitively.
const pathKey = Object.keys(process.env).find(k => k.toUpperCase() === 'PATH') ?? 'PATH'
const currentPath = process.env[pathKey]
const npmEnv = { ...process.env, [pathKey]: currentPath ? currentPath + path.delimiter + nodeDir : nodeDir }
const npmExitCode = await runCommand('npm', ['ci'], { cwd: dest, env: npmEnv })
if (npmExitCode !== 0) {
return npmExitCode
return { exitCode: npmExitCode, binDest: path.join(dest, 'node_modules', '.bin') }
}
const pnpmHome = path.join(dest, 'node_modules', '.bin')
// On Windows with standalone mode, npm's .bin shims can't properly
// execute the extensionless @pnpm/exe native binaries. Add the
// @pnpm/exe directory directly to PATH so pnpm.exe is found natively.
const pnpmHome = standalone && process.platform === 'win32'
? path.join(dest, 'node_modules', '@pnpm', 'exe')
: path.join(dest, 'node_modules', '.bin')
// PNPM_HOME/bin is where `pnpm self-update` places the target version
// binary. It must have higher PATH precedence than pnpmHome (which
// contains the bootstrap binary) so the self-updated version is found
// first. The bootstrap pnpm is invoked via absolute path, not PATH,
// so this ordering does not affect the bootstrap step.
addPath(pnpmHome)
addPath(path.join(pnpmHome, 'bin'))
exportVariable('PNPM_HOME', pnpmHome)
// Ensure pnpm bin link exists — npm ci sometimes doesn't create it
const pnpmBinLink = path.join(pnpmHome, 'pnpm')
if (process.platform !== 'win32') {
const pnpmBinLink = path.join(dest, 'node_modules', '.bin', 'pnpm')
if (!existsSync(pnpmBinLink)) {
await mkdir(pnpmHome, { recursive: true })
await mkdir(path.join(dest, 'node_modules', '.bin'), { recursive: true })
const target = standalone
? path.join('..', '@pnpm', 'exe', 'pnpm')
: path.join('..', 'pnpm', 'bin', 'pnpm.cjs')
: path.join('..', 'pnpm', 'bin', 'pnpm.mjs')
await symlink(target, pnpmBinLink)
}
}
const bootstrapPnpm = standalone
? path.join(dest, 'node_modules', '@pnpm', 'exe', 'pnpm')
: path.join(dest, 'node_modules', 'pnpm', 'bin', 'pnpm.cjs')
? path.join(dest, 'node_modules', '@pnpm', 'exe', process.platform === 'win32' ? 'pnpm.exe' : 'pnpm')
: path.join(dest, 'node_modules', 'pnpm', 'bin', 'pnpm.mjs')
// Determine the target version
// Self-update the bootstrap to the requested pnpm version. readTargetVersion
// either returns a value or throws, so this always runs.
const targetVersion = readTargetVersion({ version, packageJsonFile })
if (targetVersion) {
const cmd = standalone ? bootstrapPnpm : process.execPath
const args = standalone ? ['self-update', targetVersion] : [bootstrapPnpm, 'self-update', targetVersion]
const exitCode = await runCommand(cmd, args, { cwd: dest })
if (exitCode !== 0) {
return exitCode
return { exitCode, binDest: pnpmHome }
}
}
// Create pn/pnx alias bin links if the installed version supports them
// (pnpm v11+ adds pn and pnx as short aliases).
// self-update links bins to $PNPM_HOME/bin/ which is also on PATH,
// so we must create aliases in both directories.
await ensureAliasLinks(pnpmHome, standalone)
const pnpmBinDir = path.join(pnpmHome, 'bin')
if (existsSync(pnpmBinDir)) {
await ensureAliasLinks(pnpmBinDir, standalone)
}
return 0
// self-update writes the target pnpm/pnpx into PNPM_HOME/bin, leaving
// the bootstrap symlinks in pnpmHome pointing at the old version. Use
// PNPM_HOME/bin so consumers of the bin_dest output (e.g.
// `${steps.pnpm.outputs.bin_dest}/pnpm`) invoke the requested version.
//
// When the requested version resolves to the bootstrap version, self-update
// is a no-op and PNPM_HOME/bin is not created — fall back to pnpmHome,
// whose symlinks already point at the right version.
const updatedBinDir = path.join(pnpmHome, 'bin')
return { exitCode: 0, binDest: existsSync(updatedBinDir) ? updatedBinDir : pnpmHome }
}
function readTargetVersion(opts: {
readonly version?: string | undefined
readonly packageJsonFile: string
}): string | undefined {
}): string {
const { version, packageJsonFile } = opts
const { GITHUB_WORKSPACE } = process.env
let packageManager: unknown
let packageManager: string | undefined
let devEngines: { packageManager?: { name?: string; version?: string } } | undefined
if (GITHUB_WORKSPACE) {
try {
const content = readFileSync(path.join(GITHUB_WORKSPACE, packageJsonFile), 'utf8');
({ packageManager } = packageJsonFile.endsWith(".yaml")
const manifest = packageJsonFile.endsWith(".yaml")
? parseYaml(content, { merge: true })
: JSON.parse(content)
)
packageManager = manifest.packageManager
devEngines = manifest.devEngines
} catch (error: unknown) {
// Swallow error if package.json doesn't exist in root
if (!util.types.isNativeError(error) || !('code' in error) || error.code !== 'ENOENT') throw error
}
}
// packageManager is always exact `pnpm@<version>[+<integrity>]` per spec.
// Strip the integrity hash for self-update.
const packageManagerVersion =
typeof packageManager === 'string' && packageManager.startsWith('pnpm@')
? packageManager.slice('pnpm@'.length).split('+')[0]
: undefined
if (version) {
if (
typeof packageManager === 'string' &&
packageManager.startsWith('pnpm@') &&
packageManager.replace('pnpm@', '') !== version
) {
if (packageManagerVersion && packageManagerVersion !== version) {
throw new Error(`Multiple versions of pnpm specified:
- version ${version} in the GitHub Action config with the key "version"
- version ${packageManager} in the package.json with the key "packageManager"
@@ -111,9 +147,22 @@ Remove one of these versions to avoid version mismatch errors like ERR_PNPM_BAD_
return version
}
if (typeof packageManager === 'string' && packageManager.startsWith('pnpm@')) {
// Strip the "pnpm@" prefix and any "+sha..." hash suffix
return packageManager.replace('pnpm@', '').replace(/\+.*$/, '')
// Self-update the bootstrap pnpm to the version pinned in package.json so
// PATH-resolved `pnpm` (and the bin_dest output) reflect the target
// version. Without this, `pnpm store path` runs as the bootstrap and
// reports a different STORE_VERSION than the one the user's actual
// install writes to — breaking cache: true and actions/setup-node's
// `cache: pnpm` on cold caches (issue #233).
//
// devEngines.packageManager takes priority over packageManager, matching
// pnpm's getWantedPackageManager logic. `pnpm self-update` accepts both
// exact versions and semver ranges, so we pass either through directly.
if (devEngines?.packageManager?.name === 'pnpm' && devEngines.packageManager.version) {
return devEngines.packageManager.version
}
if (packageManagerVersion) {
return packageManagerVersion
}
if (!GITHUB_WORKSPACE) {
@@ -126,13 +175,28 @@ Otherwise, please specify the pnpm version in the action configuration.`)
throw new Error(`No pnpm version is specified.
Please specify it by one of the following ways:
- in the GitHub Action config with the key "version"
- in the package.json with the key "packageManager"`)
- in the package.json with the key "packageManager"
- in the package.json with the key "devEngines.packageManager"`)
}
function runCommand(cmd: string, args: string[], opts: { cwd: string }): Promise<number> {
function getSystemNodeVersion(): Promise<{ major: number; minor: number }> {
return new Promise((resolve) => {
const cp = spawn('node', ['--version'], { stdio: ['pipe', 'pipe', 'pipe'], shell: process.platform === 'win32' })
let output = ''
cp.stdout.on('data', (data: Buffer) => { output += data.toString() })
cp.on('close', () => {
const match = output.match(/^v(\d+)\.(\d+)/)
resolve(match ? { major: parseInt(match[1], 10), minor: parseInt(match[2], 10) } : { major: 0, minor: 0 })
})
cp.on('error', () => resolve({ major: 0, minor: 0 }))
})
}
function runCommand(cmd: string, args: string[], opts: { cwd: string; env?: Record<string, string | undefined> }): Promise<number> {
return new Promise<number>((resolve, reject) => {
const cp = spawn(cmd, args, {
cwd: opts.cwd,
env: opts.env,
stdio: ['pipe', 'inherit', 'inherit'],
shell: process.platform === 'win32',
})
+4 -5
View File
@@ -1,10 +1,9 @@
import { setOutput, addPath } from '@actions/core'
import { setOutput } from '@actions/core'
import { Inputs } from '../inputs'
import { getBinDest } from '../utils'
export function setOutputs(inputs: Inputs) {
const binDest = getBinDest(inputs)
addPath(binDest)
export function setOutputs(inputs: Inputs, binDest: string) {
// NOTE: addPath is already called in installPnpm — do not call it again
// here, as a second addPath would shadow the correct entry on Windows.
setOutput('dest', inputs.dest)
setOutput('bin_dest', binDest)
}
+6 -4
View File
@@ -1,11 +1,8 @@
import { setFailed, startGroup, endGroup } from '@actions/core'
import { spawnSync } from 'child_process'
import { Inputs } from '../inputs'
import { patchPnpmEnv } from '../utils'
export function runPnpmInstall(inputs: Inputs) {
const env = patchPnpmEnv(inputs)
for (const options of inputs.runInstall) {
const args = ['install']
if (options.recursive) args.unshift('recursive')
@@ -14,11 +11,16 @@ export function runPnpmInstall(inputs: Inputs) {
const cmdStr = ['pnpm', ...args].join(' ')
startGroup(`Running ${cmdStr}...`)
// spawnSync inherits process.env, which already has $PNPM_HOME/bin and
// $PNPM_HOME prepended via addPath() in install-pnpm. Do NOT pass a
// hand-patched env that adds node_modules/.bin to the front — on
// Windows standalone, .bin/pnpm.cmd is an npm shim pointing at the
// BOOTSTRAP pnpm, which would shadow the self-updated one and break
// newer-pnpm-only behavior.
const { error, status } = spawnSync('pnpm', args, {
stdio: 'inherit',
cwd: options.cwd,
shell: true,
env,
})
endGroup()
+2 -2
View File
@@ -1,7 +1,6 @@
import { warning, startGroup, endGroup } from '@actions/core'
import { spawnSync } from 'child_process'
import { Inputs } from '../inputs'
import { patchPnpmEnv } from '../utils'
export function pruneStore(inputs: Inputs) {
if (inputs.runInstall.length === 0) {
@@ -10,10 +9,11 @@ export function pruneStore(inputs: Inputs) {
}
startGroup('Running pnpm store prune...')
// spawnSync inherits process.env (which has the right PATH from addPath
// in install-pnpm). See pnpm-install/index.ts for the rationale.
const { error, status } = spawnSync('pnpm', ['store', 'prune'], {
stdio: 'inherit',
shell: true,
env: patchPnpmEnv(inputs),
})
endGroup()
-10
View File
@@ -1,10 +0,0 @@
import path from 'path'
import process from 'process'
import { Inputs } from '../inputs'
export const getBinDest = (inputs: Inputs): string => path.join(inputs.dest, 'node_modules', '.bin')
export const patchPnpmEnv = (inputs: Inputs): NodeJS.ProcessEnv => ({
...process.env,
PATH: path.join(getBinDest(inputs), 'bin') + path.delimiter + getBinDest(inputs) + path.delimiter + process.env.PATH,
})