mirror of
https://github.com/pnpm/pnpm.git
synced 2026-01-11 00:18:32 -05:00
fix: some commands should not fail if a different package manager is set in package.json (#8802)
close #7959
This commit is contained in:
10
.changeset/two-rice-divide.md
Normal file
10
.changeset/two-rice-divide.md
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-store-inspecting": patch
|
||||
"@pnpm/plugin-commands-completion": patch
|
||||
"@pnpm/plugin-commands-script-runners": patch
|
||||
"@pnpm/plugin-commands-store": patch
|
||||
"@pnpm/plugin-commands-env": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
Some commands should ignore the `packageManager` field check of `package.json` [#7959](https://github.com/pnpm/pnpm/issues/7959).
|
||||
@@ -5,6 +5,8 @@ import { getShellFromParams } from './getShell'
|
||||
|
||||
export const commandNames = ['completion']
|
||||
|
||||
export const skipPackageManagerCheck = true
|
||||
|
||||
export const rcOptionsTypes = (): Record<string, unknown> => ({})
|
||||
|
||||
export const cliOptionsTypes = (): Record<string, unknown> => ({})
|
||||
|
||||
2
env/plugin-commands-env/src/env.ts
vendored
2
env/plugin-commands-env/src/env.ts
vendored
@@ -7,6 +7,8 @@ import { type NvmNodeCommandOptions } from './node'
|
||||
import { envList } from './envList'
|
||||
import { envAdd } from './envAdd'
|
||||
|
||||
export const skipPackageManagerCheck = true
|
||||
|
||||
export function rcOptionsTypes (): Record<string, unknown> {
|
||||
return {}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ import renderHelp from 'render-help'
|
||||
import symlinkDir from 'symlink-dir'
|
||||
import { makeEnv } from './makeEnv'
|
||||
|
||||
export const skipPackageManagerCheck = true
|
||||
|
||||
export const commandNames = ['dlx']
|
||||
|
||||
export const shorthands: Record<string, string> = {
|
||||
|
||||
@@ -101,6 +101,10 @@ export interface CommandDefinition {
|
||||
* ```
|
||||
*/
|
||||
shorthands?: Record<string, string | string[]>
|
||||
/**
|
||||
* If true, this command should not care about what package manager is specified in the "packageManager" field of "package.json".
|
||||
*/
|
||||
skipPackageManagerCheck?: boolean
|
||||
}
|
||||
|
||||
const commands: CommandDefinition[] = [
|
||||
@@ -161,6 +165,7 @@ const aliasToFullName = new Map<string, string>()
|
||||
const completionByCommandName: Record<string, CompletionFunc> = {}
|
||||
const shorthandsByCommandName: Record<string, Record<string, string | string[]>> = {}
|
||||
const rcOptionsTypes: Record<string, unknown> = {}
|
||||
const skipPackageManagerCheckForCommandArray = ['completion-server']
|
||||
|
||||
for (let i = 0; i < commands.length; i++) {
|
||||
const {
|
||||
@@ -171,6 +176,7 @@ for (let i = 0; i < commands.length; i++) {
|
||||
help,
|
||||
rcOptionsTypes,
|
||||
shorthands,
|
||||
skipPackageManagerCheck,
|
||||
} = commands[i]
|
||||
if (!commandNames || commandNames.length === 0) {
|
||||
throw new Error(`The command at index ${i} doesn't have command names`)
|
||||
@@ -185,6 +191,9 @@ for (let i = 0; i < commands.length; i++) {
|
||||
}
|
||||
Object.assign(rcOptionsTypes, rcOptionsTypes())
|
||||
}
|
||||
if (skipPackageManagerCheck) {
|
||||
skipPackageManagerCheckForCommandArray.push(...commandNames)
|
||||
}
|
||||
if (commandNames.length > 1) {
|
||||
const fullName = commandNames[0]
|
||||
for (let i = 1; i < commandNames.length; i++) {
|
||||
@@ -210,6 +219,8 @@ function initialCompletion (): Array<{ name: string }> {
|
||||
|
||||
export const pnpmCmds = handlerByCommandName
|
||||
|
||||
export const skipPackageManagerCheckForCommand = new Set(skipPackageManagerCheckForCommandArray)
|
||||
|
||||
export function getCliOptionsTypes (commandName: string): Record<string, unknown> {
|
||||
return cliOptionsTypesByCommandName[commandName]?.() || {}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import path from 'path'
|
||||
import isEmpty from 'ramda/src/isEmpty'
|
||||
import stripAnsi from 'strip-ansi'
|
||||
import { checkForUpdates } from './checkForUpdates'
|
||||
import { pnpmCmds, rcOptionsTypes } from './cmd'
|
||||
import { pnpmCmds, rcOptionsTypes, skipPackageManagerCheckForCommand } from './cmd'
|
||||
import { formatUnknownOptionsError } from './formatError'
|
||||
import { parseCliArgs } from './parseCliArgs'
|
||||
import { initReporter, type ReporterType } from './reporter'
|
||||
@@ -108,7 +108,7 @@ export async function main (inputArgv: string[]): Promise<void> {
|
||||
if (!isExecutedByCorepack() && cmd !== 'setup' && config.wantedPackageManager != null) {
|
||||
if (config.managePackageManagerVersions && config.wantedPackageManager?.name === 'pnpm') {
|
||||
await switchCliVersion(config)
|
||||
} else {
|
||||
} else if (!cmd || !skipPackageManagerCheckForCommand.has(cmd)) {
|
||||
checkPackageManager(config.wantedPackageManager, config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,81 +248,6 @@ test('`pnpm -r add` should fail if no package name was provided', () => {
|
||||
expect(stdout.toString()).toContain('`pnpm add` requires the package name')
|
||||
})
|
||||
|
||||
test('install should fail if the used pnpm version does not satisfy the pnpm version specified in engines', async () => {
|
||||
prepare({
|
||||
name: 'project',
|
||||
version: '1.0.0',
|
||||
|
||||
engines: {
|
||||
pnpm: '99999',
|
||||
},
|
||||
})
|
||||
|
||||
const { status, stdout } = execPnpmSync(['install'])
|
||||
|
||||
expect(status).toBe(1)
|
||||
expect(stdout.toString()).toContain('Your pnpm version is incompatible with')
|
||||
})
|
||||
|
||||
test('install should not fail if the used pnpm version does not satisfy the pnpm version specified in packageManager', async () => {
|
||||
prepare({
|
||||
name: 'project',
|
||||
version: '1.0.0',
|
||||
|
||||
packageManager: 'pnpm@0.0.0',
|
||||
})
|
||||
|
||||
expect(execPnpmSync(['install', '--config.manage-package-manager-versions=false']).status).toBe(0)
|
||||
|
||||
const { status, stderr } = execPnpmSync(['install', '--config.manage-package-manager-versions=false', '--config.package-manager-strict-version=true'])
|
||||
|
||||
expect(status).toBe(1)
|
||||
expect(stderr.toString()).toContain('This project is configured to use v0.0.0 of pnpm. Your current pnpm is')
|
||||
})
|
||||
|
||||
test('install should fail if the project requires a different package manager', async () => {
|
||||
prepare({
|
||||
name: 'project',
|
||||
version: '1.0.0',
|
||||
|
||||
packageManager: 'yarn@4.0.0',
|
||||
})
|
||||
|
||||
const { status, stderr } = execPnpmSync(['install', '--config.manage-package-manager-versions=true'])
|
||||
|
||||
expect(status).toBe(1)
|
||||
expect(stderr.toString()).toContain('This project is configured to use yarn')
|
||||
|
||||
expect(execPnpmSync(['install', '--config.package-manager-strict=false']).status).toBe(0)
|
||||
})
|
||||
|
||||
test('install should not fail for packageManager field with hash', async () => {
|
||||
const versionProcess = execPnpmSync(['--version'])
|
||||
const pnpmVersion = versionProcess.stdout.toString().trim()
|
||||
|
||||
prepare({
|
||||
name: 'project',
|
||||
version: '1.0.0',
|
||||
|
||||
packageManager: `pnpm@${pnpmVersion}+sha256.123456789`,
|
||||
})
|
||||
|
||||
const { status } = execPnpmSync(['install'])
|
||||
expect(status).toBe(0)
|
||||
})
|
||||
|
||||
test('install should not fail for packageManager field with url', async () => {
|
||||
prepare({
|
||||
name: 'project',
|
||||
version: '1.0.0',
|
||||
|
||||
packageManager: 'pnpm@https://github.com/pnpm/pnpm',
|
||||
})
|
||||
|
||||
const { status } = execPnpmSync(['install'])
|
||||
expect(status).toBe(0)
|
||||
})
|
||||
|
||||
test('engine-strict=false: install should not fail if the used Node version does not satisfy the Node version specified in engines', async () => {
|
||||
prepare({
|
||||
name: 'project',
|
||||
|
||||
89
pnpm/test/packageManagerCheck.test.ts
Normal file
89
pnpm/test/packageManagerCheck.test.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { prepare } from '@pnpm/prepare'
|
||||
import { execPnpmSync } from './utils'
|
||||
|
||||
test('install should fail if the used pnpm version does not satisfy the pnpm version specified in engines', async () => {
|
||||
prepare({
|
||||
name: 'project',
|
||||
version: '1.0.0',
|
||||
|
||||
engines: {
|
||||
pnpm: '99999',
|
||||
},
|
||||
})
|
||||
|
||||
const { status, stdout } = execPnpmSync(['install'])
|
||||
|
||||
expect(status).toBe(1)
|
||||
expect(stdout.toString()).toContain('Your pnpm version is incompatible with')
|
||||
})
|
||||
|
||||
test('install should not fail if the used pnpm version does not satisfy the pnpm version specified in packageManager', async () => {
|
||||
prepare({
|
||||
name: 'project',
|
||||
version: '1.0.0',
|
||||
|
||||
packageManager: 'pnpm@0.0.0',
|
||||
})
|
||||
|
||||
expect(execPnpmSync(['install', '--config.manage-package-manager-versions=false']).status).toBe(0)
|
||||
|
||||
const { status, stderr } = execPnpmSync(['install', '--config.manage-package-manager-versions=false', '--config.package-manager-strict-version=true'])
|
||||
|
||||
expect(status).toBe(1)
|
||||
expect(stderr.toString()).toContain('This project is configured to use v0.0.0 of pnpm. Your current pnpm is')
|
||||
})
|
||||
|
||||
test('install should fail if the project requires a different package manager', async () => {
|
||||
prepare({
|
||||
name: 'project',
|
||||
version: '1.0.0',
|
||||
|
||||
packageManager: 'yarn@4.0.0',
|
||||
})
|
||||
|
||||
const { status, stderr } = execPnpmSync(['install', '--config.manage-package-manager-versions=true'])
|
||||
|
||||
expect(status).toBe(1)
|
||||
expect(stderr.toString()).toContain('This project is configured to use yarn')
|
||||
|
||||
expect(execPnpmSync(['install', '--config.package-manager-strict=false']).status).toBe(0)
|
||||
})
|
||||
|
||||
test('install should not fail for packageManager field with hash', async () => {
|
||||
const versionProcess = execPnpmSync(['--version'])
|
||||
const pnpmVersion = versionProcess.stdout.toString().trim()
|
||||
|
||||
prepare({
|
||||
name: 'project',
|
||||
version: '1.0.0',
|
||||
|
||||
packageManager: `pnpm@${pnpmVersion}+sha256.123456789`,
|
||||
})
|
||||
|
||||
const { status } = execPnpmSync(['install'])
|
||||
expect(status).toBe(0)
|
||||
})
|
||||
|
||||
test('install should not fail for packageManager field with url', async () => {
|
||||
prepare({
|
||||
name: 'project',
|
||||
version: '1.0.0',
|
||||
|
||||
packageManager: 'pnpm@https://github.com/pnpm/pnpm',
|
||||
})
|
||||
|
||||
const { status } = execPnpmSync(['install'])
|
||||
expect(status).toBe(0)
|
||||
})
|
||||
|
||||
test('some commands should not fail if the required package manager is not pnpm', async () => {
|
||||
prepare({
|
||||
name: 'project',
|
||||
version: '1.0.0',
|
||||
|
||||
packageManager: 'yarn@3.0.0',
|
||||
})
|
||||
|
||||
const { status } = execPnpmSync(['store', 'path'])
|
||||
expect(status).toBe(0)
|
||||
})
|
||||
@@ -10,6 +10,8 @@ import renderHelp from 'render-help'
|
||||
|
||||
const INTEGRITY_REGEX: RegExp = /^([^-]+)-([A-Za-z0-9+/=]+)$/
|
||||
|
||||
export const skipPackageManagerCheck = true
|
||||
|
||||
export const commandNames = ['cat-file']
|
||||
|
||||
export const rcOptionsTypes = cliOptionsTypes
|
||||
|
||||
@@ -12,6 +12,8 @@ import sortKeys from 'sort-keys'
|
||||
import loadJsonFile from 'load-json-file'
|
||||
import renderHelp from 'render-help'
|
||||
|
||||
export const skipPackageManagerCheck = true
|
||||
|
||||
export const commandNames = ['cat-index']
|
||||
|
||||
export const rcOptionsTypes = cliOptionsTypes
|
||||
|
||||
@@ -13,6 +13,8 @@ import renderHelp from 'render-help'
|
||||
export const PACKAGE_INFO_CLR = chalk.greenBright
|
||||
export const INDEX_PATH_CLR = chalk.hex('#078487')
|
||||
|
||||
export const skipPackageManagerCheck = true
|
||||
|
||||
export const commandNames = ['find-hash']
|
||||
|
||||
export const rcOptionsTypes = cliOptionsTypes
|
||||
|
||||
@@ -10,6 +10,8 @@ import { storeAdd } from './storeAdd'
|
||||
import { storePrune } from './storePrune'
|
||||
import { storeStatus } from './storeStatus'
|
||||
|
||||
export const skipPackageManagerCheck = true
|
||||
|
||||
export const rcOptionsTypes = cliOptionsTypes
|
||||
|
||||
export function cliOptionsTypes (): Record<string, unknown> {
|
||||
|
||||
Reference in New Issue
Block a user