mirror of
https://github.com/pnpm/pnpm.git
synced 2026-01-09 15:38:39 -05:00
fix: pnpm exec should use the right Node.js version (#3477)
This commit is contained in:
5
.changeset/early-rockets-beg.md
Normal file
5
.changeset/early-rockets-beg.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-nvm": minor
|
||||
---
|
||||
|
||||
Remove the `pnpm node [args...]` command.
|
||||
5
.changeset/great-ants-punch.md
Normal file
5
.changeset/great-ants-punch.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-script-runners": patch
|
||||
---
|
||||
|
||||
`pnpm exec` should add `node_modules/.bin` to the PATH.
|
||||
5
.changeset/stale-emus-chew.md
Normal file
5
.changeset/stale-emus-chew.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-script-runners": patch
|
||||
---
|
||||
|
||||
`pnpm exec` should add the Node.js location to the PATH.
|
||||
@@ -29,18 +29,14 @@
|
||||
},
|
||||
"homepage": "https://github.com/pnpm/pnpm/blob/master/packages/plugin-commands-nvm#readme",
|
||||
"dependencies": {
|
||||
"@pnpm/cli-utils": "workspace:0.6.5",
|
||||
"@pnpm/config": "workspace:12.3.0",
|
||||
"@pnpm/fetch": "workspace:3.1.0",
|
||||
"@pnpm/package-store": "workspace:12.0.7",
|
||||
"@pnpm/store-path": "^5.0.0",
|
||||
"@pnpm/tarball-fetcher": "workspace:9.2.2",
|
||||
"adm-zip": "^0.5.5",
|
||||
"execa": "^5.0.0",
|
||||
"load-json-file": "^6.2.0",
|
||||
"path-name": "^1.0.0",
|
||||
"rename-overwrite": "^4.0.0",
|
||||
"render-help": "^1.0.1",
|
||||
"tempy": "^1.0.0",
|
||||
"write-json-file": "^4.3.0"
|
||||
},
|
||||
|
||||
@@ -1,37 +1,16 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { docsUrl } from '@pnpm/cli-utils'
|
||||
import { Config } from '@pnpm/config'
|
||||
import fetch, { createFetchFromRegistry, FetchFromRegistry } from '@pnpm/fetch'
|
||||
import { createCafsStore } from '@pnpm/package-store'
|
||||
import storePath from '@pnpm/store-path'
|
||||
import createFetcher, { waitForFilesIndex } from '@pnpm/tarball-fetcher'
|
||||
import AdmZip from 'adm-zip'
|
||||
import execa from 'execa'
|
||||
import PATH from 'path-name'
|
||||
import renameOverwrite from 'rename-overwrite'
|
||||
import renderHelp from 'render-help'
|
||||
import tempy from 'tempy'
|
||||
import loadJsonFile from 'load-json-file'
|
||||
import writeJsonFile from 'write-json-file'
|
||||
|
||||
export const rcOptionsTypes = () => ({})
|
||||
|
||||
export const cliOptionsTypes = () => ({})
|
||||
|
||||
export const shorthands = {}
|
||||
|
||||
export const commandNames = ['node']
|
||||
|
||||
export function help () {
|
||||
return renderHelp({
|
||||
description: 'Run Node.js',
|
||||
descriptionLists: [],
|
||||
url: docsUrl('node'),
|
||||
usages: ['pnpm node'],
|
||||
})
|
||||
}
|
||||
|
||||
export type NvmNodeCommandOptions = Pick<Config,
|
||||
| 'rawConfig'
|
||||
| 'fetchRetries'
|
||||
@@ -54,24 +33,6 @@ export type NvmNodeCommandOptions = Pick<Config,
|
||||
| 'pnpmHomeDir'
|
||||
>
|
||||
|
||||
export async function handler (
|
||||
opts: NvmNodeCommandOptions & {
|
||||
argv: {
|
||||
original: string[]
|
||||
}
|
||||
}
|
||||
) {
|
||||
const nodeDir = await getNodeDir(opts)
|
||||
const { exitCode } = await execa('node', opts.argv.original.slice(1), {
|
||||
env: {
|
||||
[PATH]: `${nodeDir}${path.delimiter}${process.env[PATH]!}`,
|
||||
},
|
||||
stdout: 'inherit',
|
||||
stdin: 'inherit',
|
||||
})
|
||||
return { exitCode }
|
||||
}
|
||||
|
||||
export async function getNodeDir (opts: NvmNodeCommandOptions) {
|
||||
const nodesDir = path.join(opts.pnpmHomeDir, 'nodes')
|
||||
let wantedNodeVersion = opts.useNodeVersion ?? (await readNodeVersionsManifest(nodesDir))?.default
|
||||
|
||||
@@ -1,30 +1,5 @@
|
||||
import fs from 'fs'
|
||||
import { node } from '@pnpm/plugin-commands-nvm'
|
||||
import { tempDir } from '@pnpm/prepare'
|
||||
|
||||
test('run specific version of Node.js', async () => {
|
||||
tempDir()
|
||||
const { exitCode } = await node.handler({
|
||||
argv: {
|
||||
original: ['node', '-e', 'require("fs").writeFileSync("version",process.version, "utf8")'],
|
||||
},
|
||||
useNodeVersion: '14.0.0',
|
||||
pnpmHomeDir: process.cwd(),
|
||||
rawConfig: {},
|
||||
})
|
||||
expect(exitCode).toBe(0)
|
||||
expect(fs.readFileSync('version', 'utf8')).toBe('v14.0.0')
|
||||
})
|
||||
|
||||
test('run LTS version of Node.js by default', async () => {
|
||||
tempDir()
|
||||
const { exitCode } = await node.handler({
|
||||
argv: {
|
||||
original: ['node', '-e', 'require("fs").writeFileSync("version",process.version, "utf8")'],
|
||||
},
|
||||
pnpmHomeDir: process.cwd(),
|
||||
rawConfig: {},
|
||||
})
|
||||
expect(exitCode).toBe(0)
|
||||
expect(fs.readFileSync('version', 'utf8')).toMatch(/^v[0-9]+\.[0-9]+\.[0-9]+$/)
|
||||
test('check API (placeholder test)', async () => {
|
||||
expect(typeof node.getNodeDir).toBe('function')
|
||||
})
|
||||
|
||||
@@ -48,10 +48,12 @@
|
||||
"@pnpm/config": "workspace:12.3.0",
|
||||
"@pnpm/error": "workspace:2.0.0",
|
||||
"@pnpm/lifecycle": "workspace:11.0.0",
|
||||
"@pnpm/read-project-manifest": "workspace:2.0.2",
|
||||
"@pnpm/sort-packages": "workspace:2.0.1",
|
||||
"@pnpm/types": "workspace:7.1.0",
|
||||
"p-limit": "^3.1.0",
|
||||
"path-exists": "^4.0.0",
|
||||
"path-name": "^1.0.0",
|
||||
"ramda": "^0.27.1",
|
||||
"realpath-missing": "^1.1.0",
|
||||
"render-help": "^1.0.1"
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import path from 'path'
|
||||
import { RecursiveSummary, throwOnCommandFail } from '@pnpm/cli-utils'
|
||||
import { Config, types } from '@pnpm/config'
|
||||
import PnpmError from '@pnpm/error'
|
||||
import { makeNodeRequireOption } from '@pnpm/lifecycle'
|
||||
import logger from '@pnpm/logger'
|
||||
import readProjectManifest from '@pnpm/read-project-manifest'
|
||||
import sortPackages from '@pnpm/sort-packages'
|
||||
import execa from 'execa'
|
||||
import pLimit from 'p-limit'
|
||||
import PATH from 'path-name'
|
||||
import * as R from 'ramda'
|
||||
import renderHelp from 'render-help'
|
||||
import existsInDir from './existsInDir'
|
||||
@@ -57,12 +59,9 @@ export async function handler (
|
||||
rawConfig: object
|
||||
sort?: boolean
|
||||
workspaceConcurrency?: number
|
||||
} & Pick<Config, 'recursive' | 'workspaceDir'>,
|
||||
} & Pick<Config, 'extraBinPaths' | 'lockfileDir' | 'dir' | 'recursive' | 'workspaceDir'>,
|
||||
params: string[]
|
||||
) {
|
||||
if (!opts.recursive) {
|
||||
throw new PnpmError('EXEC_NOT_RECURSIVE', 'The "pnpm exec" command currently only works with the "-r" option')
|
||||
}
|
||||
const limitRun = pLimit(opts.workspaceConcurrency ?? 4)
|
||||
|
||||
const result = {
|
||||
@@ -70,9 +69,24 @@ export async function handler (
|
||||
passes: 0,
|
||||
} as RecursiveSummary
|
||||
|
||||
const chunks = opts.sort
|
||||
? sortPackages(opts.selectedProjectsGraph)
|
||||
: [Object.keys(opts.selectedProjectsGraph).sort()]
|
||||
const rootDir = opts.lockfileDir ?? opts.workspaceDir ?? opts.dir
|
||||
let chunks!: string[][]
|
||||
if (opts.recursive) {
|
||||
chunks = opts.sort
|
||||
? sortPackages(opts.selectedProjectsGraph)
|
||||
: [Object.keys(opts.selectedProjectsGraph).sort()]
|
||||
} else {
|
||||
chunks = [[rootDir]]
|
||||
opts.selectedProjectsGraph = {
|
||||
[rootDir]: {
|
||||
dependencies: [],
|
||||
package: {
|
||||
...await readProjectManifest(rootDir),
|
||||
dir: rootDir,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
const existsPnp = existsInDir.bind(null, '.pnp.cjs')
|
||||
const workspacePnpPath = opts.workspaceDir && await existsPnp(opts.workspaceDir)
|
||||
|
||||
@@ -89,6 +103,11 @@ export async function handler (
|
||||
env: {
|
||||
...process.env,
|
||||
...extraEnv,
|
||||
[PATH]: [
|
||||
...opts.extraBinPaths,
|
||||
path.join(rootDir, 'node_modules/.bin'),
|
||||
process.env[PATH],
|
||||
].join(path.delimiter),
|
||||
PNPM_PACKAGE_NAME: opts.selectedProjectsGraph[prefix].package.manifest.name,
|
||||
},
|
||||
stdio: 'inherit',
|
||||
|
||||
@@ -3,7 +3,7 @@ import path from 'path'
|
||||
import PnpmError from '@pnpm/error'
|
||||
import { readProjects } from '@pnpm/filter-workspace-packages'
|
||||
import { exec } from '@pnpm/plugin-commands-script-runners'
|
||||
import { preparePackages } from '@pnpm/prepare'
|
||||
import prepare, { preparePackages } from '@pnpm/prepare'
|
||||
import rimraf from '@zkochan/rimraf'
|
||||
import execa from 'execa'
|
||||
import { DEFAULT_OPTS, REGISTRY } from './utils'
|
||||
@@ -62,6 +62,7 @@ test('pnpm recursive exec', async () => {
|
||||
])
|
||||
await exec.handler({
|
||||
...DEFAULT_OPTS,
|
||||
dir: process.cwd(),
|
||||
recursive: true,
|
||||
selectedProjectsGraph,
|
||||
}, ['npm', 'run', 'build'])
|
||||
@@ -84,6 +85,7 @@ test('pnpm recursive exec sets PNPM_PACKAGE_NAME env var', async () => {
|
||||
const { selectedProjectsGraph } = await readProjects(process.cwd(), [])
|
||||
await exec.handler({
|
||||
...DEFAULT_OPTS,
|
||||
dir: process.cwd(),
|
||||
recursive: true,
|
||||
selectedProjectsGraph,
|
||||
}, ['node', '-e', 'require(\'fs\').writeFileSync(\'pkgname\', process.env.PNPM_PACKAGE_NAME, \'utf8\')'])
|
||||
@@ -145,6 +147,7 @@ test('testing the bail config with "pnpm recursive exec"', async () => {
|
||||
try {
|
||||
await exec.handler({
|
||||
...DEFAULT_OPTS,
|
||||
dir: process.cwd(),
|
||||
recursive: true,
|
||||
selectedProjectsGraph,
|
||||
}, ['npm', 'run', 'build', '--no-bail'])
|
||||
@@ -165,6 +168,7 @@ test('testing the bail config with "pnpm recursive exec"', async () => {
|
||||
try {
|
||||
await exec.handler({
|
||||
...DEFAULT_OPTS,
|
||||
dir: process.cwd(),
|
||||
recursive: true,
|
||||
selectedProjectsGraph,
|
||||
}, ['npm', 'run', 'build'])
|
||||
@@ -215,6 +219,7 @@ test('pnpm recursive exec --no-sort', async () => {
|
||||
])
|
||||
await exec.handler({
|
||||
...DEFAULT_OPTS,
|
||||
dir: process.cwd(),
|
||||
recursive: true,
|
||||
selectedProjectsGraph,
|
||||
sort: false,
|
||||
@@ -226,21 +231,18 @@ test('pnpm recursive exec --no-sort', async () => {
|
||||
expect(outputs).toStrictEqual(['a-dependent', 'b-dependency'])
|
||||
})
|
||||
|
||||
test('pnpm exec fails without the recursive=true option', async () => {
|
||||
preparePackages([])
|
||||
test('pnpm exec on single project', async () => {
|
||||
prepare({})
|
||||
|
||||
let err!: PnpmError
|
||||
try {
|
||||
await exec.handler({
|
||||
...DEFAULT_OPTS,
|
||||
recursive: false,
|
||||
selectedProjectsGraph: {},
|
||||
}, ['npm', 'run', 'build'])
|
||||
} catch (_err) {
|
||||
err = _err
|
||||
}
|
||||
await exec.handler({
|
||||
...DEFAULT_OPTS,
|
||||
dir: process.cwd(),
|
||||
recursive: false,
|
||||
selectedProjectsGraph: {},
|
||||
}, ['node', '-e', 'require("fs").writeFileSync("output.json", "[]", "utf8")'])
|
||||
|
||||
expect(err.code).toBe('ERR_PNPM_EXEC_NOT_RECURSIVE')
|
||||
const { default: outputs } = await import(path.resolve('output.json'))
|
||||
expect(outputs).toStrictEqual([])
|
||||
})
|
||||
|
||||
test('pnpm recursive exec works with PnP', async () => {
|
||||
@@ -300,6 +302,7 @@ test('pnpm recursive exec works with PnP', async () => {
|
||||
})
|
||||
await exec.handler({
|
||||
...DEFAULT_OPTS,
|
||||
dir: process.cwd(),
|
||||
recursive: true,
|
||||
selectedProjectsGraph,
|
||||
}, ['npm', 'run', 'build'])
|
||||
|
||||
@@ -9,6 +9,7 @@ export const DEFAULT_OPTS = {
|
||||
ca: undefined,
|
||||
cert: undefined,
|
||||
cliOptions: {},
|
||||
extraBinPaths: [],
|
||||
fetchRetries: 2,
|
||||
fetchRetryFactor: 90,
|
||||
fetchRetryMaxtimeout: 90,
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
### Minor Changes
|
||||
|
||||
- New setting added: `use-node-version`. When set, pnpm will install the specified version of Node.js and use it for running any lifecycle scripts [#3459](https://github.com/pnpm/pnpm/pull/3459).
|
||||
- New experimental command added: `pnpm node [args...]`. Runs Node.js with the provided arguments. When `use-node-version` is provided, also installs the wanted Node.js version to run it [#3459](https://github.com/pnpm/pnpm/pull/3459).
|
||||
- New experimental command added: `pnpm setup`. This command adds the path to the pnpm bin to the active shell of the user. So it modifies the bash, zsh, or fish config file [#3456](https://github.com/pnpm/pnpm/pull/3456).
|
||||
- `pnpm publish -r` supports a new option: `--report-summary`. When it is used, `pnpm publish -r --report-summary` will save the summary of published packages to `pnpm-publish-summary.json` [#3461](https://github.com/pnpm/pnpm/pull/3461).
|
||||
- New CLI option added: `--use-stderr`. When set, all the output is written to stderr [#3463](https://github.com/pnpm/pnpm/pull/3463).
|
||||
|
||||
@@ -4,7 +4,6 @@ import { audit } from '@pnpm/plugin-commands-audit'
|
||||
import { importCommand } from '@pnpm/plugin-commands-import'
|
||||
import { add, fetch, install, link, prune, remove, unlink, update } from '@pnpm/plugin-commands-installation'
|
||||
import { list, ll, why } from '@pnpm/plugin-commands-listing'
|
||||
import { node } from '@pnpm/plugin-commands-nvm'
|
||||
import { outdated } from '@pnpm/plugin-commands-outdated'
|
||||
import { pack, publish } from '@pnpm/plugin-commands-publishing'
|
||||
import { rebuild } from '@pnpm/plugin-commands-rebuild'
|
||||
@@ -70,7 +69,6 @@ const commands: Array<{
|
||||
link,
|
||||
list,
|
||||
ll,
|
||||
node,
|
||||
outdated,
|
||||
pack,
|
||||
prune,
|
||||
|
||||
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@@ -1927,7 +1927,6 @@ importers:
|
||||
|
||||
packages/plugin-commands-nvm:
|
||||
specifiers:
|
||||
'@pnpm/cli-utils': workspace:0.6.5
|
||||
'@pnpm/config': workspace:12.3.0
|
||||
'@pnpm/fetch': workspace:3.1.0
|
||||
'@pnpm/package-store': workspace:12.0.7
|
||||
@@ -1937,26 +1936,19 @@ importers:
|
||||
'@pnpm/tarball-fetcher': workspace:9.2.2
|
||||
'@types/adm-zip': ^0.4.34
|
||||
adm-zip: ^0.5.5
|
||||
execa: ^5.0.0
|
||||
load-json-file: ^6.2.0
|
||||
path-name: ^1.0.0
|
||||
rename-overwrite: ^4.0.0
|
||||
render-help: ^1.0.1
|
||||
tempy: ^1.0.0
|
||||
write-json-file: ^4.3.0
|
||||
dependencies:
|
||||
'@pnpm/cli-utils': link:../cli-utils
|
||||
'@pnpm/config': link:../config
|
||||
'@pnpm/fetch': link:../fetch
|
||||
'@pnpm/package-store': link:../package-store
|
||||
'@pnpm/store-path': 5.0.0
|
||||
'@pnpm/tarball-fetcher': link:../tarball-fetcher
|
||||
adm-zip: 0.5.5
|
||||
execa: 5.0.0
|
||||
load-json-file: 6.2.0
|
||||
path-name: 1.0.0
|
||||
rename-overwrite: 4.0.0
|
||||
render-help: 1.0.2
|
||||
tempy: 1.0.1
|
||||
write-json-file: 4.3.0
|
||||
devDependencies:
|
||||
@@ -2207,6 +2199,7 @@ importers:
|
||||
'@pnpm/logger': ^4.0.0
|
||||
'@pnpm/plugin-commands-script-runners': 'link:'
|
||||
'@pnpm/prepare': workspace:0.0.23
|
||||
'@pnpm/read-project-manifest': workspace:2.0.2
|
||||
'@pnpm/sort-packages': workspace:2.0.1
|
||||
'@pnpm/types': workspace:7.1.0
|
||||
'@types/ramda': 0.27.39
|
||||
@@ -2215,6 +2208,7 @@ importers:
|
||||
is-windows: ^1.0.2
|
||||
p-limit: ^3.1.0
|
||||
path-exists: ^4.0.0
|
||||
path-name: ^1.0.0
|
||||
ramda: ^0.27.1
|
||||
realpath-missing: ^1.1.0
|
||||
render-help: ^1.0.1
|
||||
@@ -2226,10 +2220,12 @@ importers:
|
||||
'@pnpm/config': link:../config
|
||||
'@pnpm/error': link:../error
|
||||
'@pnpm/lifecycle': link:../lifecycle
|
||||
'@pnpm/read-project-manifest': link:../read-project-manifest
|
||||
'@pnpm/sort-packages': link:../sort-packages
|
||||
'@pnpm/types': link:../types
|
||||
p-limit: 3.1.0
|
||||
path-exists: 4.0.0
|
||||
path-name: 1.0.0
|
||||
ramda: 0.27.1
|
||||
realpath-missing: 1.1.0
|
||||
render-help: 1.0.2
|
||||
|
||||
Reference in New Issue
Block a user