mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
fix(scripts): resolve pnpm when npx or npm run exports npm's own CLI (#34271)
`npx` and `npm run` set npm_execpath to npm's own npm-cli.js/npx-cli.js, so resolvePnpmCliInvocation ran npm with pnpm's arguments. Skip npm's CLI by file name and fall back to PNPM_HOME / pnpm on PATH. Route build-workspace-packages and terminal layout parity through the shared resolver instead of their own npm_execpath parsing. Fixes #29438 Co-authored-by: Lance Woodson <65194841+woodsonl@users.noreply.github.com>
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
} from 'node:fs'
|
||||
import { createRequire } from 'node:module'
|
||||
import { dirname, join, relative, resolve } from 'node:path'
|
||||
import { resolvePnpmCliInvocation } from './pnpm-cli-invocation.mjs'
|
||||
|
||||
const root = resolve(import.meta.dirname, '../..')
|
||||
const PACKAGES = [{ name: '@orca/process-host', dir: 'src/packages/process-host' }]
|
||||
@@ -90,14 +91,11 @@ function writeStamp(packageDir, inputs) {
|
||||
|
||||
function runPackageBuild(name) {
|
||||
// Why not @orca/process-host: this builds it, so its dist may not exist yet.
|
||||
const pnpmEntry = process.env.npm_execpath
|
||||
const [program, args] = /\.[cm]?js$/.test(pnpmEntry ?? '')
|
||||
? [process.execPath, [pnpmEntry, '--filter', name, 'build']]
|
||||
: ['pnpm', ['--filter', name, 'build']]
|
||||
const result = spawnSync(program, args, {
|
||||
const { command, prefixArgs, shell } = resolvePnpmCliInvocation()
|
||||
const result = spawnSync(command, [...prefixArgs, '--filter', name, 'build'], {
|
||||
cwd: root,
|
||||
stdio: 'inherit',
|
||||
shell: program === 'pnpm' && process.platform === 'win32'
|
||||
shell
|
||||
})
|
||||
if (result.error) {
|
||||
throw result.error
|
||||
|
||||
@@ -4,6 +4,8 @@ import { statSync } from 'node:fs'
|
||||
import { win32 } from 'node:path'
|
||||
|
||||
const JS_CLI_EXTENSION = /\.[cm]?js$/i
|
||||
// Why: `npx` and `npm run` export npm's own CLI as npm_execpath, which would run npm, not pnpm.
|
||||
const NPM_OWN_CLI_PATH = /(?:^|[/\\])np[mx]-cli\.js$/i
|
||||
|
||||
function isFile(path) {
|
||||
try {
|
||||
@@ -20,7 +22,11 @@ export function resolvePnpmCliInvocation({
|
||||
pnpmHome = process.env.PNPM_HOME,
|
||||
fileExists = isFile
|
||||
} = {}) {
|
||||
if (typeof npmExecPath === 'string' && npmExecPath.length > 0) {
|
||||
if (
|
||||
typeof npmExecPath === 'string' &&
|
||||
npmExecPath.length > 0 &&
|
||||
!NPM_OWN_CLI_PATH.test(npmExecPath)
|
||||
) {
|
||||
if (JS_CLI_EXTENSION.test(npmExecPath)) {
|
||||
return { command: nodeExecPath, prefixArgs: [npmExecPath], shell: false }
|
||||
}
|
||||
|
||||
@@ -37,6 +37,20 @@ describe('resolvePnpmCliInvocation', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it.each([
|
||||
['/usr/share/nodejs/npm/bin/npx-cli.js', 'linux', 'pnpm', false],
|
||||
['/usr/local/lib/node_modules/npm/bin/npm-cli.js', 'darwin', 'pnpm', false],
|
||||
['/Users/dev/.volta/tools/image/npm/10.8.0/bin/npm-cli.js', 'darwin', 'pnpm', false],
|
||||
['C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npx-cli.js', 'win32', 'pnpm.cmd', true]
|
||||
])(
|
||||
'ignores the npm CLI %s that `npx` or `npm run` exports',
|
||||
(npmExecPath, platform, command, shell) => {
|
||||
expect(
|
||||
resolvePnpmCliInvocation({ npmExecPath, nodeExecPath, platform, pnpmHome: '' })
|
||||
).toEqual({ command, prefixArgs: [], shell })
|
||||
}
|
||||
)
|
||||
|
||||
it('does not wrap a Windows native pnpm.exe in node', () => {
|
||||
expect(
|
||||
resolvePnpmCliInvocation({
|
||||
|
||||
@@ -13,11 +13,12 @@ import {
|
||||
writeFileSync
|
||||
} from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { basename, join, resolve } from 'node:path'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import { parseArgs } from 'node:util'
|
||||
import { runProcessSync } from '@orca/process-host'
|
||||
import { describeProcessFailure } from './process-failure-message.mjs'
|
||||
import { resolvePnpmCliInvocation } from './pnpm-cli-invocation.mjs'
|
||||
const repoRoot = resolve(import.meta.dirname, '../..')
|
||||
const BUILD_STAMP = join('out', '.terminal-layout-parity-build')
|
||||
|
||||
@@ -88,16 +89,9 @@ function git(args) {
|
||||
return result.stdout.trim()
|
||||
}
|
||||
|
||||
// npm_execpath is pnpm's JS entry (run under node), a native pnpm binary (corepack), or unset.
|
||||
function pnpm(args, cwd, env = process.env) {
|
||||
const entry = process.env.npm_execpath
|
||||
if (entry && /\.[cm]?js$/i.test(entry)) {
|
||||
run(process.execPath, [entry, ...args], cwd, env)
|
||||
} else if (entry && /pnpm/i.test(basename(entry)) && existsSync(entry)) {
|
||||
run(entry, args, cwd, env)
|
||||
} else {
|
||||
run('pnpm', args, cwd, env)
|
||||
}
|
||||
const { command, prefixArgs } = resolvePnpmCliInvocation()
|
||||
run(command, [...prefixArgs, ...args], cwd, env)
|
||||
}
|
||||
|
||||
/** A detached worktree per commit, installed and built once; a failed build throws before stamping. */
|
||||
|
||||
Reference in New Issue
Block a user