From 2ae7fd8e0d64042244bb0ec770605419375cdbb0 Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Sat, 2 Dec 2023 11:59:45 -0700 Subject: [PATCH] fix: show error log message for workspace run failures --- lib/commands/run-script.js | 20 +++++++++++------- lib/utils/exit-handler.js | 21 +++++++------------ .../test/workspace-run-script-error-logs.js | 19 +++++++++++++++++ 3 files changed, 40 insertions(+), 20 deletions(-) create mode 100644 smoke-tests/test/workspace-run-script-error-logs.js diff --git a/lib/commands/run-script.js b/lib/commands/run-script.js index 75f00a46b84e9..d0298c2a9d088 100644 --- a/lib/commands/run-script.js +++ b/lib/commands/run-script.js @@ -194,22 +194,28 @@ class RunScript extends BaseCommand { } async runWorkspaces (args, filters) { - const res = [] await this.setWorkspaces() + const errors = [] for (const workspacePath of this.workspacePaths) { const { content: pkg } = await pkgJson.normalize(workspacePath) - const runResult = await this.run(args, { - path: workspacePath, - pkg, - }).catch(err => { + try { + await this.run(args, { + path: workspacePath, + pkg, + }) + } catch (err) { log.error(`Lifecycle script \`${args[0]}\` failed with error:`) log.error(err) log.error(` in workspace: ${pkg._id || pkg.name}`) log.error(` at location: ${workspacePath}`) + errors.push(err) process.exitCode = 1 - }) - res.push(runResult) + } + } + + if (errors.some(r => r?.message.startsWith('Missing script'))) { + throw new Error(`Missing script: ${args[0]}`) } } diff --git a/lib/utils/exit-handler.js b/lib/utils/exit-handler.js index 25cecd170a584..279219197f952 100644 --- a/lib/utils/exit-handler.js +++ b/lib/utils/exit-handler.js @@ -131,28 +131,25 @@ const exitHandler = err => { log.level = level } - let exitCode = process.exitCode || 0 - let noLogMessage = exitCode !== 0 + let exitCode = err ? 1 : process.exitCode || 0 + let suppressLogMessage = !err let jsonError if (err) { - exitCode = 1 // if we got a command that just shells out to something else, then it // will presumably print its own errors and exit with a proper status // code if there's a problem. If we got an error with a code=0, then... // something else went wrong along the way, so maybe an npm problem? - const isShellout = npm.isShellout - const quietShellout = isShellout && typeof err.code === 'number' && err.code - if (quietShellout) { + if (npm.isShellout && typeof err.code === 'number' && err.code) { exitCode = err.code - noLogMessage = true + suppressLogMessage = true } else if (typeof err === 'string') { // XXX: we should stop throwing strings log.error('', err) - noLogMessage = true + suppressLogMessage = true } else if (!(err instanceof Error)) { log.error('weird error', err) - noLogMessage = true + suppressLogMessage = true } else { if (!err.code) { const matchErrorCode = err.message.match(/^(?:Error: )?(E[A-Z]+)/) @@ -208,11 +205,9 @@ const exitHandler = err => { npm.flushOutput(jsonError) } - log.verbose('exit', exitCode || 0) + log.verbose('exit', exitCode) - showLogFileError = (hasLoadedNpm && npm.silent) || noLogMessage - ? false - : !!exitCode + showLogFileError = npm?.silent || suppressLogMessage ? false : exitCode !== 0 // explicitly call process.exit now so we don't hang on things like the // update notifier, also flush stdout/err beforehand because process.exit doesn't diff --git a/smoke-tests/test/workspace-run-script-error-logs.js b/smoke-tests/test/workspace-run-script-error-logs.js new file mode 100644 index 0000000000000..bbfa4fe88903b --- /dev/null +++ b/smoke-tests/test/workspace-run-script-error-logs.js @@ -0,0 +1,19 @@ + +const t = require('tap') +const setup = require('./fixtures/setup.js') + +t.test('basic', async t => { + const { npm } = await setup(t) + + await t.test('npm install sends correct user-agent', async t => { + await npm('init', '-y') + await npm('init', '-y', `--workspace=pkga`) + await npm('init', '-y', `--workspace=pkgb`) + + await npm('pkg', 'set', '-w=pkga', `scripts.hello=echo a`) + + const logs = await npm('run', 'hello', '-ws').catch((r) => r.stderr) + + t.match(logs, 'A complete log of this run can be found in:', 'has log message') + }) +})