mirror of
https://github.com/pnpm/action-setup.git
synced 2026-08-14 05:52:09 +08:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aec59b9f6c | ||
|
|
76bfe9d01c | ||
|
|
188c8307ce | ||
|
|
b179ac1ba6 | ||
|
|
51e56d41e9 | ||
|
|
11687bb3d2 | ||
|
|
747414e7da |
@@ -1 +0,0 @@
|
||||
* @zkochan
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
||||
with:
|
||||
run_install: true
|
||||
version: 11
|
||||
version: 9
|
||||
|
||||
- name: Update dist/index.js
|
||||
run: pnpm run build
|
||||
|
||||
+63
-303
@@ -1,76 +1,39 @@
|
||||
name: Test Action
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
- push
|
||||
- pull_request
|
||||
- workflow_dispatch
|
||||
|
||||
jobs:
|
||||
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 }})'
|
||||
test_default_inputs:
|
||||
name: Test with default inputs
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
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'
|
||||
pnpm:
|
||||
- 9.15.5
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
- windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
|
||||
- id: pnpm
|
||||
name: Run the action
|
||||
- name: Run the action
|
||||
uses: ./
|
||||
with:
|
||||
version: ${{ matrix.version }}
|
||||
dest: ${{ matrix.dest || '~/setup-pnpm' }}
|
||||
version: 9.15.5
|
||||
|
||||
- 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: which'
|
||||
run: which pnpm; which pnpx
|
||||
|
||||
- name: 'Test: version'
|
||||
run: pnpm --version
|
||||
|
||||
- name: 'Test: install in a fresh project'
|
||||
run: |
|
||||
@@ -80,95 +43,47 @@ jobs:
|
||||
pnpm add is-odd
|
||||
shell: bash
|
||||
|
||||
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 }}'
|
||||
test_dest:
|
||||
name: Test with dest
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
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
|
||||
pnpm:
|
||||
- 9.15.5
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
- windows-latest
|
||||
|
||||
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: ${{ matrix.explicit_version }}
|
||||
version: 9.15.5
|
||||
dest: ~/test/pnpm
|
||||
|
||||
- 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: which'
|
||||
run: which pnpm && which pnpx
|
||||
|
||||
- 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
|
||||
- name: 'Test: version'
|
||||
run: pnpm --version
|
||||
|
||||
standalone:
|
||||
name: Standalone mode
|
||||
test_standalone:
|
||||
name: Test with standalone
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
@@ -179,125 +94,34 @@ jobs:
|
||||
version: 9.15.0
|
||||
standalone: true
|
||||
|
||||
- name: 'Test: pnpm works'
|
||||
- name: 'Test: which'
|
||||
run: which pnpm
|
||||
|
||||
- name: 'Test: version'
|
||||
run: pnpm --version
|
||||
|
||||
- name: 'Test: install in a fresh project'
|
||||
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
|
||||
|
||||
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
|
||||
test_run_install:
|
||||
name: 'Test with run_install (${{ matrix.run_install.name }}, ${{ 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
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pnpm:
|
||||
- 9.15.5
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
- windows-latest
|
||||
run_install:
|
||||
- name: 'null'
|
||||
value: 'null'
|
||||
@@ -318,72 +142,8 @@ jobs:
|
||||
version: 9.15.5
|
||||
run_install: ${{ matrix.run_install.value }}
|
||||
|
||||
- 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
|
||||
- name: 'Test: which'
|
||||
run: which pnpm; which pnpx
|
||||
|
||||
cache_lockfile_verification:
|
||||
# The action caches pnpm's lockfile verification log, which lives in
|
||||
# `cacheDir` — a directory pnpm resolves per platform and does not print.
|
||||
# Guard the action's copy of that default against pnpm's own.
|
||||
name: 'Lockfile verification cache (${{ matrix.os }}, cache=${{ matrix.cache }})'
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# The log is cached independently of the store, so the store-less
|
||||
# configuration has to reach it too.
|
||||
- os: ubuntu-latest
|
||||
cache: false
|
||||
- os: ubuntu-latest
|
||||
cache: true
|
||||
- os: macos-latest
|
||||
cache: true
|
||||
- os: windows-latest
|
||||
cache: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
|
||||
- name: Set up a project with a supply-chain policy
|
||||
# A one-minute floor activates the verification without holding back
|
||||
# any version the install resolves.
|
||||
run: |
|
||||
echo '{"dependencies":{"is-odd":"3.0.1"}}' > package.json
|
||||
printf 'packages:\n - .\nminimumReleaseAge: 1\n' > pnpm-workspace.yaml
|
||||
shell: bash
|
||||
|
||||
- uses: ./
|
||||
with:
|
||||
version: '12.0.0-rc.4'
|
||||
cache: ${{ matrix.cache }}
|
||||
run_install: |
|
||||
- args: [--no-frozen-lockfile]
|
||||
|
||||
- name: 'Test: pnpm wrote the verification log where the action looks for it'
|
||||
run: |
|
||||
set -e
|
||||
case "$RUNNER_OS" in
|
||||
Linux) cacheDir="${XDG_CACHE_HOME:-$HOME/.cache}/pnpm" ;;
|
||||
macOS) cacheDir="$HOME/Library/Caches/pnpm" ;;
|
||||
Windows) cacheDir="$(cygpath -u "$LOCALAPPDATA")/pnpm-cache" ;;
|
||||
*) echo "Unexpected RUNNER_OS: $RUNNER_OS"; exit 1 ;;
|
||||
esac
|
||||
echo "Expecting the verification log in ${cacheDir}"
|
||||
if [ ! -f "${cacheDir}/lockfile-verified.jsonl" ]; then
|
||||
echo "No lockfile-verified.jsonl there; the action would cache nothing"
|
||||
ls -la "${cacheDir}" || true
|
||||
exit 1
|
||||
fi
|
||||
shell: bash
|
||||
- name: 'Test: version'
|
||||
run: pnpm --version
|
||||
|
||||
@@ -9,4 +9,3 @@ temp
|
||||
tmp.*
|
||||
temp.*
|
||||
.pnpm-store
|
||||
.claude
|
||||
|
||||
@@ -1,60 +1,10 @@
|
||||
> [!IMPORTANT]
|
||||
> **This action has a successor: [`pnpm/setup`](https://github.com/pnpm/setup).**
|
||||
>
|
||||
> 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
|
||||
# Setup pnpm
|
||||
|
||||
[`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. |
|
||||
Install pnpm package manager.
|
||||
|
||||
## Inputs
|
||||
|
||||
@@ -62,9 +12,9 @@ Input and output changes:
|
||||
|
||||
Version of pnpm to install.
|
||||
|
||||
**Optional** when there is a [`packageManager` or `devEngines.packageManager` field in the `package.json`](https://nodejs.org/api/corepack.html).
|
||||
**Optional** when there is a [`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 `10.9.8`), or a version range (such as `10`, `10.x.x`, `10.9.x`, `^10.9.8`, `*`, etc.), or `latest`.
|
||||
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`.
|
||||
|
||||
### `dest`
|
||||
|
||||
@@ -94,15 +44,15 @@ If `run_install` is a YAML string representation of either an object or an array
|
||||
|
||||
### `cache`
|
||||
|
||||
**Optional** (_type:_ `boolean`, _default:_ `false`) Whether to cache the pnpm store directory, keyed on the lockfile's content hash. On pnpm v11 and newer, the results of pnpm's lockfile verification are cached regardless of this input — see [Lockfile verification cache](#lockfile-verification-cache).
|
||||
**Optional** (_type:_ `boolean`, _default:_ `false`) Whether to cache the pnpm store directory.
|
||||
|
||||
### `cache_dependency_path`
|
||||
|
||||
**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.
|
||||
**Optional** (_type:_ `string|string[]`, _default:_ `pnpm-lock.yaml`) File path to the pnpm lockfile, which contents hash will be used as a cache key.
|
||||
|
||||
### `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` or `devEngines.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" configuration.
|
||||
|
||||
### `standalone`
|
||||
|
||||
@@ -124,7 +74,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` or `devEngines.packageManager`.
|
||||
This works when the repo either doesn't have a `package.json` or has a `package.json` but it doesn't specify `packageManager`.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
@@ -136,14 +86,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: pnpm/action-setup@v6
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
```
|
||||
|
||||
### Install only pnpm with `packageManager`
|
||||
|
||||
Omit `version` input to use the version in the [`packageManager` or `devEngines.packageManager` field in the `package.json`](https://nodejs.org/api/corepack.html).
|
||||
Omit `version` input to use the version in the [`packageManager` field in the `package.json`](https://nodejs.org/api/corepack.html).
|
||||
|
||||
```yaml
|
||||
on:
|
||||
@@ -155,7 +105,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: pnpm/action-setup@v6
|
||||
- uses: pnpm/action-setup@v4
|
||||
```
|
||||
|
||||
### Install pnpm and a few npm packages
|
||||
@@ -170,9 +120,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v6
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
run_install: |
|
||||
@@ -194,9 +144,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v6
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 10
|
||||
@@ -208,55 +158,9 @@ jobs:
|
||||
|
||||
**Note:** You don't need to run `pnpm store prune` at the end; post-action has already taken care of that.
|
||||
|
||||
### Lockfile verification cache
|
||||
|
||||
pnpm v11 and newer check every lockfile entry before installing it — that each entry pins an integrity hash, that a pinned tarball URL matches the registry's own metadata, and, where configured, your `minimumReleaseAge` and `trustPolicy` policies. The verdict is memoized in a sub-kilobyte file, so an unchanged lockfile is not re-checked against the registry.
|
||||
|
||||
The action restores and saves that file on every run, independently of the `cache` input, because a job that starts without it pays for the check every time. On a repository with ~2000 lockfile entries and a warm store:
|
||||
|
||||
| | without the log | with it |
|
||||
| --- | --- | --- |
|
||||
| `minimumReleaseAge` + `trustPolicy` | 13.5s | 1.5s |
|
||||
| no policies configured | 6.7s | 1.6s |
|
||||
|
||||
Reusing a verdict is not a weaker check: pnpm re-verifies whenever the lockfile content changes, and whenever the recorded policy is looser than the one now configured.
|
||||
|
||||
The log is uploaded as soon as the install that produced it finishes, not at the end of the job, so nothing the job runs afterwards — its tests, its build, any later step — can alter what other jobs restore. Dependency lifecycle scripts are the exception, since they run inside the install itself, ahead of the upload: pnpm refuses to run them unless the repository allow-lists the package through `allowBuilds`, and a package on that list can already run code in the job.
|
||||
|
||||
Before uploading, the action checks that the log grew the way an install grows it: every record that predated the install still there, and no more new records than installs it ran. A dependency's script that slips an extra record in is caught by that, and the log is not cached — the next job re-verifies, which costs seconds and nothing else.
|
||||
|
||||
A job that installs in a step of its own rather than through this action is saved at the end of the job instead, since that is the first moment the log is known to be complete. The record count cannot be bounded there, so only the "nothing disappeared" half of the check applies.
|
||||
|
||||
### 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 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.
|
||||
This action does not setup Node.js for you, use [actions/setup-node](https://github.com/actions/setup-node) yourself.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
+2
-5
@@ -16,14 +16,11 @@ inputs:
|
||||
required: false
|
||||
default: 'null'
|
||||
cache:
|
||||
description: |
|
||||
Whether to cache the pnpm store directory, keyed on the lockfile's
|
||||
content hash. On pnpm v11 and newer, the results of pnpm's lockfile
|
||||
verification are cached either way — see the README.
|
||||
description: Whether to cache the pnpm store directory
|
||||
required: false
|
||||
default: 'false'
|
||||
cache_dependency_path:
|
||||
description: File path to the pnpm lockfile, whose contents hash will be used as a cache key. Accepts multiple paths delimited by newlines.
|
||||
description: File path to the pnpm lockfile, which contents hash will be used as a cache key
|
||||
required: false
|
||||
default: 'pnpm-lock.yaml'
|
||||
package_json_file:
|
||||
|
||||
Vendored
+162
-157
File diff suppressed because one or more lines are too long
+4
-3
@@ -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",
|
||||
"start": "pnpm run build && sh ./run.sh",
|
||||
"update-bootstrap": "node scripts/update-bootstrap.mjs"
|
||||
"test": "vitest run",
|
||||
"start": "pnpm run build && sh ./run.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/cache": "^4.1.0",
|
||||
@@ -19,6 +19,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.27.4",
|
||||
"typescript": "^5.3.3"
|
||||
"typescript": "^5.3.3",
|
||||
"vitest": "^4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+727
@@ -42,6 +42,9 @@ 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:
|
||||
|
||||
@@ -121,6 +124,15 @@ 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'}
|
||||
@@ -281,12 +293,134 @@ 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==}
|
||||
|
||||
@@ -297,6 +431,35 @@ 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'}
|
||||
@@ -305,6 +468,10 @@ 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==}
|
||||
|
||||
@@ -318,6 +485,10 @@ 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'}
|
||||
@@ -325,6 +496,9 @@ 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'}
|
||||
@@ -338,6 +512,10 @@ 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'}
|
||||
@@ -350,6 +528,9 @@ 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'}
|
||||
@@ -363,6 +544,9 @@ 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'}
|
||||
@@ -375,14 +559,32 @@ 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==}
|
||||
|
||||
@@ -422,6 +624,83 @@ 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'}
|
||||
@@ -440,6 +719,11 @@ 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}
|
||||
@@ -449,10 +733,32 @@ 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==}
|
||||
|
||||
@@ -463,9 +769,37 @@ 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==}
|
||||
|
||||
@@ -495,12 +829,95 @@ 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'}
|
||||
@@ -678,6 +1095,22 @@ 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
|
||||
|
||||
@@ -758,12 +1191,88 @@ 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':
|
||||
@@ -778,12 +1287,55 @@ 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: {}
|
||||
@@ -798,18 +1350,24 @@ 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
|
||||
@@ -820,6 +1378,8 @@ snapshots:
|
||||
|
||||
es-errors@1.3.0: {}
|
||||
|
||||
es-module-lexer@2.0.0: {}
|
||||
|
||||
es-object-atoms@1.1.1:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
@@ -860,6 +1420,10 @@ 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: {}
|
||||
@@ -868,10 +1432,16 @@ 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
|
||||
@@ -881,6 +1451,9 @@ 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:
|
||||
@@ -931,6 +1504,59 @@ 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: {}
|
||||
@@ -945,20 +1571,76 @@ 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: {}
|
||||
@@ -977,6 +1659,46 @@ 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:
|
||||
@@ -984,6 +1706,11 @@ 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
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/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 })
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,10 @@ import { Inputs } from '../inputs'
|
||||
import { runRestoreCache } from './run'
|
||||
|
||||
export async function restoreCache(inputs: Inputs) {
|
||||
if (!inputs.cache) return
|
||||
|
||||
if (!isFeatureAvailable()) {
|
||||
if (inputs.cache) {
|
||||
warning('Cache is not available, skipping cache restoration')
|
||||
}
|
||||
warning('Cache is not available, skipping cache restoration')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -4,51 +4,23 @@ import { getExecOutput } from '@actions/exec'
|
||||
import { hashFiles } from '@actions/glob'
|
||||
import os from 'os'
|
||||
import { Inputs } from '../inputs'
|
||||
import { restoreVerificationCache } from '../lockfile-verification-cache'
|
||||
import { removeWindowsExtendedPathPrefix } from '../windows-path'
|
||||
|
||||
export async function runRestoreCache(inputs: Inputs) {
|
||||
const fileHash = await hashFiles(inputs.cacheDependencyPath)
|
||||
if (!fileHash) {
|
||||
// Both caches are keyed on the lockfile, so neither can be restored
|
||||
// without one. Only the store cache was asked for by name.
|
||||
if (inputs.cache) {
|
||||
throw new Error('Some specified paths were not resolved, unable to cache dependencies.')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Restored whether or not the store is cached: the log is a fraction of a
|
||||
// kilobyte, and without it pnpm re-checks every lockfile entry against the
|
||||
// registry on each run — seconds even on a repository that configures no
|
||||
// supply-chain policies.
|
||||
await restoreVerificationCache(fileHash)
|
||||
|
||||
if (inputs.cache) {
|
||||
await runRestoreStoreCache(fileHash)
|
||||
}
|
||||
}
|
||||
|
||||
async function runRestoreStoreCache(fileHash: string) {
|
||||
const cachePath = await getCacheDirectory()
|
||||
saveState('cache_path', cachePath)
|
||||
|
||||
const fileHash = await hashFiles(inputs.cacheDependencyPath)
|
||||
if (!fileHash) {
|
||||
throw new Error('Some specified paths were not resolved, unable to cache dependencies.')
|
||||
}
|
||||
|
||||
const primaryKey = `pnpm-cache-${process.env.RUNNER_OS}-${os.arch()}-${fileHash}`
|
||||
debug(`Primary key is ${primaryKey}`)
|
||||
saveState('cache_primary_key', 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()}-`
|
||||
];
|
||||
let cacheKey = await restoreCache([cachePath], primaryKey)
|
||||
|
||||
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)
|
||||
setOutput('cache-hit', Boolean(cacheKey))
|
||||
|
||||
if (!cacheKey) {
|
||||
info(`Cache is not found`)
|
||||
@@ -61,7 +33,7 @@ async function runRestoreStoreCache(fileHash: string) {
|
||||
|
||||
async function getCacheDirectory() {
|
||||
const { stdout } = await getExecOutput('pnpm store path --silent')
|
||||
const cacheFolderPath = removeWindowsExtendedPathPrefix(stdout.trim())
|
||||
const cacheFolderPath = stdout.trim()
|
||||
debug(`Cache folder is set to "${cacheFolderPath}"`)
|
||||
return cacheFolderPath
|
||||
}
|
||||
|
||||
+8
-16
@@ -3,41 +3,33 @@ import restoreCache from './cache-restore'
|
||||
import saveCache from './cache-save'
|
||||
import getInputs, { Inputs } from './inputs'
|
||||
import installPnpm from './install-pnpm'
|
||||
import { saveVerificationCache } from './lockfile-verification-cache'
|
||||
import setOutputs from './outputs'
|
||||
import pnpmInstall from './pnpm-install'
|
||||
import pruneStore from './pnpm-store-prune'
|
||||
|
||||
async function main() {
|
||||
const inputs = getInputs()
|
||||
|
||||
if (getState('is_post') === 'true') {
|
||||
await runPost()
|
||||
await runPost(inputs)
|
||||
} else {
|
||||
await runMain()
|
||||
await runMain(inputs)
|
||||
}
|
||||
}
|
||||
|
||||
async function runMain() {
|
||||
const inputs = getInputs()
|
||||
saveState('inputs', inputs)
|
||||
async function runMain(inputs: Inputs) {
|
||||
saveState('is_post', 'true')
|
||||
|
||||
const binDest = await installPnpm(inputs)
|
||||
if (binDest === undefined) return
|
||||
await installPnpm(inputs)
|
||||
console.log('Installation Completed!')
|
||||
setOutputs(inputs, binDest)
|
||||
setOutputs(inputs)
|
||||
|
||||
await restoreCache(inputs)
|
||||
|
||||
pnpmInstall(inputs)
|
||||
await saveVerificationCache(inputs.runInstall.length)
|
||||
}
|
||||
|
||||
async function runPost() {
|
||||
const inputs = JSON.parse(getState('inputs')) as Inputs
|
||||
// Covers a job that installs in a later step of its own; when this action
|
||||
// installed, the log was already saved then. Runs before the prune because
|
||||
// pnpm versions before pnpm/pnpm#13893 delete the log during one.
|
||||
await saveVerificationCache()
|
||||
async function runPost(inputs: Inputs) {
|
||||
pruneStore(inputs)
|
||||
await saveCache(inputs)
|
||||
}
|
||||
|
||||
@@ -5,42 +5,34 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@pnpm/exe": "11.19.0"
|
||||
"@pnpm/exe": "10.32.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@pnpm/exe": {
|
||||
"version": "11.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@pnpm/exe/-/exe-11.19.0.tgz",
|
||||
"integrity": "sha512-P1mw8BZaNkEpttlyzKsxTj7PVs94bMB4cQ8pJhgbrCTSBP7xCzKS3VlOwIInS7aS5by6KAbfO5Vs9yK/ekugrg==",
|
||||
"version": "10.32.1",
|
||||
"resolved": "https://registry.npmjs.org/@pnpm/exe/-/exe-10.32.1.tgz",
|
||||
"integrity": "sha512-baEtwHeZwmZAdBuuDDL6tbdGg5KpxhPxr3QFfYTGXvY6ws+Z1bN0mQ7ZjcaXBSC1HuLpVXnZ6NsBiaZ2DMv4vg==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@reflink/reflink": "0.1.19",
|
||||
"detect-libc": "^2.1.2"
|
||||
},
|
||||
"bin": {
|
||||
"pn": "pn",
|
||||
"pnpm": "pnpm",
|
||||
"pnpx": "pnpx",
|
||||
"pnx": "pnx"
|
||||
"pnpm": "pnpm"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/pnpm"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@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"
|
||||
"@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"
|
||||
}
|
||||
},
|
||||
"node_modules/@pnpm/linux-arm64": {
|
||||
"version": "11.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@pnpm/linux-arm64/-/linux-arm64-11.19.0.tgz",
|
||||
"integrity": "sha512-c5AJqnsj0BMqMCOtctOzsCqyfY+afFe1kdM9F2FrNhYwtnQRMHoJy+51qfee4yuTPOVRyk3Yh1dwvyAadiznvA==",
|
||||
"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==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -49,14 +41,17 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"bin": {
|
||||
"pnpm": "pnpm"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/pnpm"
|
||||
}
|
||||
},
|
||||
"node_modules/@pnpm/linux-x64": {
|
||||
"version": "11.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@pnpm/linux-x64/-/linux-x64-11.19.0.tgz",
|
||||
"integrity": "sha512-KOKpA9o75SvmRQgWO+EqEpQzJg1b9uHk5y61PAx90sSpdYtKDPua2eBXBglzv8YK1xM3DsYXFEf7Scs+3HeDsA==",
|
||||
"version": "10.32.1",
|
||||
"resolved": "https://registry.npmjs.org/@pnpm/linux-x64/-/linux-x64-10.32.1.tgz",
|
||||
"integrity": "sha512-AM2tv23Fg7h+nV+adqA/SkZKUysSIEetHfBwYFl8ArgdgkqbGoQy0rAOdKYQBb920CqfexXfI8OA8kPCzRxYng==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -65,52 +60,17 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"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"
|
||||
],
|
||||
"bin": {
|
||||
"pnpm": "pnpm"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/pnpm"
|
||||
}
|
||||
},
|
||||
"node_modules/@pnpm/macos-arm64": {
|
||||
"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==",
|
||||
"version": "10.32.1",
|
||||
"resolved": "https://registry.npmjs.org/@pnpm/macos-arm64/-/macos-arm64-10.32.1.tgz",
|
||||
"integrity": "sha512-Zr4JkhRbtGVsYgbuGZO0dq/6FPOn072Pdo0ubmqWtc14cUATKgAJD7efG03yqr3MLgtwFHgdtUzZ1WsaYAtUTA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -119,14 +79,36 @@
|
||||
"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": "11.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@pnpm/win-arm64/-/win-arm64-11.19.0.tgz",
|
||||
"integrity": "sha512-rOiWuJ9wjaFY9ZDVPGVjpvjIQHZNB72rioxvuyzDKJ7dqKQ97VF27a4rmOtjhMB5u83cdDGEJ+OY+H1+TP+frw==",
|
||||
"version": "10.32.1",
|
||||
"resolved": "https://registry.npmjs.org/@pnpm/win-arm64/-/win-arm64-10.32.1.tgz",
|
||||
"integrity": "sha512-P8rsP5IUetpYjr2iwggoswL2qUukYrJoToXWuMyo8immn58CsYxaXsHVQ1Oq1R3XMfmGGWTXLsiJuQ7H991MRg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -135,14 +117,17 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"bin": {
|
||||
"pnpm": "pnpm.exe"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/pnpm"
|
||||
}
|
||||
},
|
||||
"node_modules/@pnpm/win-x64": {
|
||||
"version": "11.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@pnpm/win-x64/-/win-x64-11.19.0.tgz",
|
||||
"integrity": "sha512-l26XeTxoGxfU+mVcZ5jFdP9hNe5yrOlLPSkAlwwpXPI1iyyU4JUSxm6Jdyxu1UAU1FerD/BvLK2vrlR6d9ogag==",
|
||||
"version": "10.32.1",
|
||||
"resolved": "https://registry.npmjs.org/@pnpm/win-x64/-/win-x64-10.32.1.tgz",
|
||||
"integrity": "sha512-i24GwbtBO8ojrhp8WWimX7NgZs0UKH1171oRt6qcRL+a+FxE0Eggv2y0KP7ZI7F3+LZMarwr3tnYsZryfciUOg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -151,177 +136,12 @@
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,22 +5,20 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"pnpm": "11.19.0"
|
||||
"pnpm": "latest"
|
||||
}
|
||||
},
|
||||
"node_modules/pnpm": {
|
||||
"version": "11.19.0",
|
||||
"resolved": "https://registry.npmjs.org/pnpm/-/pnpm-11.19.0.tgz",
|
||||
"integrity": "sha512-eIHz7VkNRyxKlV4riLISF5ERYGbcyIy8o4SeybYPG7qm0syyIfqR2k4cZb7yvL43k2Wup6xTnHv4be3DobItzg==",
|
||||
"version": "10.32.1",
|
||||
"resolved": "https://registry.npmjs.org/pnpm/-/pnpm-10.32.1.tgz",
|
||||
"integrity": "sha512-pwaTjw6JrBRWtlY+q07fHR+vM2jRGR/FxZeQ6W3JGORFarLmfWE94QQ9LoyB+HMD5rQNT/7KnfFe8a1Wc0jyvg==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"pn": "bin/pnpm.mjs",
|
||||
"pnpm": "bin/pnpm.mjs",
|
||||
"pnpx": "bin/pnpx.mjs",
|
||||
"pnx": "bin/pnpx.mjs"
|
||||
"pnpm": "bin/pnpm.cjs",
|
||||
"pnpx": "bin/pnpx.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.13"
|
||||
"node": ">=18.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/pnpm"
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
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')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,84 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,15 +4,13 @@ import runSelfInstaller from './run'
|
||||
|
||||
export { runSelfInstaller }
|
||||
|
||||
export async function install(inputs: Inputs): Promise<string | undefined> {
|
||||
export async function install(inputs: Inputs) {
|
||||
startGroup('Running self-installer...')
|
||||
const { exitCode, binDest } = await runSelfInstaller(inputs)
|
||||
const status = await runSelfInstaller(inputs)
|
||||
endGroup()
|
||||
if (exitCode) {
|
||||
setFailed(`Something went wrong, self-installer exits with code ${exitCode}`)
|
||||
return undefined
|
||||
if (status) {
|
||||
return setFailed(`Something went wrong, self-installer exits with code ${status}`)
|
||||
}
|
||||
return binDest
|
||||
}
|
||||
|
||||
export default install
|
||||
|
||||
+50
-114
@@ -8,22 +8,13 @@ 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 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)
|
||||
export async function runSelfInstaller(inputs: Inputs): Promise<number> {
|
||||
const { version, dest, packageJsonFile, standalone } = inputs
|
||||
|
||||
// Install bootstrap pnpm via npm (integrity verified by committed lockfile)
|
||||
await rm(dest, { recursive: true, force: true })
|
||||
@@ -34,110 +25,83 @@ export async function runSelfInstaller(inputs: Inputs): Promise<SelfInstallerRes
|
||||
await writeFile(path.join(dest, 'package.json'), packageJson)
|
||||
await writeFile(path.join(dest, 'package-lock.json'), JSON.stringify(lockfile))
|
||||
|
||||
// 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 })
|
||||
const npmExitCode = await runCommand('npm', ['ci'], { cwd: dest })
|
||||
if (npmExitCode !== 0) {
|
||||
return { exitCode: npmExitCode, binDest: path.join(dest, 'node_modules', '.bin') }
|
||||
return npmExitCode
|
||||
}
|
||||
|
||||
// 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.
|
||||
const pnpmHome = path.join(dest, 'node_modules', '.bin')
|
||||
addPath(pnpmHome)
|
||||
addPath(path.join(pnpmHome, 'bin'))
|
||||
exportVariable('PNPM_HOME', pnpmHome)
|
||||
|
||||
// Ensure pnpm bin link exists — npm ci sometimes doesn't create it
|
||||
if (process.platform !== 'win32') {
|
||||
const pnpmBinLink = path.join(dest, 'node_modules', '.bin', 'pnpm')
|
||||
if (!existsSync(pnpmBinLink)) {
|
||||
await mkdir(path.join(dest, 'node_modules', '.bin'), { recursive: true })
|
||||
const target = standalone
|
||||
? path.join('..', '@pnpm', 'exe', 'pnpm')
|
||||
: path.join('..', 'pnpm', 'bin', 'pnpm.mjs')
|
||||
await symlink(target, pnpmBinLink)
|
||||
}
|
||||
const pnpmBinLink = path.join(pnpmHome, 'pnpm')
|
||||
if (!existsSync(pnpmBinLink)) {
|
||||
await mkdir(pnpmHome, { recursive: true })
|
||||
const target = standalone
|
||||
? path.join('..', '@pnpm', 'exe', 'pnpm')
|
||||
: path.join('..', 'pnpm', 'bin', 'pnpm.cjs')
|
||||
await symlink(target, pnpmBinLink)
|
||||
}
|
||||
|
||||
const bootstrapPnpm = standalone
|
||||
? path.join(dest, 'node_modules', '@pnpm', 'exe', process.platform === 'win32' ? 'pnpm.exe' : 'pnpm')
|
||||
: path.join(dest, 'node_modules', 'pnpm', 'bin', 'pnpm.mjs')
|
||||
? path.join(dest, 'node_modules', '@pnpm', 'exe', 'pnpm')
|
||||
: path.join(dest, 'node_modules', 'pnpm', 'bin', 'pnpm.cjs')
|
||||
|
||||
// Self-update the bootstrap to the requested pnpm version. readTargetVersion
|
||||
// either returns a value or throws, so this always runs.
|
||||
// Determine the target version
|
||||
const targetVersion = readTargetVersion({ version, packageJsonFile })
|
||||
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, binDest: pnpmHome }
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
// 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 }
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
function readTargetVersion(opts: {
|
||||
readonly version?: string | undefined
|
||||
readonly packageJsonFile: string
|
||||
}): string {
|
||||
}): string | undefined {
|
||||
const { version, packageJsonFile } = opts
|
||||
const { GITHUB_WORKSPACE } = process.env
|
||||
|
||||
let packageManager: string | undefined
|
||||
let devEngines: { packageManager?: { name?: string; version?: string } } | undefined
|
||||
let packageManager: unknown
|
||||
|
||||
if (GITHUB_WORKSPACE) {
|
||||
try {
|
||||
const content = readFileSync(path.join(GITHUB_WORKSPACE, packageJsonFile), 'utf8');
|
||||
const manifest = packageJsonFile.endsWith(".yaml")
|
||||
({ packageManager } = 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 (packageManagerVersion && packageManagerVersion !== version) {
|
||||
if (
|
||||
typeof packageManager === 'string' &&
|
||||
packageManager.startsWith('pnpm@') &&
|
||||
packageManager.replace('pnpm@', '') !== 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"
|
||||
@@ -147,22 +111,9 @@ Remove one of these versions to avoid version mismatch errors like ERR_PNPM_BAD_
|
||||
return version
|
||||
}
|
||||
|
||||
// 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 (typeof packageManager === 'string' && packageManager.startsWith('pnpm@')) {
|
||||
// Strip the "pnpm@" prefix and any "+sha..." hash suffix
|
||||
return packageManager.replace('pnpm@', '').replace(/\+.*$/, '')
|
||||
}
|
||||
|
||||
if (!GITHUB_WORKSPACE) {
|
||||
@@ -175,28 +126,13 @@ 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 "devEngines.packageManager"`)
|
||||
- in the package.json with the key "packageManager"`)
|
||||
}
|
||||
|
||||
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> {
|
||||
function runCommand(cmd: string, args: string[], opts: { cwd: string }): 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',
|
||||
})
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
import { restoreCache, saveCache } from '@actions/cache'
|
||||
import { debug, getState, info, saveState, warning } from '@actions/core'
|
||||
import { getExecOutput } from '@actions/exec'
|
||||
import { existsSync, readFileSync } from 'fs'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
import { removeWindowsExtendedPathPrefix } from '../windows-path'
|
||||
|
||||
/**
|
||||
* Where pnpm v11+ memoizes which lockfile passed which supply-chain policies.
|
||||
* A job without it re-checks every lockfile entry against the registry, which
|
||||
* on a large repository costs more than the install.
|
||||
*/
|
||||
const VERIFICATION_CACHE_FILE = 'lockfile-verified.jsonl'
|
||||
|
||||
const PATH_STATE = 'lockfile_verification_cache_path'
|
||||
const KEY_STATE = 'lockfile_verification_cache_key'
|
||||
const STORED_STATE = 'lockfile_verification_cache_stored'
|
||||
|
||||
/**
|
||||
* Where the log lives and under which key it belongs in the cache. Held in
|
||||
* memory as well as in the action's state because the main and post steps run
|
||||
* as separate processes, and state written by one is only readable by the
|
||||
* other.
|
||||
*/
|
||||
let target: { cacheFilePath: string, key: string } | undefined
|
||||
|
||||
/** Whether this process already restored or saved the log. */
|
||||
let stored = false
|
||||
|
||||
/** The log's records as they stood before the install ran. */
|
||||
let recordsBeforeInstall: string[] | undefined
|
||||
|
||||
/**
|
||||
* The verdict is only valid for the exact lockfile content it was recorded
|
||||
* for, so this cache is keyed on the same lockfile hash as the store cache
|
||||
* but restored without prefix fallback: an older entry could never be used.
|
||||
*/
|
||||
export async function restoreVerificationCache(lockfileHash: string): Promise<void> {
|
||||
try {
|
||||
const cacheFilePath = path.join(await getPnpmCacheDirectory(), VERIFICATION_CACHE_FILE)
|
||||
const key = `pnpm-lockfile-verified-${process.env.RUNNER_OS}-${os.arch()}-${lockfileHash}`
|
||||
target = { cacheFilePath, key }
|
||||
saveState(PATH_STATE, cacheFilePath)
|
||||
saveState(KEY_STATE, key)
|
||||
debug(`Lockfile verification cache path is ${cacheFilePath}, key is ${key}`)
|
||||
|
||||
const restoredKey = await restoreCache([cacheFilePath], key)
|
||||
recordsBeforeInstall = readRecords(cacheFilePath)
|
||||
if (!restoredKey) {
|
||||
info('Lockfile verification cache is not found')
|
||||
return
|
||||
}
|
||||
|
||||
stored = true
|
||||
saveState(STORED_STATE, 'true')
|
||||
info(`Lockfile verification cache restored from key: ${restoredKey}`)
|
||||
} catch (error) {
|
||||
// The gate only costs time, never correctness — a job that cannot reuse
|
||||
// a past verdict re-verifies and moves on.
|
||||
warning(`Failed to restore the lockfile verification cache: ${(error as Error).message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploaded as soon as the install that produced the log finishes, rather than
|
||||
* at the end of the job: whatever a job runs after installing can rewrite the
|
||||
* log on disk, and the job's own cache write would then publish that for later
|
||||
* jobs to trust. Lifecycle scripts of the installed packages stay inside the
|
||||
* window — they run during the install — but pnpm only runs those the
|
||||
* repository has allow-listed, and `expectedNewRecords` catches what they
|
||||
* append.
|
||||
*
|
||||
* Safe to call more than once; the second call is a no-op.
|
||||
*/
|
||||
export async function saveVerificationCache(expectedNewRecords = Infinity): Promise<void> {
|
||||
if (stored || getState(STORED_STATE) === 'true') return
|
||||
|
||||
const cacheFilePath = target?.cacheFilePath ?? getState(PATH_STATE)
|
||||
const key = target?.key ?? getState(KEY_STATE)
|
||||
if (!cacheFilePath || !key || !existsSync(cacheFilePath)) return
|
||||
|
||||
if (!onlyGrewAsExpected(cacheFilePath, expectedNewRecords)) return
|
||||
|
||||
try {
|
||||
const cacheId = await saveCache([cacheFilePath], key)
|
||||
if (cacheId === -1) return
|
||||
stored = true
|
||||
saveState(STORED_STATE, 'true')
|
||||
info(`Lockfile verification cache saved with the key: ${key}`)
|
||||
} catch (error) {
|
||||
warning(`Failed to save the lockfile verification cache: ${(error as Error).message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An install appends its own verdict and leaves every earlier record in place.
|
||||
* Anything else — a record the install did not write, or an earlier one gone —
|
||||
* means something other than pnpm's verification wrote to the log, and
|
||||
* uploading it would hand that to every later job. pnpm compacting the log
|
||||
* (past a thousand records) lands here too, at the cost of one re-verification.
|
||||
*/
|
||||
function onlyGrewAsExpected(cacheFilePath: string, expectedNewRecords: number): boolean {
|
||||
const before = recordsBeforeInstall
|
||||
if (before === undefined) return true
|
||||
|
||||
const after = readRecords(cacheFilePath)
|
||||
if (after === undefined) return false
|
||||
|
||||
if (!before.every((record, index) => after[index] === record)) {
|
||||
warning(
|
||||
'Records that predate the install are missing from the lockfile verification log; not caching it.'
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
const added = after.length - before.length
|
||||
if (added > expectedNewRecords) {
|
||||
warning(
|
||||
`The lockfile verification log gained ${added} records during the install, expected at most ${expectedNewRecords}; not caching it.`
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
function readRecords(cacheFilePath: string): string[] | undefined {
|
||||
try {
|
||||
return readFileSync(cacheFilePath, 'utf8').split('\n').filter(Boolean)
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
async function getPnpmCacheDirectory(): Promise<string> {
|
||||
const { stdout } = await getExecOutput('pnpm config get cacheDir', undefined, {
|
||||
silent: true,
|
||||
ignoreReturnCode: true,
|
||||
})
|
||||
const configured = stdout.trim()
|
||||
// `pnpm config get` reports settings, not defaults: an unset `cacheDir`
|
||||
// prints `undefined` and the default has to be derived here.
|
||||
if (configured && configured !== 'undefined') {
|
||||
return removeWindowsExtendedPathPrefix(configured)
|
||||
}
|
||||
return defaultPnpmCacheDirectory()
|
||||
}
|
||||
|
||||
/** Mirrors pnpm's own `cacheDir` default. */
|
||||
function defaultPnpmCacheDirectory(): string {
|
||||
const { XDG_CACHE_HOME, LOCALAPPDATA } = process.env
|
||||
if (XDG_CACHE_HOME) return path.join(XDG_CACHE_HOME, 'pnpm')
|
||||
|
||||
const homeDir = os.homedir()
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
return path.join(homeDir, 'Library', 'Caches', 'pnpm')
|
||||
case 'win32':
|
||||
return LOCALAPPDATA ? path.join(LOCALAPPDATA, 'pnpm-cache') : path.join(homeDir, '.pnpm-cache')
|
||||
default:
|
||||
return path.join(homeDir, '.cache', 'pnpm')
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
import { setOutput } from '@actions/core'
|
||||
import { setOutput, addPath } from '@actions/core'
|
||||
import { Inputs } from '../inputs'
|
||||
import { getBinDest } from '../utils'
|
||||
|
||||
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.
|
||||
export function setOutputs(inputs: Inputs) {
|
||||
const binDest = getBinDest(inputs)
|
||||
addPath(binDest)
|
||||
setOutput('dest', inputs.dest)
|
||||
setOutput('bin_dest', binDest)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
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')
|
||||
@@ -11,16 +14,11 @@ 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()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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) {
|
||||
@@ -9,11 +10,10 @@ 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()
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
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,
|
||||
})
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* pnpm may report an extended-length path on Windows. The `?` in that prefix
|
||||
* is interpreted as a wildcard by `@actions/cache`, which rejects it as a glob
|
||||
* in the root segment. Cache APIs do not need the extended-length form, so
|
||||
* convert it back to a regular drive or UNC path.
|
||||
*/
|
||||
export function removeWindowsExtendedPathPrefix(cachePath: string): string {
|
||||
const extendedPathPrefix = '\\\\?\\'
|
||||
if (!cachePath.startsWith(extendedPathPrefix)) return cachePath
|
||||
|
||||
const pathWithoutPrefix = cachePath.slice(extendedPathPrefix.length)
|
||||
const uncPrefix = 'UNC\\'
|
||||
if (pathWithoutPrefix.toUpperCase().startsWith(uncPrefix)) {
|
||||
return `\\\\${pathWithoutPrefix.slice(uncPrefix.length)}`
|
||||
}
|
||||
return pathWithoutPrefix
|
||||
}
|
||||
|
||||
export default removeWindowsExtendedPathPrefix
|
||||
Reference in New Issue
Block a user