diff --git a/bin/nyc.js b/bin/nyc.js index 5f295abb7..4f216385a 100755 --- a/bin/nyc.js +++ b/bin/nyc.js @@ -2,6 +2,7 @@ 'use strict' const configUtil = require('../lib/config-util') +const { cliWrapper, suppressEPIPE } = require('../lib/commands/helpers') const foreground = require('foreground-child') const resolveFrom = require('resolve-from') const NYC = require('../index.js') @@ -81,29 +82,32 @@ async function main () { // a non-zero exit codes in either one leads to an overall non-zero exit code. process.exitCode = 0 foreground(childArgs, async () => { - var mainChildExitCode = process.exitCode - - await nyc.writeProcessIndex() - - nyc.maybePurgeSourceMapCache() - if (argv.checkCoverage) { - await nyc.checkCoverage({ - lines: argv.lines, - functions: argv.functions, - branches: argv.branches, - statements: argv.statements - }, argv['per-file']) - process.exitCode = process.exitCode || mainChildExitCode - } - - if (!argv.silent) { - await nyc.report() + const mainChildExitCode = process.exitCode + + try { + await nyc.writeProcessIndex() + + nyc.maybePurgeSourceMapCache() + if (argv.checkCoverage) { + await nyc.checkCoverage({ + lines: argv.lines, + functions: argv.functions, + branches: argv.branches, + statements: argv.statements + }, argv['per-file']).catch(suppressEPIPE) + process.exitCode = process.exitCode || mainChildExitCode + } + + if (!argv.silent) { + await nyc.report().catch(suppressEPIPE) + } + } catch (error) { + /* istanbul ignore next */ + process.exitCode = process.exitCode || mainChildExitCode || 1 + /* istanbul ignore next */ + console.error(error.message) } }) } -/* istanbul ignore next: the error branch should be unreachable */ -main().catch(error => { - console.error(error.message) - process.exit(1) -}) +cliWrapper(main)() diff --git a/lib/commands/check-coverage.js b/lib/commands/check-coverage.js index 56ffdf219..cc361d16e 100644 --- a/lib/commands/check-coverage.js +++ b/lib/commands/check-coverage.js @@ -1,7 +1,7 @@ 'use strict' const NYC = require('../../index.js') -const { cliWrapper, setupOptions } = require('./helpers.js') +const { cliWrapper, suppressEPIPE, setupOptions } = require('./helpers.js') exports.command = 'check-coverage' @@ -24,5 +24,5 @@ exports.handler = cliWrapper(async argv => { functions: argv.functions, branches: argv.branches, statements: argv.statements - }, argv['per-file']) + }, argv['per-file']).catch(suppressEPIPE) }) diff --git a/lib/commands/helpers.js b/lib/commands/helpers.js index 8b967bd81..92e09242b 100644 --- a/lib/commands/helpers.js +++ b/lib/commands/helpers.js @@ -50,10 +50,23 @@ module.exports = { } }) }, + /* istanbul ignore next: unsure how to test this */ + suppressEPIPE (error) { + /* Prevent dumping error when `nyc npm t|head` causes stdout to + * be closed when reporting runs. */ + if (error.code !== 'EPIPE') { + throw error + } + }, cliWrapper (execute) { return argv => { execute(argv).catch(error => { - console.error(error.message) + try { + console.error(error.message) + } catch (_) { + /* We need to run process.exit(1) even if stderr is destroyed */ + } + process.exit(1) }) } diff --git a/lib/commands/report.js b/lib/commands/report.js index 8293bf790..6efb44166 100644 --- a/lib/commands/report.js +++ b/lib/commands/report.js @@ -1,7 +1,7 @@ 'use strict' const NYC = require('../../index.js') -const { cliWrapper, setupOptions } = require('./helpers.js') +const { cliWrapper, suppressEPIPE, setupOptions } = require('./helpers.js') exports.command = 'report' @@ -18,13 +18,13 @@ exports.builder = function (yargs) { exports.handler = cliWrapper(async argv => { process.env.NYC_CWD = process.cwd() var nyc = new NYC(argv) - await nyc.report() + await nyc.report().catch(suppressEPIPE) if (argv.checkCoverage) { await nyc.checkCoverage({ lines: argv.lines, functions: argv.functions, branches: argv.branches, statements: argv.statements - }, argv['per-file']) + }, argv['per-file']).catch(suppressEPIPE) } })