diff --git a/integration/lerna-publish-lifecycle-errors.test.js b/integration/lerna-publish-lifecycle-errors.test.js index 2e8eb5921d..306bf459ae 100644 --- a/integration/lerna-publish-lifecycle-errors.test.js +++ b/integration/lerna-publish-lifecycle-errors.test.js @@ -26,7 +26,6 @@ test("lerna publish lifecycle scripts stop on non-zero exit", async () => { const json = await fs.readJson(rootManifest); json.scripts.preversion = "echo boom && exit 123"; - // console.log(json); await fs.writeJson(rootManifest, json); await gitAdd(cwd, rootManifest); @@ -56,11 +55,7 @@ lerna info Looking for changed packages since initial commit. lerna info auto-confirmed lerna info lifecycle lifecycle@0.0.0-monorepo~preversion: lifecycle@0.0.0-monorepo lerna info lifecycle lifecycle@0.0.0-monorepo~preversion: Failed to exec preversion script -lerna ERR! lifecycle "preversion" errored in "lifecycle", ejecting -lerna ERR! exited 123 in 'lifecycle' -lerna ERR! exited 123 in 'lifecycle' -lerna ERR! exited 123 in 'lifecycle' -lerna ERR! exited 123 in 'lifecycle' +lerna ERR! lifecycle "preversion" errored in "lifecycle", exiting 123 `); } diff --git a/utils/run-lifecycle/__tests__/run-lifecycle.test.js b/utils/run-lifecycle/__tests__/run-lifecycle.test.js index 28ee6b00c5..f5fb32a39c 100644 --- a/utils/run-lifecycle/__tests__/run-lifecycle.test.js +++ b/utils/run-lifecycle/__tests__/run-lifecycle.test.js @@ -94,11 +94,12 @@ describe("createRunner", () => { }); it("logs script error and re-throws", async () => { - npmLifecycle.mockImplementationOnce(() => { + npmLifecycle.mockImplementationOnce(({ scripts }, stage) => { const err = new Error("boom"); // https://git.io/fAE3f err.errno = 123; + err.script = scripts[stage]; return Promise.reject(err); }); @@ -107,17 +108,46 @@ describe("createRunner", () => { name: "has-script-error", version: "1.0.0", location: "test", - scripts: { prepublishOnly: "exit 1" }, + scripts: { prepublishOnly: "exit 123" }, }; try { await runPackageLifecycle(pkg, "prepublishOnly"); } catch (err) { - expect(err.pkg).toBe(pkg); + expect(err.code).toBe(123); + expect(err.script).toBe("exit 123"); expect(process.exitCode).toBe(123); } const [errorLog] = loggingOutput("error"); - expect(errorLog).toMatch('"prepublishOnly" errored in "has-script-error", ejecting'); + expect(errorLog).toBe('"prepublishOnly" errored in "has-script-error", exiting 123'); + }); + + it("defaults error exit code to 1", async () => { + npmLifecycle.mockImplementationOnce(({ scripts }, stage) => { + const err = new Error("kersplode"); + + // errno only gets added when a proc closes, not from error + err.script = scripts[stage]; + + return Promise.reject(err); + }); + + const pkg = { + name: "has-execution-error", + version: "1.0.0", + location: "test", + scripts: { prepack: "a-thing-that-ends-poorly" }, + }; + + try { + await runPackageLifecycle(pkg, "prepack"); + } catch (err) { + expect(err.code).toBe(1); + expect(err.script).toBe("a-thing-that-ends-poorly"); + } + + const [errorLog] = loggingOutput("error"); + expect(errorLog).toBe('"prepack" errored in "has-execution-error", exiting 1'); }); }); diff --git a/utils/run-lifecycle/run-lifecycle.js b/utils/run-lifecycle/run-lifecycle.js index 3736c1f999..2174dd5355 100644 --- a/utils/run-lifecycle/run-lifecycle.js +++ b/utils/run-lifecycle/run-lifecycle.js @@ -37,20 +37,20 @@ function runLifecycle(pkg, stage, opts) { }).then( () => pkg, err => { - // error logging has already occurred on stderr, but we need to stop the chain - log.error("lifecycle", "%j errored in %j, ejecting", stage, pkg.name); + // propagate the exit code + const exitCode = err.errno || 1; - // ensure clean logging... - err.pkg = pkg; + // error logging has already occurred on stderr, but we need to stop the chain + log.error("lifecycle", "%j errored in %j, exiting %d", stage, pkg.name, exitCode); - // ...propagate the exit code... - const exitCode = err.errno; + // ensure clean logging, avoiding spurious log dump + err.name = "ValidationError"; - // (using the property our yargs.fail() handler expects :P) + // our yargs.fail() handler expects a numeric .code, not .errno err.code = exitCode; process.exitCode = exitCode; - // ...and send it on its merry way + // stop the chain throw err; } );