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 0b9ee3da57c60..279219197f952 100644 --- a/lib/utils/exit-handler.js +++ b/lib/utils/exit-handler.js @@ -132,7 +132,7 @@ const exitHandler = err => { } let exitCode = err ? 1 : process.exitCode || 0 - let suppressLogMessage = exitCode === 0 + let suppressLogMessage = !err let jsonError if (err) { @@ -140,10 +140,8 @@ const exitHandler = err => { // 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) { - exitCode = err.code || 0 + if (npm.isShellout && typeof err.code === 'number' && err.code) { + exitCode = err.code suppressLogMessage = true } else if (typeof err === 'string') { // XXX: we should stop throwing strings @@ -209,9 +207,7 @@ const exitHandler = err => { log.verbose('exit', exitCode) - showLogFileError = (hasLoadedNpm && npm.silent) || suppressLogMessage - ? false - : exitCode !== 0 + 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 index 179b0f4306197..bbfa4fe88903b 100644 --- a/smoke-tests/test/workspace-run-script-error-logs.js +++ b/smoke-tests/test/workspace-run-script-error-logs.js @@ -11,7 +11,6 @@ t.test('basic', async t => { await npm('init', '-y', `--workspace=pkgb`) await npm('pkg', 'set', '-w=pkga', `scripts.hello=echo a`) - await npm('pkg', 'set', '-w=pkgb', `scripts.hello=exit 1`) const logs = await npm('run', 'hello', '-ws').catch((r) => r.stderr)