mirror of
https://github.com/pnpm/pnpm.git
synced 2026-02-11 15:41:44 -05:00
fix!: do not allow to install pnpm globally via pnpm add (#8728)
This commit is contained in:
6
.changeset/tricky-crabs-yell.md
Normal file
6
.changeset/tricky-crabs-yell.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-installation": major
|
||||
"pnpm": major
|
||||
---
|
||||
|
||||
`pnpm add --global pnpm` or (`pnpm add --global @pnpm/exe`) fails with an error suggesting to use `pnpm self-update`.
|
||||
@@ -193,10 +193,15 @@ export async function handler (
|
||||
'If you don\'t want to see this warning anymore, you may set the ignore-workspace-root-check setting to true.'
|
||||
)
|
||||
}
|
||||
if (opts.global && !opts.bin) {
|
||||
throw new PnpmError('NO_GLOBAL_BIN_DIR', 'Unable to find the global bin directory', {
|
||||
hint: 'Run "pnpm setup" to create it automatically, or set the global-bin-dir setting, or the PNPM_HOME env variable. The global bin directory should be in the PATH.',
|
||||
})
|
||||
if (opts.global) {
|
||||
if (!opts.bin) {
|
||||
throw new PnpmError('NO_GLOBAL_BIN_DIR', 'Unable to find the global bin directory', {
|
||||
hint: 'Run "pnpm setup" to create it automatically, or set the global-bin-dir setting, or the PNPM_HOME env variable. The global bin directory should be in the PATH.',
|
||||
})
|
||||
}
|
||||
if (params.includes('pnpm') || params.includes('@pnpm/exe')) {
|
||||
throw new PnpmError('GLOBAL_PNPM_INSTALL', 'Use the "pnpm self-update" command to install or update pnpm')
|
||||
}
|
||||
}
|
||||
|
||||
const include = {
|
||||
|
||||
@@ -353,3 +353,43 @@ test('add: fail when global bin directory is not found', async () => {
|
||||
}
|
||||
expect(err.code).toBe('ERR_PNPM_NO_GLOBAL_BIN_DIR')
|
||||
})
|
||||
|
||||
test('add: fail trying to install pnpm', async () => {
|
||||
prepareEmpty()
|
||||
|
||||
let err!: PnpmError
|
||||
try {
|
||||
await add.handler({
|
||||
...DEFAULT_OPTIONS,
|
||||
bin: path.resolve('project/bin'),
|
||||
dir: path.resolve('project'),
|
||||
global: true,
|
||||
linkWorkspacePackages: false,
|
||||
saveWorkspaceProtocol: false,
|
||||
workspace: false,
|
||||
}, ['pnpm'])
|
||||
} catch (_err: any) { // eslint-disable-line
|
||||
err = _err
|
||||
}
|
||||
expect(err.code).toBe('ERR_PNPM_GLOBAL_PNPM_INSTALL')
|
||||
})
|
||||
|
||||
test('add: fail trying to install @pnpm/exe', async () => {
|
||||
prepareEmpty()
|
||||
|
||||
let err!: PnpmError
|
||||
try {
|
||||
await add.handler({
|
||||
...DEFAULT_OPTIONS,
|
||||
bin: path.resolve('project/bin'),
|
||||
dir: path.resolve('project'),
|
||||
global: true,
|
||||
linkWorkspacePackages: false,
|
||||
saveWorkspaceProtocol: false,
|
||||
workspace: false,
|
||||
}, ['@pnpm/exe'])
|
||||
} catch (_err: any) { // eslint-disable-line
|
||||
err = _err
|
||||
}
|
||||
expect(err.code).toBe('ERR_PNPM_GLOBAL_PNPM_INSTALL')
|
||||
})
|
||||
|
||||
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
@@ -5796,9 +5796,6 @@ importers:
|
||||
'@types/semver':
|
||||
specifier: 'catalog:'
|
||||
version: 7.5.3
|
||||
'@types/which':
|
||||
specifier: 'catalog:'
|
||||
version: 2.0.2
|
||||
'@zkochan/retry':
|
||||
specifier: 'catalog:'
|
||||
version: 0.2.0
|
||||
@@ -5886,9 +5883,6 @@ importers:
|
||||
tree-kill:
|
||||
specifier: 'catalog:'
|
||||
version: 1.2.2
|
||||
which:
|
||||
specifier: 'catalog:'
|
||||
version: '@pnpm/which@3.0.1'
|
||||
write-json-file:
|
||||
specifier: 'catalog:'
|
||||
version: 4.3.0
|
||||
|
||||
@@ -86,7 +86,6 @@
|
||||
"@types/pnpm__byline": "catalog:",
|
||||
"@types/ramda": "catalog:",
|
||||
"@types/semver": "catalog:",
|
||||
"@types/which": "catalog:",
|
||||
"@zkochan/retry": "catalog:",
|
||||
"@zkochan/rimraf": "catalog:",
|
||||
"chalk": "catalog:",
|
||||
@@ -116,7 +115,6 @@
|
||||
"symlink-dir": "catalog:",
|
||||
"tempy": "catalog:",
|
||||
"tree-kill": "catalog:",
|
||||
"which": "catalog:",
|
||||
"write-json-file": "catalog:",
|
||||
"write-pkg": "catalog:",
|
||||
"write-yaml-file": "catalog:"
|
||||
|
||||
@@ -23,7 +23,6 @@ import { isCI } from 'ci-info'
|
||||
import path from 'path'
|
||||
import isEmpty from 'ramda/src/isEmpty'
|
||||
import stripAnsi from 'strip-ansi'
|
||||
import which from 'which'
|
||||
import { checkForUpdates } from './checkForUpdates'
|
||||
import { pnpmCmds, rcOptionsTypes } from './cmd'
|
||||
import { formatUnknownOptionsError } from './formatError'
|
||||
@@ -170,21 +169,8 @@ export async function main (inputArgv: string[]): Promise<void> {
|
||||
global[REPORTER_INITIALIZED] = reporterType
|
||||
}
|
||||
|
||||
const selfUpdate = config.global && (cmd === 'add' || cmd === 'update') && cliParams.includes(packageManager.name)
|
||||
|
||||
if (selfUpdate) {
|
||||
if (cmd === 'self-update') {
|
||||
await pnpmCmds.server(config as any, ['stop']) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
try {
|
||||
const currentPnpmDir = path.dirname(which.sync('pnpm'))
|
||||
if (path.relative(currentPnpmDir, config.bin) !== '') {
|
||||
console.log(`The location of the currently running pnpm differs from the location where pnpm will be installed
|
||||
Current pnpm location: ${currentPnpmDir}
|
||||
Target location: ${config.bin}
|
||||
`)
|
||||
}
|
||||
} catch {
|
||||
// if pnpm not found, then ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -261,7 +247,7 @@ export async function main (inputArgv: string[]): Promise<void> {
|
||||
if (
|
||||
config.updateNotifier !== false &&
|
||||
!isCI &&
|
||||
!selfUpdate &&
|
||||
cmd !== 'self-update' &&
|
||||
!config.offline &&
|
||||
!config.preferOffline &&
|
||||
!config.fallbackCommandUsed &&
|
||||
|
||||
@@ -30,7 +30,7 @@ skipOnWindows('self-update stops the store server', async () => {
|
||||
XDG_DATA_HOME: path.resolve('data'),
|
||||
}
|
||||
|
||||
await execPnpm(['install', '-g', 'pnpm', '--store-dir', path.resolve('..', 'store'), '--reporter=append-only'], { env })
|
||||
await execPnpm(['self-update', `--config.store-dir=${path.resolve('..', 'store')}`, '--reporter=append-only'], { env })
|
||||
|
||||
expect(fs.existsSync(serverJsonPath)).toBeFalsy()
|
||||
project.isExecutable('../pnpm')
|
||||
|
||||
Reference in New Issue
Block a user