Compare commits

..

2 Commits

Author SHA1 Message Date
Zoltan Kochan
7133229bf3 feat: skip self-update for devEngines.packageManager and add CI tests
pnpm auto-switches to the right version when devEngines.packageManager
is set, so self-update is unnecessary. This also enables range support
(e.g. ">=9.15.0") which self-update doesn't handle.
2026-03-27 11:04:52 +01:00
Zoltan Kochan
cf8555bd12 feat: read pnpm version from devEngines.packageManager field
When no version is specified in the action config or the packageManager
field of package.json, fall back to devEngines.packageManager.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 01:51:01 +01:00
10 changed files with 167 additions and 255 deletions

View File

@@ -33,14 +33,7 @@ jobs:
run: which pnpm; which pnpx
- name: 'Test: version'
run: |
actual="$(pnpm --version)"
echo "pnpm version: ${actual}"
if [[ ! "${actual}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-.+)?$ ]]; then
echo "ERROR: pnpm --version did not produce valid output"
exit 1
fi
shell: bash
run: pnpm --version
- name: 'Test: install in a fresh project'
run: |
@@ -78,14 +71,7 @@ jobs:
run: which pnpm && which pnpx
- name: 'Test: version'
run: |
actual="$(pnpm --version)"
echo "pnpm version: ${actual}"
if [[ ! "${actual}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-.+)?$ ]]; then
echo "ERROR: pnpm --version did not produce valid output"
exit 1
fi
shell: bash
run: pnpm --version
test_standalone:
name: Test with standalone
@@ -112,14 +98,7 @@ jobs:
run: which pnpm
- name: 'Test: version'
run: |
actual="$(pnpm --version)"
echo "pnpm version: ${actual}"
if [[ ! "${actual}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-.+)?$ ]]; then
echo "ERROR: pnpm --version did not produce valid output"
exit 1
fi
shell: bash
run: pnpm --version
- name: 'Test: install in a fresh project'
run: |
@@ -217,11 +196,4 @@ jobs:
run: which pnpm; which pnpx
- name: 'Test: version'
run: |
actual="$(pnpm --version)"
echo "pnpm version: ${actual}"
if [[ ! "${actual}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-.+)?$ ]]; then
echo "ERROR: pnpm --version did not produce valid output"
exit 1
fi
shell: bash
run: pnpm --version

1
.gitignore vendored
View File

@@ -9,4 +9,3 @@ temp
tmp.*
temp.*
.pnpm-store
.claude

View File

@@ -14,7 +14,7 @@ Version of pnpm to install.
**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`
@@ -86,7 +86,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: pnpm/action-setup@v6
- uses: pnpm/action-setup@v5
with:
version: 10
```
@@ -105,7 +105,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: pnpm/action-setup@v6
- uses: pnpm/action-setup@v5
```
### Install pnpm and a few npm packages
@@ -120,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@v5
with:
version: 10
run_install: |
@@ -144,9 +144,9 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- uses: pnpm/action-setup@v6
- uses: pnpm/action-setup@v5
name: Install pnpm
with:
version: 10

222
dist/index.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -3,8 +3,7 @@
"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"
"start": "pnpm run build && sh ./run.sh"
},
"dependencies": {
"@actions/cache": "^4.1.0",

View File

@@ -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 })
}
}

View File

@@ -5,13 +5,13 @@
"packages": {
"": {
"dependencies": {
"@pnpm/exe": "11.0.0-rc.0"
"@pnpm/exe": "11.0.0-beta.3"
}
},
"node_modules/@pnpm/exe": {
"version": "11.0.0-rc.0",
"resolved": "https://registry.npmjs.org/@pnpm/exe/-/exe-11.0.0-rc.0.tgz",
"integrity": "sha512-lpa3BGQaCvH5BGS256VTyJ4+Ib2PiA5gipTfTs7MTL02utSYXcWarP0OeDhw++Cg/tgrCVRDYWcUjHOy/KNTtA==",
"version": "11.0.0-beta.3",
"resolved": "https://registry.npmjs.org/@pnpm/exe/-/exe-11.0.0-beta.3.tgz",
"integrity": "sha512-yWNlHHdYmvf4c0MCkCzAa4csJDPdA+7yJCbXBUDXMbUu/0Zv/AxtO77q24MwlnBUC0dWeA+0F/pPmdkR9aTV2A==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -27,18 +27,18 @@
"url": "https://opencollective.com/pnpm"
},
"optionalDependencies": {
"@pnpm/linux-arm64": "11.0.0-rc.0",
"@pnpm/linux-x64": "11.0.0-rc.0",
"@pnpm/macos-arm64": "11.0.0-rc.0",
"@pnpm/macos-x64": "11.0.0-rc.0",
"@pnpm/win-arm64": "11.0.0-rc.0",
"@pnpm/win-x64": "11.0.0-rc.0"
"@pnpm/linux-arm64": "11.0.0-beta.3",
"@pnpm/linux-x64": "11.0.0-beta.3",
"@pnpm/macos-arm64": "11.0.0-beta.3",
"@pnpm/macos-x64": "11.0.0-beta.3",
"@pnpm/win-arm64": "11.0.0-beta.3",
"@pnpm/win-x64": "11.0.0-beta.3"
}
},
"node_modules/@pnpm/linux-arm64": {
"version": "11.0.0-rc.0",
"resolved": "https://registry.npmjs.org/@pnpm/linux-arm64/-/linux-arm64-11.0.0-rc.0.tgz",
"integrity": "sha512-6JIbPFu8y7RevLIpOH/rhML9JtnLgAa9VVVGl8A02+sRdF415Q3cldz+N9Oh3ZNLi2JZWtvHRa5UE2FRFELOJQ==",
"version": "11.0.0-beta.3",
"resolved": "https://registry.npmjs.org/@pnpm/linux-arm64/-/linux-arm64-11.0.0-beta.3.tgz",
"integrity": "sha512-TF2fyuCY9GggR4kfhjo1hMmgn+rIohenwNoH0tLPM7JlBK7/UAIFt1LI+o999tRwTCEw7gnxHFwtI2vyQuDfNw==",
"cpu": [
"arm64"
],
@@ -52,9 +52,9 @@
}
},
"node_modules/@pnpm/linux-x64": {
"version": "11.0.0-rc.0",
"resolved": "https://registry.npmjs.org/@pnpm/linux-x64/-/linux-x64-11.0.0-rc.0.tgz",
"integrity": "sha512-5nSOBz07hmznMKJ88LaO/mk6BXCOMs3cA7VkwAz7ehWvtxeT1Dqez2Rnf5nK//BgEF1jQ8cgjff6MWaSmiYY8A==",
"version": "11.0.0-beta.3",
"resolved": "https://registry.npmjs.org/@pnpm/linux-x64/-/linux-x64-11.0.0-beta.3.tgz",
"integrity": "sha512-7GrLsnSuDH62y486GUTwJdohGIC1ugz9ZJkbKOHgxIAkNGcSTJ1IkkdARtv7/WMmOEwwESDmtpOQ6LmjnpDMSA==",
"cpu": [
"x64"
],
@@ -68,9 +68,9 @@
}
},
"node_modules/@pnpm/macos-arm64": {
"version": "11.0.0-rc.0",
"resolved": "https://registry.npmjs.org/@pnpm/macos-arm64/-/macos-arm64-11.0.0-rc.0.tgz",
"integrity": "sha512-X1KgttzXrspprRU4JV3y1rxraX/H8AzXhuO3tDJj01nbUhps0kkjdfJziLJFFYN74bwSO8DgFWmJ5w5V+Hp0Cg==",
"version": "11.0.0-beta.3",
"resolved": "https://registry.npmjs.org/@pnpm/macos-arm64/-/macos-arm64-11.0.0-beta.3.tgz",
"integrity": "sha512-NQKgI1DURrEiOUzpxL0Mc+yn7DV4tpShqGnjaJLbz8ZCXsX/qhmybebvCG3r+IfSk3P5KID66lcgC/Osiaz0Dg==",
"cpu": [
"arm64"
],
@@ -84,9 +84,9 @@
}
},
"node_modules/@pnpm/macos-x64": {
"version": "11.0.0-rc.0",
"resolved": "https://registry.npmjs.org/@pnpm/macos-x64/-/macos-x64-11.0.0-rc.0.tgz",
"integrity": "sha512-Ra/CuHN7hrqScrl9w3zPDcMbY5AjAZMqTDKXL/1qP/GlY4lOJp24sQrH19y3pQGoUKoxlvVo0S4I29ZX2Wsf7A==",
"version": "11.0.0-beta.3",
"resolved": "https://registry.npmjs.org/@pnpm/macos-x64/-/macos-x64-11.0.0-beta.3.tgz",
"integrity": "sha512-Ky22KFYHXx8+8WU4KJT9NXVgzFioL2w9pHTQjsqTK70AbxiErscPYhrFIehlCNbXjgs+tGVIy13QNKkiwvmS8w==",
"cpu": [
"x64"
],
@@ -100,9 +100,9 @@
}
},
"node_modules/@pnpm/win-arm64": {
"version": "11.0.0-rc.0",
"resolved": "https://registry.npmjs.org/@pnpm/win-arm64/-/win-arm64-11.0.0-rc.0.tgz",
"integrity": "sha512-vum6DgUMO6hxYdhJBUkdNpnXW0TU/iKRUuZca6qgn/uckhaobENsuaN0pG1ga49G26I+jL5C8GfVBmdnRenm6w==",
"version": "11.0.0-beta.3",
"resolved": "https://registry.npmjs.org/@pnpm/win-arm64/-/win-arm64-11.0.0-beta.3.tgz",
"integrity": "sha512-7L8TFNDm25m+XYSyhcola3YFd/li6BZzzl56SsyGnZabsvUslMwnDiJad48wOz8IuN7zsrTSGh+X/x6F+GdrFQ==",
"cpu": [
"arm64"
],
@@ -116,9 +116,9 @@
}
},
"node_modules/@pnpm/win-x64": {
"version": "11.0.0-rc.0",
"resolved": "https://registry.npmjs.org/@pnpm/win-x64/-/win-x64-11.0.0-rc.0.tgz",
"integrity": "sha512-avY9Gz97pvcWO7nRL1AoJToVwljZIybX9A09buGpgrxTSTGjfs6bbFE+d+576ro02MHqhTn6qUnkCbPyKPcWrA==",
"version": "11.0.0-beta.3",
"resolved": "https://registry.npmjs.org/@pnpm/win-x64/-/win-x64-11.0.0-beta.3.tgz",
"integrity": "sha512-Z/6OpMUaIpggXjCtWEhp6kWjiT/2EImhkJAu8AodOORqeNcWouGEq3sO4XU0em6d+pAHmdV0hWMQ2xCUmPVuiA==",
"cpu": [
"x64"
],

View File

@@ -5,13 +5,13 @@
"packages": {
"": {
"dependencies": {
"pnpm": "11.0.0-rc.0"
"pnpm": "11.0.0-beta.3"
}
},
"node_modules/pnpm": {
"version": "11.0.0-rc.0",
"resolved": "https://registry.npmjs.org/pnpm/-/pnpm-11.0.0-rc.0.tgz",
"integrity": "sha512-Hwjq3uoCXpFEjebV3uQqbJR2QlcADAQ6nja4/xKEmnLry5xl/BiFCUdHJJ5S9T2Lc62hGBRGu6gYZoEMik0/bA==",
"version": "11.0.0-beta.3",
"resolved": "https://registry.npmjs.org/pnpm/-/pnpm-11.0.0-beta.3.tgz",
"integrity": "sha512-6PrfRjycZV4vRX6ttG9oR6pOgbI2/OcF2QLOzHm35UcRuvtqP4zf3wQfAAPwEbeu1uAbpSg/Q5cL8h32tumy6Q==",
"license": "MIT",
"bin": {
"pn": "bin/pnpm.mjs",

View File

@@ -34,33 +34,23 @@ export async function runSelfInstaller(inputs: Inputs): Promise<number> {
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 expects PNPM_HOME/bin in PATH for global binaries (e.g. node
// installed via `pnpm runtime`). Add it first so the next addPath
// (pnpmHome itself, which contains pnpm.exe) has higher precedence.
addPath(path.join(pnpmHome, 'bin'))
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')
const pnpmBinLink = path.join(pnpmHome, 'pnpm')
if (!existsSync(pnpmBinLink)) {
await mkdir(path.join(dest, 'node_modules', '.bin'), { recursive: true })
await mkdir(pnpmHome, { recursive: true })
const target = standalone
? path.join('..', '@pnpm', 'exe', 'pnpm')
: path.join('..', 'pnpm', 'bin', 'pnpm.mjs')
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', 'exe', 'pnpm')
: path.join(dest, 'node_modules', 'pnpm', 'bin', 'pnpm.mjs')
// Determine the target version

View File

@@ -1,11 +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) {
const binDest = getBinDest(inputs)
// NOTE: addPath is already called in installPnpm — do not call it again
// here, as a second addPath would shadow the correct entry on Windows.
addPath(binDest)
setOutput('dest', inputs.dest)
setOutput('bin_dest', binDest)
}