mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-23 23:29:17 -05:00
12
.changeset/yellow-brooms-sort.md
Normal file
12
.changeset/yellow-brooms-sort.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-installation": major
|
||||
"@pnpm/plugin-commands-publishing": major
|
||||
"@pnpm/plugin-commands-script-runners": major
|
||||
"@pnpm/plugin-commands-env": minor
|
||||
"@pnpm/core": minor
|
||||
"@pnpm/lifecycle": minor
|
||||
"@pnpm/types": minor
|
||||
"pnpm": minor
|
||||
---
|
||||
|
||||
Support specifying node version (via `pnpm.executionEnv.nodeVersion` in `package.json`) for running lifecycle scripts per each package in a workspace [#6720](https://github.com/pnpm/pnpm/issues/6720).
|
||||
1
env/plugin-commands-env/package.json
vendored
1
env/plugin-commands-env/package.json
vendored
@@ -41,6 +41,7 @@
|
||||
"@pnpm/node.resolver": "workspace:*",
|
||||
"@pnpm/remove-bins": "workspace:*",
|
||||
"@pnpm/store-path": "workspace:*",
|
||||
"@pnpm/types": "workspace:*",
|
||||
"@zkochan/cmd-shim": "catalog:",
|
||||
"@zkochan/rimraf": "catalog:",
|
||||
"graceful-fs": "catalog:",
|
||||
|
||||
4
env/plugin-commands-env/src/index.ts
vendored
4
env/plugin-commands-env/src/index.ts
vendored
@@ -1,4 +1,4 @@
|
||||
import * as env from './env'
|
||||
import * as node from './node'
|
||||
import { prepareExecutionEnv } from './node'
|
||||
|
||||
export { env, node }
|
||||
export { env, prepareExecutionEnv }
|
||||
|
||||
20
env/plugin-commands-env/src/node.ts
vendored
20
env/plugin-commands-env/src/node.ts
vendored
@@ -6,6 +6,7 @@ import { createFetchFromRegistry, type FetchFromRegistry } from '@pnpm/fetch'
|
||||
import { globalInfo } from '@pnpm/logger'
|
||||
import { fetchNode } from '@pnpm/node.fetcher'
|
||||
import { getStorePath } from '@pnpm/store-path'
|
||||
import { type PrepareExecutionEnvOptions, type PrepareExecutionEnvResult } from '@pnpm/types'
|
||||
import loadJsonFile from 'load-json-file'
|
||||
import writeJsonFile from 'write-json-file'
|
||||
import { getNodeMirror } from './getNodeMirror'
|
||||
@@ -36,6 +37,25 @@ export type NvmNodeCommandOptions = Pick<Config,
|
||||
remote?: boolean
|
||||
}
|
||||
|
||||
const nodeFetchPromises: Record<string, Promise<string>> = {}
|
||||
|
||||
export async function prepareExecutionEnv (config: NvmNodeCommandOptions, { extraBinPaths, executionEnv }: PrepareExecutionEnvOptions): Promise<PrepareExecutionEnvResult> {
|
||||
if (!executionEnv?.nodeVersion) return { extraBinPaths: extraBinPaths ?? [] }
|
||||
|
||||
let nodePathPromise = nodeFetchPromises[executionEnv.nodeVersion]
|
||||
if (!nodePathPromise) {
|
||||
nodePathPromise = getNodeBinDir({
|
||||
...config,
|
||||
useNodeVersion: executionEnv.nodeVersion,
|
||||
})
|
||||
nodeFetchPromises[executionEnv.nodeVersion] = nodePathPromise
|
||||
}
|
||||
|
||||
return {
|
||||
extraBinPaths: [await nodePathPromise, ...extraBinPaths ?? []],
|
||||
}
|
||||
}
|
||||
|
||||
export async function getNodeBinDir (opts: NvmNodeCommandOptions): Promise<string> {
|
||||
const fetch = createFetchFromRegistry(opts)
|
||||
const nodesDir = getNodeVersionsBaseDir(opts.pnpmHomeDir)
|
||||
|
||||
16
env/plugin-commands-env/test/node.test.ts
vendored
16
env/plugin-commands-env/test/node.test.ts
vendored
@@ -2,7 +2,7 @@ import AdmZip from 'adm-zip'
|
||||
import { Response } from 'node-fetch'
|
||||
import path from 'path'
|
||||
import { Readable } from 'stream'
|
||||
import { node } from '@pnpm/plugin-commands-env'
|
||||
import { getNodeDir, getNodeBinDir, getNodeVersionsBaseDir, type NvmNodeCommandOptions } from '../lib/node'
|
||||
import { tempDir } from '@pnpm/prepare'
|
||||
|
||||
const fetchMock = jest.fn(async (url: string) => {
|
||||
@@ -28,7 +28,7 @@ beforeEach(() => {
|
||||
})
|
||||
|
||||
test('check API (placeholder test)', async () => {
|
||||
expect(typeof node.getNodeDir).toBe('function')
|
||||
expect(typeof getNodeDir).toBe('function')
|
||||
})
|
||||
|
||||
// TODO: unskip. The mock function should return a valid tarball
|
||||
@@ -37,7 +37,7 @@ test.skip('install Node uses node-mirror:release option', async () => {
|
||||
const configDir = path.resolve('config')
|
||||
|
||||
const nodeMirrorRelease = 'https://pnpm-node-mirror-test.localhost/download/release'
|
||||
const opts: node.NvmNodeCommandOptions = {
|
||||
const opts: NvmNodeCommandOptions = {
|
||||
bin: process.cwd(),
|
||||
configDir,
|
||||
global: true,
|
||||
@@ -48,7 +48,7 @@ test.skip('install Node uses node-mirror:release option', async () => {
|
||||
useNodeVersion: '16.4.0',
|
||||
}
|
||||
|
||||
await node.getNodeBinDir(opts)
|
||||
await getNodeBinDir(opts)
|
||||
|
||||
for (const call of fetchMock.mock.calls) {
|
||||
expect(call[0]).toMatch(nodeMirrorRelease)
|
||||
@@ -60,7 +60,7 @@ test.skip('install an rc version of Node.js', async () => {
|
||||
tempDir()
|
||||
const configDir = path.resolve('config')
|
||||
|
||||
const opts: node.NvmNodeCommandOptions = {
|
||||
const opts: NvmNodeCommandOptions = {
|
||||
bin: process.cwd(),
|
||||
configDir,
|
||||
global: true,
|
||||
@@ -69,7 +69,7 @@ test.skip('install an rc version of Node.js', async () => {
|
||||
useNodeVersion: 'rc/18.0.0-rc.3',
|
||||
}
|
||||
|
||||
await node.getNodeBinDir(opts)
|
||||
await getNodeBinDir(opts)
|
||||
|
||||
const platform = process.platform === 'win32' ? 'win' : process.platform
|
||||
const arch = process.arch
|
||||
@@ -80,7 +80,7 @@ test.skip('install an rc version of Node.js', async () => {
|
||||
})
|
||||
|
||||
test('get node version base dir', async () => {
|
||||
expect(typeof node.getNodeVersionsBaseDir).toBe('function')
|
||||
const versionDir = node.getNodeVersionsBaseDir(process.cwd())
|
||||
expect(typeof getNodeVersionsBaseDir).toBe('function')
|
||||
const versionDir = getNodeVersionsBaseDir(process.cwd())
|
||||
expect(versionDir).toBe(path.resolve(process.cwd(), 'nodejs'))
|
||||
})
|
||||
|
||||
3
env/plugin-commands-env/tsconfig.json
vendored
3
env/plugin-commands-env/tsconfig.json
vendored
@@ -24,6 +24,9 @@
|
||||
{
|
||||
"path": "../../packages/error"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/types"
|
||||
},
|
||||
{
|
||||
"path": "../../pkg-manager/remove-bins"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { lifecycleLogger } from '@pnpm/core-loggers'
|
||||
import { globalWarn } from '@pnpm/logger'
|
||||
import lifecycle from '@pnpm/npm-lifecycle'
|
||||
import { type DependencyManifest, type ProjectManifest } from '@pnpm/types'
|
||||
import { type DependencyManifest, type ProjectManifest, type PrepareExecutionEnv } from '@pnpm/types'
|
||||
import { PnpmError } from '@pnpm/error'
|
||||
import { existsSync } from 'fs'
|
||||
import isWindows from 'is-windows'
|
||||
@@ -24,6 +24,7 @@ export interface RunLifecycleHookOptions {
|
||||
shellEmulator?: boolean
|
||||
stdio?: string
|
||||
unsafePerm: boolean
|
||||
prepareExecutionEnv?: PrepareExecutionEnv
|
||||
}
|
||||
|
||||
export async function runLifecycleHook (
|
||||
@@ -94,13 +95,17 @@ Please unset the script-shell option, or configure it to a .exe instead.
|
||||
const logLevel = (opts.stdio !== 'inherit' || opts.silent)
|
||||
? 'silent'
|
||||
: undefined
|
||||
const extraBinPaths = (await opts.prepareExecutionEnv?.({
|
||||
extraBinPaths: opts.extraBinPaths,
|
||||
executionEnv: (manifest as ProjectManifest).pnpm?.executionEnv,
|
||||
}))?.extraBinPaths ?? opts.extraBinPaths
|
||||
await lifecycle(m, stage, opts.pkgRoot, {
|
||||
config: {
|
||||
...opts.rawConfig,
|
||||
'frozen-lockfile': false,
|
||||
},
|
||||
dir: opts.rootModulesDir,
|
||||
extraBinPaths: opts.extraBinPaths ?? [],
|
||||
extraBinPaths,
|
||||
extraEnv: {
|
||||
...opts.extraEnv,
|
||||
INIT_CWD: opts.initCwd ?? process.cwd(),
|
||||
|
||||
@@ -57,7 +57,7 @@ export async function runLifecycleHooksConcurrently (
|
||||
logger.warn({ message, prefix: rootDir })
|
||||
},
|
||||
})
|
||||
const runLifecycleHookOpts = {
|
||||
const runLifecycleHookOpts: RunLifecycleHookOptions = {
|
||||
...opts,
|
||||
depPath: rootDir,
|
||||
pkgRoot: rootDir,
|
||||
|
||||
@@ -6,7 +6,6 @@ import { OUTPUT_OPTIONS } from '@pnpm/common-cli-options-help'
|
||||
import { type Config, types } from '@pnpm/config'
|
||||
import { createBase32Hash } from '@pnpm/crypto.base32-hash'
|
||||
import { PnpmError } from '@pnpm/error'
|
||||
import { node } from '@pnpm/plugin-commands-env'
|
||||
import { add } from '@pnpm/plugin-commands-installation'
|
||||
import { readPackageJsonFromDir } from '@pnpm/read-package-json'
|
||||
import { getBinsFromPackageManifest } from '@pnpm/package-bins'
|
||||
@@ -65,7 +64,7 @@ export function help (): string {
|
||||
export type DlxCommandOptions = {
|
||||
package?: string[]
|
||||
shellMode?: boolean
|
||||
} & Pick<Config, 'reporter' | 'userAgent' | 'cacheDir' | 'dlxCacheMaxAge' | 'useNodeVersion' > & add.AddCommandOptions
|
||||
} & Pick<Config, 'extraBinPaths' | 'reporter' | 'userAgent' | 'cacheDir' | 'dlxCacheMaxAge' | 'useNodeVersion' > & add.AddCommandOptions
|
||||
|
||||
export async function handler (
|
||||
opts: DlxCommandOptions,
|
||||
@@ -95,12 +94,10 @@ export async function handler (
|
||||
}
|
||||
const modulesDir = path.join(cacheLink, 'node_modules')
|
||||
const binsDir = path.join(modulesDir, '.bin')
|
||||
const prependPaths = [binsDir]
|
||||
if (opts.useNodeVersion) {
|
||||
const nodePath = await node.getNodeBinDir(opts)
|
||||
prependPaths.push(nodePath)
|
||||
}
|
||||
const env = makeEnv({ userAgent: opts.userAgent, prependPaths })
|
||||
const env = makeEnv({
|
||||
userAgent: opts.userAgent,
|
||||
prependPaths: [binsDir, ...opts.extraBinPaths],
|
||||
})
|
||||
const binName = opts.package
|
||||
? command
|
||||
: await getBinName(modulesDir, await getPkgName(cacheLink))
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
tryReadProjectManifest,
|
||||
} from '@pnpm/cli-utils'
|
||||
import { type CompletionFunc } from '@pnpm/command'
|
||||
import { prepareExecutionEnv } from '@pnpm/plugin-commands-env'
|
||||
import { FILTERING, UNIVERSAL_OPTIONS } from '@pnpm/common-cli-options-help'
|
||||
import { type Config, types as allTypes } from '@pnpm/config'
|
||||
import { PnpmError } from '@pnpm/error'
|
||||
@@ -155,7 +156,7 @@ For options that may be used with `-r`, see "pnpm help recursive"',
|
||||
export type RunOpts =
|
||||
& Omit<RecursiveRunOpts, 'allProjects' | 'selectedProjectsGraph' | 'workspaceDir'>
|
||||
& { recursive?: boolean }
|
||||
& Pick<Config, 'dir' | 'engineStrict' | 'extraBinPaths' | 'reporter' | 'scriptsPrependNodePath' | 'scriptShell' | 'shellEmulator' | 'enablePrePostScripts' | 'userAgent' | 'extraEnv' | 'nodeOptions'>
|
||||
& Pick<Config, 'bin' | 'dir' | 'engineStrict' | 'extraBinPaths' | 'pnpmHomeDir' | 'reporter' | 'scriptsPrependNodePath' | 'scriptShell' | 'shellEmulator' | 'enablePrePostScripts' | 'userAgent' | 'extraEnv' | 'nodeOptions'>
|
||||
& (
|
||||
& { recursive?: false }
|
||||
& Partial<Pick<Config, 'allProjects' | 'selectedProjectsGraph' | 'workspaceDir'>>
|
||||
@@ -250,6 +251,10 @@ so you may run "pnpm -w run ${scriptName}"`,
|
||||
stdio: (specifiedScripts.length > 1 && concurrency > 1) ? 'pipe' : 'inherit',
|
||||
unsafePerm: true, // when running scripts explicitly, assume that they're trusted.
|
||||
}
|
||||
const executionEnv = manifest.pnpm?.executionEnv
|
||||
if (executionEnv != null) {
|
||||
lifecycleOpts.extraBinPaths = (await prepareExecutionEnv(opts, { executionEnv })).extraBinPaths
|
||||
}
|
||||
const existsPnp = existsInDir.bind(null, '.pnp.cjs')
|
||||
const pnpPath = (opts.workspaceDir && existsPnp(opts.workspaceDir)) ?? existsPnp(dir)
|
||||
if (pnpPath) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import path from 'path'
|
||||
import util from 'util'
|
||||
import { throwOnCommandFail } from '@pnpm/cli-utils'
|
||||
import { type Config } from '@pnpm/config'
|
||||
import { prepareExecutionEnv } from '@pnpm/plugin-commands-env'
|
||||
import { PnpmError } from '@pnpm/error'
|
||||
import {
|
||||
makeNodeRequireOption,
|
||||
@@ -20,8 +21,10 @@ import { tryBuildRegExpFromCommand } from './regexpCommand'
|
||||
import { type PackageScripts, type ProjectRootDir } from '@pnpm/types'
|
||||
|
||||
export type RecursiveRunOpts = Pick<Config,
|
||||
| 'bin'
|
||||
| 'enablePrePostScripts'
|
||||
| 'unsafePerm'
|
||||
| 'pnpmHomeDir'
|
||||
| 'rawConfig'
|
||||
| 'rootProjectManifest'
|
||||
| 'scriptsPrependNodePath'
|
||||
@@ -121,6 +124,10 @@ export async function runRecursive (
|
||||
stdio,
|
||||
unsafePerm: true, // when running scripts explicitly, assume that they're trusted.
|
||||
}
|
||||
const { executionEnv } = pkg.package.manifest.pnpm ?? {}
|
||||
if (executionEnv != null) {
|
||||
lifecycleOpts.extraBinPaths = (await prepareExecutionEnv(opts, { executionEnv })).extraBinPaths
|
||||
}
|
||||
const pnpPath = workspacePnpPath ?? existsPnp(prefix)
|
||||
if (pnpPath) {
|
||||
lifecycleOpts.extraEnv = {
|
||||
|
||||
@@ -29,18 +29,22 @@ test('pnpm run: returns correct exit code', async () => {
|
||||
})
|
||||
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
}, ['exit0'])
|
||||
|
||||
let err!: Error & { errno: number }
|
||||
try {
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
}, ['exit1'])
|
||||
} catch (_err: any) { // eslint-disable-line
|
||||
@@ -59,10 +63,12 @@ test('pnpm run --no-bail never fails', async () => {
|
||||
fs.writeFileSync('recordArgs.js', RECORD_ARGS_FILE, 'utf8')
|
||||
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
bail: false,
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
}, ['exit1'])
|
||||
|
||||
@@ -84,9 +90,11 @@ test('run: pass the args to the command that is specified in the build script',
|
||||
fs.writeFileSync('recordArgs.js', RECORD_ARGS_FILE, 'utf8')
|
||||
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
}, ['foo', 'arg', '--flag=true', '--help', '-h'])
|
||||
|
||||
@@ -106,9 +114,11 @@ test('run: pass the args to the command that is specified in the build script of
|
||||
fs.writeFileSync('recordArgs.js', RECORD_ARGS_FILE, 'utf8')
|
||||
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
}, ['foo', 'arg', '--flag=true', '--help', '-h'])
|
||||
|
||||
@@ -128,9 +138,11 @@ test('test: pass the args to the command that is specified in the build script o
|
||||
fs.writeFileSync('recordArgs.js', RECORD_ARGS_FILE, 'utf8')
|
||||
|
||||
await testCommand.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
}, ['arg', '--flag=true', '--help', '-h'])
|
||||
|
||||
@@ -150,9 +162,11 @@ test('run start: pass the args to the command that is specified in the build scr
|
||||
fs.writeFileSync('recordArgs.js', RECORD_ARGS_FILE, 'utf8')
|
||||
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
}, ['start', 'arg', '--flag=true', '--help', '-h'])
|
||||
|
||||
@@ -172,9 +186,11 @@ test('run stop: pass the args to the command that is specified in the build scri
|
||||
fs.writeFileSync('recordArgs.js', RECORD_ARGS_FILE, 'utf8')
|
||||
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
}, ['stop', 'arg', '--flag=true', '--help', '-h'])
|
||||
|
||||
@@ -202,9 +218,11 @@ test('restart: run stop, restart and start', async () => {
|
||||
})
|
||||
|
||||
await restart.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
}, [])
|
||||
|
||||
@@ -235,10 +253,12 @@ test('restart: run stop, restart and start and all the pre/post scripts', async
|
||||
})
|
||||
|
||||
await restart.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
enablePrePostScripts: true,
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
}, [])
|
||||
|
||||
@@ -264,9 +284,11 @@ test('"pnpm run" prints the list of available commands', async () => {
|
||||
})
|
||||
|
||||
const output = await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
}, [])
|
||||
|
||||
@@ -310,9 +332,11 @@ test('"pnpm run" prints the list of available commands, including commands of th
|
||||
process.chdir('foo')
|
||||
const output = await run.handler({
|
||||
allProjects,
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
selectedProjectsGraph,
|
||||
workspaceDir,
|
||||
@@ -336,10 +360,12 @@ Commands of the root workspace project (to run them, use "pnpm -w run"):
|
||||
{
|
||||
process.chdir('..')
|
||||
const output = await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
allProjects,
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
selectedProjectsGraph,
|
||||
workspaceDir,
|
||||
@@ -360,10 +386,12 @@ test('pnpm run does not fail with --if-present even if the wanted script is not
|
||||
prepare({})
|
||||
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
ifPresent: true,
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
}, ['build'])
|
||||
})
|
||||
@@ -427,9 +455,11 @@ test('scripts work with PnP', async () => {
|
||||
},
|
||||
})
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
}, ['foo'])
|
||||
|
||||
@@ -461,9 +491,11 @@ skipOnWindows('pnpm run with custom shell', async () => {
|
||||
])
|
||||
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
scriptShell: path.resolve('node_modules/.bin/shell-mock'),
|
||||
}, ['build'])
|
||||
@@ -490,9 +522,11 @@ onlyOnWindows('pnpm shows error if script-shell is .cmd', async () => {
|
||||
|
||||
async function runScript () {
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
scriptShell: path.resolve('node_modules/.bin/shell-mock.cmd'),
|
||||
}, ['build'])
|
||||
@@ -518,9 +552,11 @@ test('pnpm run with RegExp script selector should work', async () => {
|
||||
})
|
||||
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
}, ['/^(lint|build):.*/'])
|
||||
|
||||
@@ -542,9 +578,11 @@ test('pnpm run with RegExp script selector should work also for pre/post script'
|
||||
})
|
||||
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
enablePrePostScripts: true,
|
||||
}, ['/build:.*/'])
|
||||
@@ -565,9 +603,11 @@ test('pnpm run with RegExp script selector should work parallel as a default beh
|
||||
})
|
||||
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
}, ['/build:.*/'])
|
||||
|
||||
@@ -589,9 +629,11 @@ test('pnpm run with RegExp script selector should work sequentially with --works
|
||||
})
|
||||
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
workspaceConcurrency: 1,
|
||||
}, ['/build:.*/'])
|
||||
@@ -616,9 +658,11 @@ test('pnpm run with RegExp script selector with flag should throw error', async
|
||||
let err!: Error
|
||||
try {
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
workspaceConcurrency: 1,
|
||||
}, ['/build:.*/i'])
|
||||
@@ -637,9 +681,11 @@ test('pnpm run with slightly incorrect command suggests correct one', async () =
|
||||
|
||||
// cspell:ignore buil
|
||||
await expect(run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
workspaceConcurrency: 1,
|
||||
}, ['buil'])).rejects.toEqual(expect.objectContaining({
|
||||
@@ -656,11 +702,54 @@ test('pnpm run with custom node-options', async () => {
|
||||
})
|
||||
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {},
|
||||
nodeOptions: '--max-old-space-size=1200',
|
||||
workspaceConcurrency: 1,
|
||||
}, ['build'])
|
||||
})
|
||||
|
||||
test('pnpm run without node version', async () => {
|
||||
prepare({
|
||||
scripts: {
|
||||
'assert-node-version': `node -e "assert.equal(process.version, '${process.version}')"`,
|
||||
},
|
||||
})
|
||||
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: process.cwd(),
|
||||
rawConfig: {},
|
||||
workspaceConcurrency: 1,
|
||||
}, ['assert-node-version'])
|
||||
})
|
||||
|
||||
test('pnpm run with node version', async () => {
|
||||
prepare({
|
||||
scripts: {
|
||||
'assert-node-version': 'node -e "assert.equal(process.version, \'v20.0.0\')"',
|
||||
},
|
||||
pnpm: {
|
||||
executionEnv: {
|
||||
nodeVersion: '20.0.0',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
await run.handler({
|
||||
bin: 'node_modules/.bin',
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
extraEnv: {},
|
||||
pnpmHomeDir: process.cwd(),
|
||||
rawConfig: {},
|
||||
workspaceConcurrency: 1,
|
||||
}, ['assert-node-version'])
|
||||
})
|
||||
|
||||
@@ -10,6 +10,7 @@ export const DEFAULT_OPTS = {
|
||||
original: [],
|
||||
},
|
||||
bail: false,
|
||||
bin: 'node_modules/.bin',
|
||||
ca: undefined,
|
||||
cacheDir: '../cache',
|
||||
cert: undefined,
|
||||
@@ -66,6 +67,7 @@ export const DLX_DEFAULT_OPTS = {
|
||||
bin: 'node_modules/.bin',
|
||||
cacheDir: path.join(tmp, 'cache'),
|
||||
extraEnv: {},
|
||||
extraBinPaths: [],
|
||||
cliOptions: {},
|
||||
dlxCacheMaxAge: Infinity,
|
||||
include: {
|
||||
|
||||
14
packages/types/src/env.ts
Normal file
14
packages/types/src/env.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export interface PrepareExecutionEnvOptions {
|
||||
extraBinPaths?: string[]
|
||||
executionEnv: ExecutionEnv | undefined
|
||||
}
|
||||
|
||||
export interface PrepareExecutionEnvResult {
|
||||
extraBinPaths: string[]
|
||||
}
|
||||
|
||||
export type PrepareExecutionEnv = (options: PrepareExecutionEnvOptions) => Promise<PrepareExecutionEnvResult>
|
||||
|
||||
export interface ExecutionEnv {
|
||||
nodeVersion?: string
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './env'
|
||||
export * from './misc'
|
||||
export * from './options'
|
||||
export * from './package'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { type ExecutionEnv } from './env'
|
||||
|
||||
export type Dependencies = Record<string, string>
|
||||
|
||||
export type PackageBin = string | { [commandName: string]: string }
|
||||
@@ -146,6 +148,7 @@ export interface ProjectManifest extends BaseManifest {
|
||||
}
|
||||
requiredScripts?: string[]
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
executionEnv?: ExecutionEnv
|
||||
}
|
||||
private?: boolean
|
||||
resolutions?: Record<string, string>
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
type PackageExtension,
|
||||
type ReadPackageHook,
|
||||
type Registries,
|
||||
type PrepareExecutionEnv,
|
||||
} from '@pnpm/types'
|
||||
import { pnpmPkgJson } from '../pnpmPkgJson'
|
||||
import { type ReporterFunction } from '../types'
|
||||
@@ -151,6 +152,7 @@ export interface StrictInstallOptions {
|
||||
hoistWorkspacePackages?: boolean
|
||||
virtualStoreDirMaxLength: number
|
||||
peersSuffixMaxLength: number
|
||||
prepareExecutionEnv?: PrepareExecutionEnv
|
||||
}
|
||||
|
||||
export type InstallOptions =
|
||||
|
||||
@@ -311,6 +311,7 @@ export async function mutateModules (
|
||||
stdio: opts.ownLifecycleHooksStdio,
|
||||
storeController: opts.storeController,
|
||||
unsafePerm: opts.unsafePerm || false,
|
||||
prepareExecutionEnv: opts.prepareExecutionEnv,
|
||||
}
|
||||
|
||||
if (!opts.ignoreScripts && !opts.ignorePackageManifest && rootProjectManifest?.scripts?.[DEV_PREINSTALL]) {
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
"@pnpm/outdated": "workspace:*",
|
||||
"@pnpm/package-store": "workspace:*",
|
||||
"@pnpm/parse-wanted-dependency": "workspace:*",
|
||||
"@pnpm/plugin-commands-env": "workspace:*",
|
||||
"@pnpm/plugin-commands-rebuild": "workspace:*",
|
||||
"@pnpm/pnpmfile": "workspace:*",
|
||||
"@pnpm/read-project-manifest": "workspace:*",
|
||||
|
||||
@@ -2,6 +2,7 @@ import { docsUrl } from '@pnpm/cli-utils'
|
||||
import { FILTERING, OPTIONS, UNIVERSAL_OPTIONS } from '@pnpm/common-cli-options-help'
|
||||
import { types as allTypes } from '@pnpm/config'
|
||||
import { PnpmError } from '@pnpm/error'
|
||||
import { prepareExecutionEnv } from '@pnpm/plugin-commands-env'
|
||||
import pick from 'ramda/src/pick'
|
||||
import renderHelp from 'render-help'
|
||||
import { type InstallCommandOptions } from './install'
|
||||
@@ -207,5 +208,6 @@ export async function handler (
|
||||
...opts,
|
||||
include,
|
||||
includeDirect: include,
|
||||
prepareExecutionEnv: prepareExecutionEnv.bind(null, opts),
|
||||
}, params)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { docsUrl } from '@pnpm/cli-utils'
|
||||
import { OPTIONS, UNIVERSAL_OPTIONS } from '@pnpm/common-cli-options-help'
|
||||
import { dedupeDiffCheck } from '@pnpm/dedupe.check'
|
||||
import { prepareExecutionEnv } from '@pnpm/plugin-commands-env'
|
||||
import renderHelp from 'render-help'
|
||||
import { type InstallCommandOptions, rcOptionsTypes as installCommandRcOptionsTypes } from './install'
|
||||
import { installDeps } from './installDeps'
|
||||
@@ -63,5 +64,6 @@ export async function handler (opts: DedupeCommandOptions): Promise<void> {
|
||||
include,
|
||||
includeDirect: include,
|
||||
lockfileCheck: opts.check ? dedupeDiffCheck : undefined,
|
||||
prepareExecutionEnv: prepareExecutionEnv.bind(null, opts),
|
||||
}, [])
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { docsUrl } from '@pnpm/cli-utils'
|
||||
import { FILTERING, OPTIONS, OUTPUT_OPTIONS, UNIVERSAL_OPTIONS } from '@pnpm/common-cli-options-help'
|
||||
import { type Config, types as allTypes } from '@pnpm/config'
|
||||
import { WANTED_LOCKFILE } from '@pnpm/constants'
|
||||
import { prepareExecutionEnv } from '@pnpm/plugin-commands-env'
|
||||
import { type CreateStoreControllerOptions } from '@pnpm/store-connection-manager'
|
||||
import { isCI } from 'ci-info'
|
||||
import pick from 'ramda/src/pick'
|
||||
@@ -329,6 +330,7 @@ export async function handler (opts: InstallCommandOptions): Promise<void> {
|
||||
typeof opts.rawLocalConfig['prefer-frozen-lockfile'] === 'undefined',
|
||||
include,
|
||||
includeDirect: include,
|
||||
prepareExecutionEnv: prepareExecutionEnv.bind(null, opts),
|
||||
}
|
||||
if (opts.resolutionOnly) {
|
||||
installDepsOptions.lockfileOnly = true
|
||||
|
||||
@@ -12,7 +12,7 @@ import { findWorkspacePackages } from '@pnpm/workspace.find-packages'
|
||||
import { type Lockfile } from '@pnpm/lockfile-types'
|
||||
import { rebuildProjects } from '@pnpm/plugin-commands-rebuild'
|
||||
import { createOrConnectStoreController, type CreateStoreControllerOptions } from '@pnpm/store-connection-manager'
|
||||
import { type IncludedDependencies, type Project, type ProjectsGraph, type ProjectRootDir } from '@pnpm/types'
|
||||
import { type IncludedDependencies, type Project, type ProjectsGraph, type ProjectRootDir, type PrepareExecutionEnv } from '@pnpm/types'
|
||||
import {
|
||||
install,
|
||||
mutateModulesInSingleProject,
|
||||
@@ -115,6 +115,7 @@ export type InstallDepsOptions = Pick<Config,
|
||||
dedupe?: boolean
|
||||
workspace?: boolean
|
||||
includeOnlyPackageFiles?: boolean
|
||||
prepareExecutionEnv: PrepareExecutionEnv
|
||||
} & Partial<Pick<Config, 'pnpmHomeDir'>>
|
||||
|
||||
export async function installDeps (
|
||||
|
||||
@@ -10,6 +10,7 @@ import { globalInfo } from '@pnpm/logger'
|
||||
import { createMatcher } from '@pnpm/matcher'
|
||||
import { outdatedDepsOfProjects } from '@pnpm/outdated'
|
||||
import { PnpmError } from '@pnpm/error'
|
||||
import { prepareExecutionEnv } from '@pnpm/plugin-commands-env'
|
||||
import { type IncludedDependencies, type ProjectRootDir } from '@pnpm/types'
|
||||
import { prompt } from 'enquirer'
|
||||
import chalk from 'chalk'
|
||||
@@ -304,6 +305,7 @@ async function update (
|
||||
: undefined,
|
||||
updatePackageManifest: opts.save !== false,
|
||||
resolutionMode: opts.save === false ? 'highest' : opts.resolutionMode,
|
||||
prepareExecutionEnv: prepareExecutionEnv.bind(null, opts),
|
||||
}, dependencies)
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
{
|
||||
"path": "../../dedupe/check"
|
||||
},
|
||||
{
|
||||
"path": "../../env/plugin-commands-env"
|
||||
},
|
||||
{
|
||||
"path": "../../exec/plugin-commands-rebuild"
|
||||
},
|
||||
|
||||
53
pnpm-lock.yaml
generated
53
pnpm-lock.yaml
generated
@@ -55,8 +55,8 @@ catalogs:
|
||||
specifier: 0.0.0
|
||||
version: 0.0.0
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 3.34.0
|
||||
version: 3.34.0
|
||||
specifier: 3.36.1
|
||||
version: 3.36.1
|
||||
'@pnpm/semver-diff':
|
||||
specifier: ^1.1.0
|
||||
version: 1.1.0
|
||||
@@ -709,7 +709,7 @@ importers:
|
||||
version: 1.0.0
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/tsconfig':
|
||||
specifier: workspace:*
|
||||
version: link:__utils__/tsconfig
|
||||
@@ -821,7 +821,7 @@ importers:
|
||||
version: link:../../pkg-manager/modules-yaml
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/types':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/types
|
||||
@@ -855,7 +855,7 @@ importers:
|
||||
dependencies:
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/store.cafs':
|
||||
specifier: workspace:*
|
||||
version: link:../../store/cafs
|
||||
@@ -1711,6 +1711,9 @@ importers:
|
||||
'@pnpm/store-path':
|
||||
specifier: workspace:*
|
||||
version: link:../../store/store-path
|
||||
'@pnpm/types':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/types
|
||||
'@zkochan/cmd-shim':
|
||||
specifier: 'catalog:'
|
||||
version: 6.0.0
|
||||
@@ -2018,7 +2021,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-fixtures':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-fixtures
|
||||
@@ -2148,7 +2151,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-ipc-server':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-ipc-server
|
||||
@@ -3684,7 +3687,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-fixtures':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-fixtures
|
||||
@@ -3962,7 +3965,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/store-path':
|
||||
specifier: workspace:*
|
||||
version: link:../../store/store-path
|
||||
@@ -4247,7 +4250,7 @@ importers:
|
||||
version: link:../read-projects-context
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/store-path':
|
||||
specifier: workspace:*
|
||||
version: link:../../store/store-path
|
||||
@@ -4607,7 +4610,7 @@ importers:
|
||||
version: 'link:'
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-fixtures':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-fixtures
|
||||
@@ -4701,6 +4704,9 @@ importers:
|
||||
'@pnpm/parse-wanted-dependency':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/parse-wanted-dependency
|
||||
'@pnpm/plugin-commands-env':
|
||||
specifier: workspace:*
|
||||
version: link:../../env/plugin-commands-env
|
||||
'@pnpm/plugin-commands-rebuild':
|
||||
specifier: workspace:*
|
||||
version: link:../../exec/plugin-commands-rebuild
|
||||
@@ -4800,7 +4806,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-fixtures':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-fixtures
|
||||
@@ -5393,7 +5399,7 @@ importers:
|
||||
version: link:../pkg-manifest/read-project-manifest
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/run-npm':
|
||||
specifier: workspace:*
|
||||
version: link:../exec/run-npm
|
||||
@@ -5659,7 +5665,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/workspace.filter-packages-from-dir':
|
||||
specifier: workspace:*
|
||||
version: link:../../workspace/filter-packages-from-dir
|
||||
@@ -5708,6 +5714,9 @@ importers:
|
||||
'@pnpm/pick-registry-for-package':
|
||||
specifier: workspace:*
|
||||
version: link:../../config/pick-registry-for-package
|
||||
'@pnpm/plugin-commands-env':
|
||||
specifier: workspace:*
|
||||
version: link:../../env/plugin-commands-env
|
||||
'@pnpm/resolver-base':
|
||||
specifier: workspace:*
|
||||
version: link:../../resolving/resolver-base
|
||||
@@ -5765,7 +5774,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-ipc-server':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-ipc-server
|
||||
@@ -6334,7 +6343,7 @@ importers:
|
||||
version: link:../../pkg-manifest/read-package-json
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-fixtures':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-fixtures
|
||||
@@ -6401,7 +6410,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/workspace.filter-packages-from-dir':
|
||||
specifier: workspace:*
|
||||
version: link:../../workspace/filter-packages-from-dir
|
||||
@@ -6492,7 +6501,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-fixtures':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-fixtures
|
||||
@@ -6830,7 +6839,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 3.34.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 3.36.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@types/archy':
|
||||
specifier: 'catalog:'
|
||||
version: 0.0.33
|
||||
@@ -8411,8 +8420,8 @@ packages:
|
||||
resolution: {integrity: sha512-MDXuQpYFbabSXzAnqP7VIQqBx5Z1fzOhzB/3YmIXJ+tE7Wue//IR3itMSYlWeaFLo1G5PCJklM2zBdvggRw1nw==}
|
||||
engines: {node: '>=16.14'}
|
||||
|
||||
'@pnpm/registry-mock@3.34.0':
|
||||
resolution: {integrity: sha512-/wANbfGLun8u/ojrvzDJEJjROBcB/ZQMhrufmvV96Yk0VjR2RQ9dXoNrw0BlPyNRYUgG8Hj3Xl9RdZGQW31DYA==}
|
||||
'@pnpm/registry-mock@3.36.1':
|
||||
resolution: {integrity: sha512-WYhOXo3y+YmgzigBeFhcW5VPdUZGfFp/7Ilz0NQ8Vi3xweL8glc6/rDTqvcr0VpckBulq/WKAB3wivoAGnS/tA==}
|
||||
engines: {node: '>=10.13'}
|
||||
hasBin: true
|
||||
|
||||
@@ -15236,7 +15245,7 @@ snapshots:
|
||||
sort-keys: 4.2.0
|
||||
strip-bom: 4.0.0
|
||||
|
||||
'@pnpm/registry-mock@3.34.0(encoding@0.1.13)(typanion@3.14.0)':
|
||||
'@pnpm/registry-mock@3.36.1(encoding@0.1.13)(typanion@3.14.0)':
|
||||
dependencies:
|
||||
anonymous-npm-registry-client: 0.2.0
|
||||
execa: 5.1.1
|
||||
|
||||
@@ -51,7 +51,7 @@ catalog:
|
||||
"@pnpm/npm-package-arg": ^1.0.0
|
||||
"@pnpm/os.env.path-extender": ^2.0.0
|
||||
"@pnpm/patch-package": 0.0.0
|
||||
"@pnpm/registry-mock": 3.34.0
|
||||
"@pnpm/registry-mock": 3.36.1
|
||||
"@pnpm/semver-diff": ^1.1.0
|
||||
"@pnpm/tabtab": ^0.5.4
|
||||
"@pnpm/util.lex-comparator": 3.0.0
|
||||
|
||||
@@ -12,7 +12,7 @@ import { executionTimeLogger, scopeLogger } from '@pnpm/core-loggers'
|
||||
import { filterPackagesFromDir } from '@pnpm/filter-workspace-packages'
|
||||
import { globalWarn, logger } from '@pnpm/logger'
|
||||
import { type ParsedCliArgs } from '@pnpm/parse-cli-args'
|
||||
import { node } from '@pnpm/plugin-commands-env'
|
||||
import { prepareExecutionEnv } from '@pnpm/plugin-commands-env'
|
||||
import { finishWorkers } from '@pnpm/worker'
|
||||
import chalk from 'chalk'
|
||||
import { checkForUpdates } from './checkForUpdates'
|
||||
@@ -274,8 +274,9 @@ export async function main (inputArgv: string[]): Promise<void> {
|
||||
if ('webcontainer' in process.versions) {
|
||||
globalWarn('Automatic installation of different Node.js versions is not supported in WebContainer')
|
||||
} else {
|
||||
const nodePath = await node.getNodeBinDir(config)
|
||||
config.extraBinPaths.push(nodePath)
|
||||
config.extraBinPaths = (
|
||||
await prepareExecutionEnv(config, { executionEnv: { nodeVersion: config.useNodeVersion } })
|
||||
).extraBinPaths
|
||||
config.nodeVersion = config.useNodeVersion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { prepare } from '@pnpm/prepare'
|
||||
import { prepare, preparePackages } from '@pnpm/prepare'
|
||||
import { type PackageManifest } from '@pnpm/types'
|
||||
import { sync as rimraf } from '@zkochan/rimraf'
|
||||
import PATH from 'path-name'
|
||||
import loadJsonFile from 'load-json-file'
|
||||
import { execPnpmSync } from '../utils'
|
||||
import writeYamlFile from 'write-yaml-file'
|
||||
import { execPnpm, execPnpmSync } from '../utils'
|
||||
|
||||
const pkgRoot = path.join(__dirname, '..', '..')
|
||||
const pnpmPkg = loadJsonFile.sync<PackageManifest>(path.join(pkgRoot, 'package.json'))
|
||||
@@ -163,3 +164,90 @@ test('selectively allow scripts in some dependencies by onlyBuiltDependenciesFil
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/install-script-example/generated-by-install.js')).toBeTruthy()
|
||||
})
|
||||
|
||||
test('use node versions specified by pnpm.executionEnv.nodeVersion in workspace packages', async () => {
|
||||
const projects = preparePackages([
|
||||
{
|
||||
location: '.',
|
||||
package: {
|
||||
name: 'root',
|
||||
version: '1.0.0',
|
||||
private: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'node-version-undefined',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
install: 'node -v > node-version.txt',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'node-version-18',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
install: 'node -v > node-version.txt',
|
||||
},
|
||||
pnpm: {
|
||||
executionEnv: {
|
||||
nodeVersion: '18.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'node-version-20',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
install: 'node -v > node-version.txt',
|
||||
},
|
||||
pnpm: {
|
||||
executionEnv: {
|
||||
nodeVersion: '20.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
await writeYamlFile(path.resolve('pnpm-workspace.yaml'), {
|
||||
packages: ['*'],
|
||||
})
|
||||
|
||||
execPnpmSync(['install'])
|
||||
expect(
|
||||
['node-version-undefined', 'node-version-18', 'node-version-20'].map(name => {
|
||||
const filePath = path.join(projects[name].dir(), 'node-version.txt')
|
||||
return fs.readFileSync(filePath, 'utf-8').trim()
|
||||
})
|
||||
).toStrictEqual([process.version, 'v18.0.0', 'v20.0.0'])
|
||||
|
||||
execPnpmSync(['--config.use-node-version=19.0.0', 'install'])
|
||||
expect(
|
||||
['node-version-undefined', 'node-version-18', 'node-version-20'].map(name => {
|
||||
const filePath = path.join(projects[name].dir(), 'node-version.txt')
|
||||
return fs.readFileSync(filePath, 'utf-8').trim()
|
||||
})
|
||||
).toStrictEqual(['v19.0.0', 'v18.0.0', 'v20.0.0'])
|
||||
})
|
||||
|
||||
test('ignores pnpm.executionEnv specified by dependencies', async () => {
|
||||
prepare({
|
||||
name: 'ignores-pnpm-use-node-version-from-dependencies',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
// this package's package.json has pnpm.executionEnv.nodeVersion = '20.0.0'
|
||||
'@pnpm.e2e/has-execution-env': '1.0.0',
|
||||
},
|
||||
})
|
||||
|
||||
await execPnpm(['install'])
|
||||
|
||||
const nodeInfoFile = path.resolve('node_modules', '@pnpm.e2e', 'has-execution-env', 'node-info.json')
|
||||
const nodeInfoJson = fs.readFileSync(nodeInfoFile, 'utf-8')
|
||||
const nodeInfo = JSON.parse(nodeInfoJson)
|
||||
|
||||
// pnpm should still use system's Node.js to execute the install script despite pnpm.executionEnv.nodeVersion specified by the dependency
|
||||
expect(nodeInfo).toMatchObject({
|
||||
execPath: process.execPath,
|
||||
versions: process.versions,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -232,3 +232,61 @@ test('--reporter-hide-prefix should hide workspace prefix', async () => {
|
||||
expect(output).toContain('2')
|
||||
expect(output).not.toContain('script2: 2')
|
||||
})
|
||||
|
||||
test('recursive run when some packages define different node versions', async () => {
|
||||
preparePackages([
|
||||
{
|
||||
name: 'node-version-undefined',
|
||||
scripts: {
|
||||
'print-node-version': 'node -v',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'node-version-18',
|
||||
scripts: {
|
||||
'print-node-version': 'node -v',
|
||||
},
|
||||
pnpm: {
|
||||
executionEnv: {
|
||||
nodeVersion: '18.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'node-version-20',
|
||||
scripts: {
|
||||
'print-node-version': 'node -v',
|
||||
},
|
||||
pnpm: {
|
||||
executionEnv: {
|
||||
nodeVersion: '20.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const runPrintNodeVersion = (args: string[]) =>
|
||||
execPnpmSync(args)
|
||||
.stdout
|
||||
.toString()
|
||||
.trim()
|
||||
.split('\n')
|
||||
.filter(x => /v[0-9]+\.[0-9]+\.[0-9]+/.test(x))
|
||||
.sort()
|
||||
|
||||
expect(
|
||||
runPrintNodeVersion(['run', '-r', 'print-node-version'])
|
||||
).toStrictEqual([
|
||||
'node-version-18 print-node-version: v18.0.0',
|
||||
'node-version-20 print-node-version: v20.0.0',
|
||||
`node-version-undefined print-node-version: ${process.version}`,
|
||||
])
|
||||
|
||||
expect(
|
||||
runPrintNodeVersion(['run', '-r', '--use-node-version=19.0.0', 'print-node-version'])
|
||||
).toStrictEqual([
|
||||
'node-version-18 print-node-version: v18.0.0',
|
||||
'node-version-20 print-node-version: v20.0.0',
|
||||
'node-version-undefined print-node-version: v19.0.0',
|
||||
])
|
||||
})
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
"@pnpm/network.auth-header": "workspace:*",
|
||||
"@pnpm/package-bins": "workspace:*",
|
||||
"@pnpm/pick-registry-for-package": "workspace:*",
|
||||
"@pnpm/plugin-commands-env": "workspace:*",
|
||||
"@pnpm/resolver-base": "workspace:*",
|
||||
"@pnpm/run-npm": "workspace:*",
|
||||
"@pnpm/sort-packages": "workspace:*",
|
||||
|
||||
@@ -9,6 +9,7 @@ import { runNpm } from '@pnpm/run-npm'
|
||||
import { type ProjectManifest } from '@pnpm/types'
|
||||
import { getCurrentBranch, isGitRepo, isRemoteHistoryClean, isWorkingTreeClean } from '@pnpm/git-utils'
|
||||
import { loadToken } from '@pnpm/network.auth-header'
|
||||
import { prepareExecutionEnv } from '@pnpm/plugin-commands-env'
|
||||
import { prompt } from 'enquirer'
|
||||
import rimraf from '@zkochan/rimraf'
|
||||
import pick from 'ramda/src/pick'
|
||||
@@ -119,7 +120,7 @@ export async function handler (
|
||||
engineStrict?: boolean
|
||||
recursive?: boolean
|
||||
workspaceDir?: string
|
||||
} & Pick<Config, 'allProjects' | 'gitChecks' | 'ignoreScripts' | 'publishBranch' | 'embedReadme'>,
|
||||
} & Pick<Config, 'allProjects' | 'bin' | 'gitChecks' | 'ignoreScripts' | 'pnpmHomeDir' | 'publishBranch' | 'embedReadme'>,
|
||||
params: string[]
|
||||
): Promise<{ exitCode?: number } | undefined> {
|
||||
const result = await publish(opts, params)
|
||||
@@ -140,7 +141,7 @@ export async function publish (
|
||||
engineStrict?: boolean
|
||||
recursive?: boolean
|
||||
workspaceDir?: string
|
||||
} & Pick<Config, 'allProjects' | 'gitChecks' | 'ignoreScripts' | 'publishBranch' | 'embedReadme' | 'packGzipLevel'>,
|
||||
} & Pick<Config, 'allProjects' | 'bin' | 'gitChecks' | 'ignoreScripts' | 'pnpmHomeDir' | 'publishBranch' | 'embedReadme' | 'packGzipLevel'>,
|
||||
params: string[]
|
||||
): Promise<PublishResult> {
|
||||
if (opts.gitChecks !== false && await isGitRepo()) {
|
||||
@@ -220,6 +221,7 @@ Do you want to continue?`,
|
||||
rootModulesDir: await realpathMissing(path.join(dir, 'node_modules')),
|
||||
stdio: 'inherit',
|
||||
unsafePerm: true, // when running scripts explicitly, assume that they're trusted.
|
||||
prepareExecutionEnv: prepareExecutionEnv.bind(null, opts),
|
||||
})
|
||||
const { manifest } = await readProjectManifest(dir, opts)
|
||||
// Unfortunately, we cannot support postpack at the moment
|
||||
|
||||
@@ -12,9 +12,11 @@ import writeJsonFile from 'write-json-file'
|
||||
import { publish } from './publish'
|
||||
|
||||
export type PublishRecursiveOpts = Required<Pick<Config,
|
||||
| 'bin'
|
||||
| 'cacheDir'
|
||||
| 'cliOptions'
|
||||
| 'dir'
|
||||
| 'pnpmHomeDir'
|
||||
| 'rawConfig'
|
||||
| 'registries'
|
||||
| 'workspaceDir'
|
||||
|
||||
@@ -310,3 +310,57 @@ test('when publish some package throws an error, exit code should be non-zero',
|
||||
|
||||
expect(result?.exitCode).toBe(1)
|
||||
})
|
||||
|
||||
test('recursive publish runs script with Node.js version specified by pnpm.executionEnv.nodeVersion', async () => {
|
||||
preparePackages([
|
||||
{
|
||||
name: 'test-publish-node-version-undefined',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
prepublishOnly: 'node -v > node-version.txt',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'test-publish-node-version-18',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
prepublishOnly: 'node -v > node-version.txt',
|
||||
},
|
||||
pnpm: {
|
||||
executionEnv: {
|
||||
nodeVersion: '18.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'test-publish-node-version-20',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
prepublishOnly: 'node -v > node-version.txt',
|
||||
},
|
||||
pnpm: {
|
||||
executionEnv: {
|
||||
nodeVersion: '20.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
fs.writeFileSync('.npmrc', CREDENTIALS, 'utf8')
|
||||
|
||||
await publish.handler({
|
||||
...DEFAULT_OPTS,
|
||||
...await filterPackagesFromDir(process.cwd(), []),
|
||||
dir: process.cwd(),
|
||||
dryRun: true,
|
||||
pnpmHomeDir: process.cwd(),
|
||||
recursive: true,
|
||||
}, [])
|
||||
|
||||
expect(
|
||||
['undefined', '18', '20']
|
||||
.map(suffix => `test-publish-node-version-${suffix}`)
|
||||
.map(name => path.resolve(name, 'node-version.txt'))
|
||||
.map(nodeVersionFile => fs.readFileSync(nodeVersionFile, 'utf-8').trim())
|
||||
).toStrictEqual([process.version, 'v18.0.0', 'v20.0.0'])
|
||||
})
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
{
|
||||
"path": "../../config/pick-registry-for-package"
|
||||
},
|
||||
{
|
||||
"path": "../../env/plugin-commands-env"
|
||||
},
|
||||
{
|
||||
"path": "../../exec/lifecycle"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user