diff --git a/index.js b/index.js index 872c7fa84f..fa42babf92 100644 --- a/index.js +++ b/index.js @@ -126,17 +126,19 @@ function makeError(result, options) { let {error} = result; const {joinedCommand, timedOut, parsed: {options: {timeout}}} = options; - const [codeString, codeNumber] = getCode(result, code); + const [exitCodeName, exitCode] = getCode(result, code); if (!(error instanceof Error)) { const message = [joinedCommand, stderr, stdout].filter(Boolean).join('\n'); error = new Error(message); } - const prefix = getErrorPrefix({timedOut, timeout, signal, codeString, codeNumber}); + const prefix = getErrorPrefix({timedOut, timeout, signal, exitCodeName, exitCode}); error.message = `Command ${prefix}: ${error.message}`; - error.code = codeNumber || codeString; + error.code = exitCode || exitCodeName; + error.exitCode = exitCode; + error.exitCodeName = exitCodeName; error.stdout = stdout; error.stderr = stderr; error.failed = true; @@ -159,7 +161,7 @@ function getCode({error = {}}, code) { return []; } -function getErrorPrefix({timedOut, timeout, signal, codeString, codeNumber}) { +function getErrorPrefix({timedOut, timeout, signal, exitCodeName, exitCode}) { if (timedOut) { return `timed out after ${timeout} milliseconds`; } @@ -168,16 +170,16 @@ function getErrorPrefix({timedOut, timeout, signal, codeString, codeNumber}) { return `was killed with ${signal}`; } - if (codeString !== undefined && codeNumber !== undefined) { - return `failed with exit code ${codeNumber} (${codeString})`; + if (exitCodeName !== undefined && exitCode !== undefined) { + return `failed with exit code ${exitCode} (${exitCodeName})`; } - if (codeString !== undefined) { - return `failed with exit code ${codeString}`; + if (exitCodeName !== undefined) { + return `failed with exit code ${exitCodeName}`; } - if (codeNumber !== undefined) { - return `failed with exit code ${codeNumber}`; + if (exitCode !== undefined) { + return `failed with exit code ${exitCode}`; } return 'failed'; @@ -296,6 +298,8 @@ module.exports = (command, args, options) => { stdout: handleOutput(parsed.options, result.stdout), stderr: handleOutput(parsed.options, result.stderr), code: 0, + exitCode: 0, + exitCodeName: 'SUCCESS', failed: false, killed: false, signal: null, @@ -362,6 +366,8 @@ module.exports.sync = (command, args, options) => { stdout: handleOutput(parsed.options, result.stdout), stderr: handleOutput(parsed.options, result.stderr), code: 0, + exitCode: 0, + exitCodeName: 'SUCCESS', failed: false, signal: null, cmd: joinedCommand, diff --git a/readme.md b/readme.md index b6921faaaf..f32ad38eb8 100644 --- a/readme.md +++ b/readme.md @@ -59,14 +59,17 @@ const execa = require('execa'); console.log(error); /* { - message: 'Command failed: /bin/sh -c exit 3' - killed: false, + message: 'Command failed with exit code 3 (ESRCH): exit 3', code: 3, - signal: null, - cmd: '/bin/sh -c exit 3', + exitCode: 3, + exitCodeName: 'ESRCH', stdout: '', stderr: '', - timedOut: false + failed: true, + signal: null, + cmd: 'exit 3', + timedOut: false, + killed: false } */ } @@ -79,12 +82,15 @@ try { console.log(error); /* { - message: 'Command failed: /bin/sh -c exit 3' + message: 'Command failed with exit code 3 (ESRCH): exit 3', code: 3, - signal: null, - cmd: '/bin/sh -c exit 3', + exitCode: 3, + exitCodeName: 'ESRCH', stdout: '', stderr: '', + failed: true, + signal: null, + cmd: 'exit 3', timedOut: false } */ diff --git a/test.js b/test.js index 93b3e0d149..3e72c60d53 100644 --- a/test.js +++ b/test.js @@ -259,14 +259,22 @@ test('skip throwing when using reject option', async t => { }); test('allow unknown exit code', async t => { - await t.throwsAsync(execa('exit', ['255']), {message: /exit code 255 \(Unknown system error -255\)/}); + const {exitCode, exitCodeName} = await t.throwsAsync(execa('exit', ['255']), {message: /exit code 255 \(Unknown system error -255\)/}); + t.is(exitCode, 255); + t.is(exitCodeName, 'Unknown system error -255'); }); test('execa() returns code and failed properties', async t => { - const {code, failed} = await execa('noop', ['foo']); - const error = await t.throwsAsync(execa('exit', ['2']), {code: 2, message: getExitRegExp('2')}); + const {code, exitCode, exitCodeName, failed} = await execa('noop', ['foo']); t.is(code, 0); + t.is(exitCode, 0); + t.is(exitCodeName, 'SUCCESS'); t.false(failed); + + const error = await t.throwsAsync(execa('exit', ['2']), {code: 2, message: getExitRegExp('2')}); + t.is(error.exitCode, 2); + const expectedName = process.platform === 'win32' ? 'Unknown system error -2' : 'ENOENT'; + t.is(error.exitCodeName, expectedName); t.true(error.failed); }); @@ -361,7 +369,8 @@ test('result.signal is null if process failed, but was not killed', async t => { }); async function code(t, num) { - await t.throwsAsync(execa('exit', [`${num}`]), {code: num, message: getExitRegExp(num)}); + const error = await t.throwsAsync(execa('exit', [`${num}`]), {code: num, message: getExitRegExp(num)}); + t.is(error.exitCode, num); } test('error.code is 2', code, 2); @@ -372,7 +381,7 @@ test('timeout will kill the process early', async t => { const error = await t.throwsAsync(execa('delay', ['60000', '0'], {timeout: 1500, message: TIMEOUT_REGEXP})); t.true(error.timedOut); - t.not(error.code, 22); + t.not(error.exitCode, 22); }); test('timeout will not kill the process early', async t => { @@ -461,7 +470,7 @@ if (process.platform !== 'win32') { await execa(`fast-exit-${process.platform}`, [], {input: 'data'}); t.pass(); } catch (error) { - t.is(error.code, 32); + t.is(error.exitCode, 32); } }); }