fix(pnpm): fail on unknown command

PR #2330
close #2325
This commit is contained in:
ExE Boss authored and GitHub committed 2020-02-04 15:07:23 +02:00
1 parent 4f84d03914
commit 31d284337d
6 files changed
+58 -21

No files matched your search

+27 -7
View File
@@ -3,9 +3,27 @@ import nopt = require('nopt')
const RECURSIVE_CMDS = new Set(['recursive', 'multi', 'm'])
export interface ParsedCliArgs {
argv: {
remain: string[],
cooked: string[],
original: string[],
}
cliArgs: string[]
cliConf: {
// tslint:disable-next-line: no-any
[option: string]: any,
}
cmd: string | null
subCmd: string | null
isKnownCommand: boolean
unknownOptions: string[]
workspaceDir?: string
}
export default async function parseCliArgs (
opts: {
getCommandLongName: (commandName: string) => string,
getCommandLongName: (commandName: string) => string | null,
getTypesByCommandName: (commandName: string) => object,
globalOptionsTypes: Record<string, unknown>,
isKnownCommand: (commandName: string) => boolean,
@@ -13,7 +31,7 @@ export default async function parseCliArgs (
shortHands: Record<string, string>,
},
inputArgv: string[],
) {
): Promise<ParsedCliArgs> {
const noptExploratoryResults = nopt(
{
filter: [String],
@@ -36,7 +54,7 @@ export default async function parseCliArgs (
cliArgs: noptExploratoryResults.argv.remain,
cliConf: {},
cmd: 'help',
dir: process.cwd(),
isKnownCommand: true,
subCmd: null,
unknownOptions: [] as string[],
}
@@ -67,9 +85,10 @@ export default async function parseCliArgs (
}
}
let cmd = opts.getCommandLongName(argv.remain[0])
let cmd = argv.remain.length > 0 ? opts.getCommandLongName(argv.remain[0]) : null
let isKnownCommand = true
if (cmd && !opts.isKnownCommand(cmd) && !RECURSIVE_CMDS.has(cmd)) {
cmd = 'help'
isKnownCommand = false
}
let subCmd: string | null = argv.remain[1] && opts.getCommandLongName(argv.remain[1])
@@ -77,9 +96,9 @@ export default async function parseCliArgs (
// `pnpm install ""` is going to be just `pnpm install`
const cliArgs = argv.remain.slice(1).filter(Boolean)
if (cliConf['recursive'] !== true && (cliConf['filter'] || RECURSIVE_CMDS.has(cmd))) {
if (cliConf['recursive'] !== true && (cliConf['filter'] || RECURSIVE_CMDS.has(cmd!))) {
cliConf['recursive'] = true
if (subCmd && RECURSIVE_CMDS.has(cmd)) {
if (subCmd && RECURSIVE_CMDS.has(cmd!)) {
cliArgs.shift()
argv.remain.shift()
cmd = subCmd
@@ -119,6 +138,7 @@ export default async function parseCliArgs (
cliArgs,
cliConf,
cmd,
isKnownCommand,
subCmd,
unknownOptions,
workspaceDir,
+7 -5
View File
@@ -85,13 +85,14 @@ test('when runnning a global command inside a workspace, the workspace should be
t.end()
})
test('help is returned when an unknown command is used', async (t) => {
const { cmd } = await parseCliArgs({
test('isKnownCommand is false when an unknown command is used', async (t) => {
const { cmd, isKnownCommand } = await parseCliArgs({
...DEFAULT_OPTS,
globalOptionsTypes: {},
isKnownCommand: () => false,
}, ['foo'])
t.equal(cmd, 'help')
t.false(isKnownCommand)
t.equal(cmd, 'foo')
t.end()
})
@@ -166,9 +167,10 @@ test('if a help option is used, set cmd to "help"', async (t) => {
})
test('no command', async (t) => {
const { cmd } = await parseCliArgs({
const { cmd, isKnownCommand } = await parseCliArgs({
...DEFAULT_OPTS,
}, ['--version'])
t.equal(cmd, undefined)
t.equal(cmd, null)
t.true(isKnownCommand)
t.end()
})
+2 -2
View File
@@ -130,8 +130,8 @@ export function getCliOptionsTypes (commandName: string) {
return cliOptionsTypesByCommandName[commandName]?.() || {}
}
export function getRCOptionsTypes (commandName: string) {
return rcOptionsTypesByCommandName[commandName]?.() || {}
export function getRCOptionsTypes (commandName: string | null) {
return (commandName && rcOptionsTypesByCommandName[commandName]?.()) || {}
}
export function getCommandFullName (commandName: string) {
+9 -3
View File
@@ -30,7 +30,13 @@ import parseCliArgs from './parseCliArgs'
import initReporter, { ReporterType } from './reporter'
export default async function run (inputArgv: string[]) {
const { argv, cliArgs, cliConf, cmd, subCmd, unknownOptions, workspaceDir } = await parseCliArgs(inputArgv)
const { argv, cliArgs, cliConf, cmd, subCmd, isKnownCommand, unknownOptions, workspaceDir } = await parseCliArgs(inputArgv)
if (!isKnownCommand) {
console.error(`${chalk.bgRed.black('\u2009ERROR\u2009')} ${chalk.red(`Unknown command '${cmd}'`)}`)
console.log(`For help, run: pnpm help`)
process.exit(1)
}
if (unknownOptions.length > 0) {
let errorMsg = `${chalk.bgRed.black('\u2009ERROR\u2009')}`
if (unknownOptions.length === 1) {
@@ -39,7 +45,7 @@ export default async function run (inputArgv: string[]) {
errorMsg += ` ${chalk.red(`Unknown options ${unknownOptions.map(unknownOption => `'${unknownOption}'`).join(', ')}`)}`
}
console.error(errorMsg)
console.log(`For help, run: pnpm help ${cmd}`)
console.log(`For help, run: pnpm help${cmd ? ` ${cmd}` : ''}`)
process.exit(1)
}
process.env['npm_config_argv'] = JSON.stringify(argv)
@@ -59,7 +65,7 @@ export default async function run (inputArgv: string[]) {
} catch (err) {
// Reporting is not initialized at this point, so just printing the error
console.error(`${chalk.bgRed.black('\u2009ERROR\u2009')} ${chalk.red(err.message)}`)
console.log(`For help, run: pnpm help ${cmd}`)
console.log(`For help, run: pnpm help${cmd ? ` ${cmd}` : ''}`)
process.exit(1)
return
}
+3 -3
View File
@@ -8,7 +8,7 @@ export type ReporterType = 'default' | 'ndjson' | 'silent' | 'append-only'
export default (
reporterType: ReporterType,
opts: {
cmd: string,
cmd: string | null,
subCmd: string | null,
config: Config,
},
@@ -17,7 +17,7 @@ export default (
case 'default':
defaultReporter({
context: {
argv: opts.subCmd ? [opts.cmd, opts.subCmd] : [opts.cmd],
argv: opts.cmd ? opts.subCmd ? [opts.cmd, opts.subCmd] : [opts.cmd] : [],
config: opts.config,
},
reportingOptions: {
@@ -30,7 +30,7 @@ export default (
case 'append-only':
defaultReporter({
context: {
argv: opts.subCmd ? [opts.cmd, opts.subCmd] : [opts.cmd],
argv: opts.cmd ? opts.subCmd ? [opts.cmd, opts.subCmd] : [opts.cmd] : [],
config: opts.config,
},
reportingOptions: {
+10 -1
View File
@@ -67,7 +67,16 @@ test('pass through to npm with all the args', async t => {
t.equal(result.status, 0, 'command was successfull')
})
test('command fails when unsupport flag is used', async (t) => {
test('pnpm fails when an unsupported command is used', async (t) => {
const project = prepare(t)
const { status, stderr } = execPnpmSync('unsupported-command')
t.equal(status, 1, 'command failed')
t.ok(stderr.toString().includes("Unknown command 'unsupported-command'"))
})
test('command fails when an unsupported flag is used', async (t) => {
const project = prepare(t)
const { status, stderr } = execPnpmSync('update', '--save-dev')