Skip to content

Commit 4e58274

Browse files
committed
Do not print error banner for shell proxy commands
There are a few commands (exec, run-script, and the run-script proxies) where essentially npm is acting like a very fancy shell. It is peculiar and noisy for npm to print a verbose error banner at the end of these commands, since presumably the command itself already did whatever it had to do to report the error appropriately. For example, `npm test` runs a test script, usually outputting test results. Having npm then tell me that my tests failed with exit status 1 and print a debug log, is unnecessary and unwanted. When the error encountered for these commands does not have a non-zero numeric 'code', then we still print the standard npm error reporting messages, because presumably something went wrong OTHER than a process exiting with a non-zero status code. PR-URL: #2742 Credit: @isaacs Close: #2742 Reviewed-by: @nlf
1 parent be9f152 commit 4e58274

File tree

6 files changed

+101
-3
lines changed

6 files changed

+101
-3
lines changed

lib/npm.js

+5
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ const makeCmd = cmd => {
4949
}
5050

5151
const { types, defaults, shorthands } = require('./utils/config.js')
52+
const { shellouts } = require('./utils/cmd-list.js')
5253

5354
let warnedNonDashArg = false
5455
const _runCmd = Symbol('_runCmd')
@@ -81,6 +82,10 @@ const npm = module.exports = new class extends EventEmitter {
8182
this.updateNotification = null
8283
}
8384

85+
get shelloutCommands () {
86+
return shellouts
87+
}
88+
8489
deref (c) {
8590
return deref(c)
8691
}

lib/utils/cmd-list.js

+14
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,24 @@ const cmdList = [
136136
]
137137

138138
const plumbing = ['birthday', 'help-search']
139+
140+
// these commands just shell out to something else or handle the
141+
// error themselves, so it's confusing and weird to write out
142+
// our full error log banner when they exit non-zero
143+
const shellouts = [
144+
'exec',
145+
'run-script',
146+
'test',
147+
'start',
148+
'stop',
149+
'restart',
150+
]
151+
139152
module.exports = {
140153
aliases: Object.assign({}, shorthands, affordances),
141154
shorthands,
142155
affordances,
143156
cmdList,
144157
plumbing,
158+
shellouts,
145159
}

lib/utils/error-handler.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,7 @@ const exit = (code, noLog) => {
105105

106106
if (code && !noLog)
107107
writeLogFile()
108-
else
109-
reallyExit()
108+
reallyExit()
110109
}
111110

112111
const errorHandler = (er) => {
@@ -130,7 +129,16 @@ const errorHandler = (er) => {
130129
cbCalled = true
131130
if (!er)
132131
return exit(0)
133-
if (typeof er === 'string') {
132+
133+
// if we got a command that just shells out to something else, then it
134+
// will presumably print its own errors and exit with a proper status
135+
// code if there's a problem. If we got an error with a code=0, then...
136+
// something else went wrong along the way, so maybe an npm problem?
137+
const isShellout = npm.shelloutCommands.includes(npm.command)
138+
const quietShellout = isShellout && typeof er.code === 'number' && er.code
139+
if (quietShellout)
140+
return exit(er.code, true)
141+
else if (typeof er === 'string') {
134142
log.error('', er)
135143
return exit(1, true)
136144
} else if (!(er instanceof Error)) {

tap-snapshots/test-lib-utils-cmd-list.js-TAP.test.js

+8
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,14 @@ Object {
173173
"birthday",
174174
"help-search",
175175
],
176+
"shellouts": Array [
177+
"exec",
178+
"run-script",
179+
"test",
180+
"start",
181+
"stop",
182+
"restart",
183+
],
176184
"shorthands": Object {
177185
"c": "config",
178186
"cit": "install-ci-test",

test/lib/npm.js

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ t.test('not yet loaded', t => {
7979
set: Function,
8080
},
8181
version: String,
82+
shelloutCommands: Array,
8283
})
8384
t.throws(() => npm.config.set('foo', 'bar'))
8485
t.throws(() => npm.config.get('foo'))

test/lib/utils/error-handler.js

+62
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const config = {
4343
const npm = {
4444
version: '1.0.0',
4545
config,
46+
shelloutCommands: ['exec', 'run-script'],
4647
}
4748

4849
const npmlog = {
@@ -525,3 +526,64 @@ t.test('use exitCode when emitting exit event', (t) => {
525526

526527
process.emit('exit')
527528
})
529+
530+
t.test('do no fancy handling for shellouts', t => {
531+
const { exit } = process
532+
const { command } = npm
533+
const { log } = npmlog
534+
const LOG_RECORD = []
535+
t.teardown(() => {
536+
npmlog.log = log
537+
process.exit = exit
538+
npm.command = command
539+
})
540+
541+
npmlog.log = function (level, ...args) {
542+
log.call(this, level, ...args)
543+
LOG_RECORD.push(npmlog.record[npmlog.record.length - 1])
544+
}
545+
546+
npm.command = 'exec'
547+
548+
let EXPECT_EXIT = 0
549+
process.exit = code => {
550+
t.equal(code, EXPECT_EXIT, 'got expected exit code')
551+
EXPECT_EXIT = 0
552+
}
553+
t.beforeEach((cb) => {
554+
LOG_RECORD.length = 0
555+
cb()
556+
})
557+
558+
const loudNoises = () => LOG_RECORD
559+
.filter(({ level }) => ['warn', 'error'].includes(level))
560+
561+
t.test('shellout with a numeric error code', t => {
562+
EXPECT_EXIT = 5
563+
errorHandler(Object.assign(new Error(), { code: 5 }))
564+
t.equal(EXPECT_EXIT, 0, 'called process.exit')
565+
// should log no warnings or errors, verbose/silly is fine.
566+
t.strictSame(loudNoises(), [], 'no noisy warnings')
567+
t.end()
568+
})
569+
570+
t.test('shellout without a numeric error code (something in npm)', t => {
571+
EXPECT_EXIT = 1
572+
errorHandler(Object.assign(new Error(), { code: 'banana stand' }))
573+
t.equal(EXPECT_EXIT, 0, 'called process.exit')
574+
// should log some warnings and errors, because something weird happened
575+
t.strictNotSame(loudNoises(), [], 'bring the noise')
576+
t.end()
577+
})
578+
579+
t.test('shellout with code=0 (extra weird?)', t => {
580+
EXPECT_EXIT = 1
581+
errorHandler(Object.assign(new Error(), { code: 0 }))
582+
t.equal(EXPECT_EXIT, 0, 'called process.exit')
583+
// should log some warnings and errors, because something weird happened
584+
t.strictNotSame(loudNoises(), [], 'bring the noise')
585+
t.end()
586+
})
587+
588+
t.end()
589+
})

0 commit comments

Comments
 (0)