Exit with an error code in the face of unhandled errors (#495)

As part of fixing the exit bug recently, we accidentally made errors
lead to zero exit codes.  As a result, the Pulumi CLI thought the
prgoram exited ordinarily, and proceeded to do its usual planning and
deployment, rather than terminating abruptly.

This is a byproduct of how Node's process.uncaughtException handler
works.  It hijacks and replaces all usual error logic, including the
process.exit part.  This change simply adds back the non-zero exit.

I also added a test (and fixed one other that began failing
afterwards), so that we can prevent regressions down the road.
This commit is contained in:
Joe Duffy 2017-10-28 17:05:05 -07:00 committed by GitHub
parent 2344f9e079
commit cdb2c79e8e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 13 additions and 4 deletions

View file

@ -126,6 +126,7 @@ export function main(args: string[]): void {
// Set up the process unhandled exception handler and the program exit handler. // Set up the process unhandled exception handler and the program exit handler.
process.on("uncaughtException", (err: Error) => { process.on("uncaughtException", (err: Error) => {
// First, log the error.
if (err instanceof RunError) { if (err instanceof RunError) {
// For errors that are subtypes of RunError, we will print the message without hitting the unhandled error // For errors that are subtypes of RunError, we will print the message without hitting the unhandled error
// logic, which will dump all sorts of verbose spew like the origin source and stack trace. // logic, which will dump all sorts of verbose spew like the origin source and stack trace.
@ -135,6 +136,8 @@ export function main(args: string[]): void {
console.log(`Running program '${program}' failed with an unhandled exception:`); console.log(`Running program '${program}' failed with an unhandled exception:`);
console.log(err); console.log(err);
} }
// And next, exit with a non-zero exit code.
process.exit(1);
}); });
process.on("exit", () => { runtime.disconnectSync(); }); process.on("exit", () => { runtime.disconnectSync(); });

View file

@ -179,4 +179,3 @@ function stripEOL(data: string | Buffer): string {
} }
return dataString; return dataString;
} }

View file

@ -6,7 +6,7 @@ const pulumi = require("../../../../../");
assert.equal(pulumi.getProject(), "runtimeSettingsProject"); assert.equal(pulumi.getProject(), "runtimeSettingsProject");
assert.equal(pulumi.getStack(), "runtimeSettingsStack"); assert.equal(pulumi.getStack(), "runtimeSettingsStack");
const config = new pulumi.Config("myBag"); const config = new pulumi.Config("myBag:config");
assert.equal(config.getNumber("A"), 42); assert.equal(config.getNumber("A"), 42);
assert.equal(config.requireNumber("A"), 42); assert.equal(config.requireNumber("A"), 42);
assert.equal(config.get("bbbb"), "a string o' b's"); assert.equal(config.get("bbbb"), "a string o' b's");

View file

@ -0,0 +1 @@
throw new Error("💥 goes the dynamite");

View file

@ -276,12 +276,18 @@ describe("rpc", () => {
project: "runtimeSettingsProject", project: "runtimeSettingsProject",
stack: "runtimeSettingsStack", stack: "runtimeSettingsStack",
config: { config: {
"myBag:A": 42, "myBag:config:A": "42",
"myBag:bbbb": "a string o' b's", "myBag:config:bbbb": "a string o' b's",
}, },
program: path.join(base, "010.runtime_settings"), program: path.join(base, "010.runtime_settings"),
expectResourceCount: 0, expectResourceCount: 0,
}, },
// A program that throws an ordinary unhandled error.
"unhandled_error": {
program: path.join(base, "011.unhandled_error"),
expectResourceCount: 0,
expectError: "Program exited with non-zero exit code: 1",
},
}; };
for (const casename of Object.keys(cases)) { for (const casename of Object.keys(cases)) {