Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: nyc no longer tries to run arguments passed to the instrumented bin #322

Merged
merged 2 commits into from
Jul 24, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
292 changes: 155 additions & 137 deletions bin/nyc.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,145 +7,14 @@ try {
} catch (e) {
NYC = require('../index.js')
}
var processArgs = require('../lib/process-args')

var sw = require('spawn-wrap')
var wrapper = require.resolve('./wrap.js')
var Yargs = require('yargs/yargs')

var yargs = require('yargs/yargs')(process.argv.slice(2))
.usage('$0 [command] [options]\n\nrun your tests with the nyc bin to instrument them with coverage')
.command('report', 'run coverage report for .nyc_output', function (yargs) {
return yargs
.usage('$0 report [options]')
.option('reporter', {
alias: 'r',
describe: 'coverage reporter(s) to use',
default: 'text'
})
.option('report-dir', {
describe: 'directory to output coverage reports in',
default: 'coverage'
})
.option('temp-directory', {
describe: 'directory from which coverage JSON files are read',
default: './.nyc_output'
})
.example('$0 report --reporter=lcov', 'output an HTML lcov report to ./coverage')
})
.command('check-coverage', 'check whether coverage is within thresholds provided', function (yargs) {
return yargs
.usage('$0 check-coverage [options]')
.option('branches', {
default: 0,
description: 'what % of branches must be covered?'
})
.option('functions', {
default: 0,
description: 'what % of functions must be covered?'
})
.option('lines', {
default: 90,
description: 'what % of lines must be covered?'
})
.option('statements', {
default: 0,
description: 'what % of statements must be covered?'
})
.example('$0 check-coverage --lines 95', "check whether the JSON in nyc's output folder meets the thresholds provided")
})
.command(require('../lib/commands/instrument'))
.option('reporter', {
alias: 'r',
describe: 'coverage reporter(s) to use',
default: 'text'
})
.option('report-dir', {
describe: 'directory to output coverage reports in',
default: 'coverage'
})
.option('silent', {
alias: 's',
default: false,
type: 'boolean',
describe: "don't output a report after tests finish running"
})
.option('all', {
alias: 'a',
default: false,
type: 'boolean',
describe: 'whether or not to instrument all files of the project (not just the ones touched by your test suite)'
})
.option('exclude', {
alias: 'x',
default: [],
describe: 'a list of specific files and directories that should be excluded from coverage, glob patterns are supported, node_modules is always excluded'
})
.option('include', {
alias: 'n',
default: [],
describe: 'a list of specific files that should be covered, glob patterns are supported'
})
.option('require', {
alias: 'i',
default: [],
describe: 'a list of additional modules that nyc should attempt to require in its subprocess, e.g., babel-register, babel-polyfill.'
})
.option('cache', {
alias: 'c',
default: false,
type: 'boolean',
describe: 'cache instrumentation results for improved performance'
})
.option('extension', {
alias: 'e',
default: [],
describe: 'a list of extensions that nyc should handle in addition to .js'
})
.option('check-coverage', {
type: 'boolean',
default: false,
describe: 'check whether coverage is within thresholds provided'
})
.option('branches', {
default: 0,
description: 'what % of branches must be covered?'
})
.option('functions', {
default: 0,
description: 'what % of functions must be covered?'
})
.option('lines', {
default: 90,
description: 'what % of lines must be covered?'
})
.option('statements', {
default: 0,
description: 'what % of statements must be covered?'
})
.option('source-map', {
default: true,
type: 'boolean',
description: 'should nyc detect and handle source maps?'
})
.option('instrument', {
default: true,
type: 'boolean',
description: 'should nyc handle instrumentation?'
})
.option('hook-run-in-context', {
default: true,
type: 'boolean',
description: 'should nyc wrap vm.runInThisContext?'
})
.help('h')
.alias('h', 'help')
.version()
.pkgConf('nyc', process.cwd())
.example('$0 npm test', 'instrument your tests with coverage')
.example('$0 --require babel-core/register npm test', 'instrument your tests with coverage and babel')
.example('$0 report --reporter=text-lcov', 'output lcov report after running your tests')
.epilog('visit https://git.io/voHar for list of available reporters')

var argv = yargs.argv
var yargs = decorateYargs(buildYargs())
var argv = yargs.parse(processArgs.hideInstrumenteeArgs())

if (argv._[0] === 'report') {
// run a report.
Expand All @@ -155,7 +24,7 @@ if (argv._[0] === 'report') {
} else if (argv._[0] === 'check-coverage') {
checkCoverage(argv)
} else if (argv._[0] === 'instrument') {
// noop, let the command handler do its thing.
// look in lib/commands/instrument.js for logic.
} else if (argv._.length) {
// wrap subprocesses and execute argv[1]
argv.require = arrify(argv.require)
Expand Down Expand Up @@ -206,7 +75,11 @@ if (argv._[0] === 'report') {
// set process.exitCode. Keep track so that both children are run, but
// a non-zero exit codes in either one leads to an overall non-zero exit code.
process.exitCode = 0
foreground(nyc.mungeArgs(argv), function (done) {
foreground(processArgs.hideInstrumenterArgs(
// use the same argv descrption, but don't exit
// for flags like --help.
buildYargs().parse(process.argv.slice(2))
), function (done) {
var mainChildExitCode = process.exitCode

if (argv.checkCoverage) {
Expand Down Expand Up @@ -244,3 +117,148 @@ function checkCoverage (argv, cb) {
statements: argv.statements
})
}

function buildYargs () {
return Yargs([])
.usage('$0 [command] [options]\n\nrun your tests with the nyc bin to instrument them with coverage')
.command('report', 'run coverage report for .nyc_output', function (yargs) {
return yargs
.usage('$0 report [options]')
.option('reporter', {
alias: 'r',
describe: 'coverage reporter(s) to use',
default: 'text'
})
.option('report-dir', {
describe: 'directory to output coverage reports in',
default: 'coverage'
})
.option('temp-directory', {
describe: 'directory from which coverage JSON files are read',
default: './.nyc_output'
})
.example('$0 report --reporter=lcov', 'output an HTML lcov report to ./coverage')
})
.command('check-coverage', 'check whether coverage is within thresholds provided', function (yargs) {
return yargs
.usage('$0 check-coverage [options]')
.option('branches', {
default: 0,
description: 'what % of branches must be covered?'
})
.option('functions', {
default: 0,
description: 'what % of functions must be covered?'
})
.option('lines', {
default: 90,
description: 'what % of lines must be covered?'
})
.option('statements', {
default: 0,
description: 'what % of statements must be covered?'
})
.example('$0 check-coverage --lines 95', "check whether the JSON in nyc's output folder meets the thresholds provided")
})
.option('reporter', {
alias: 'r',
describe: 'coverage reporter(s) to use',
default: 'text'
})
.option('report-dir', {
describe: 'directory to output coverage reports in',
default: 'coverage'
})
.option('silent', {
alias: 's',
default: false,
type: 'boolean',
describe: "don't output a report after tests finish running"
})
.option('all', {
alias: 'a',
default: false,
type: 'boolean',
describe: 'whether or not to instrument all files of the project (not just the ones touched by your test suite)'
})
.option('exclude', {
alias: 'x',
default: [],
describe: 'a list of specific files and directories that should be excluded from coverage, glob patterns are supported, node_modules is always excluded'
})
.option('include', {
alias: 'n',
default: [],
describe: 'a list of specific files that should be covered, glob patterns are supported'
})
.option('require', {
alias: 'i',
default: [],
describe: 'a list of additional modules that nyc should attempt to require in its subprocess, e.g., babel-register, babel-polyfill.'
})
.option('cache', {
alias: 'c',
default: false,
type: 'boolean',
describe: 'cache instrumentation results for improved performance'
})
.option('extension', {
alias: 'e',
default: [],
describe: 'a list of extensions that nyc should handle in addition to .js'
})
.option('check-coverage', {
type: 'boolean',
default: false,
describe: 'check whether coverage is within thresholds provided'
})
.option('branches', {
default: 0,
description: 'what % of branches must be covered?'
})
.option('functions', {
default: 0,
description: 'what % of functions must be covered?'
})
.option('lines', {
default: 90,
description: 'what % of lines must be covered?'
})
.option('statements', {
default: 0,
description: 'what % of statements must be covered?'
})
.option('source-map', {
default: true,
type: 'boolean',
description: 'should nyc detect and handle source maps?'
})
.option('instrument', {
default: true,
type: 'boolean',
description: 'should nyc handle instrumentation?'
})
.option('hook-run-in-context', {
default: true,
type: 'boolean',
description: 'should nyc wrap vm.runInThisContext?'
})
.pkgConf('nyc', process.cwd())
.example('$0 npm test', 'instrument your tests with coverage')
.example('$0 --require babel-core/register npm test', 'instrument your tests with coverage and babel')
.example('$0 report --reporter=text-lcov', 'output lcov report after running your tests')
.epilog('visit https://git.io/voHar for list of available reporters')
.boolean('help')
.boolean('h')
.boolean('version')
}

// decorate yargs with all the actions
// that would make it exit: help, version, command.
function decorateYargs (yargs) {
return yargs
.help('h')
.alias('h', 'help')
.version()
.command(require('../lib/commands/instrument'))
}
6 changes: 0 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -473,10 +473,4 @@ NYC.prototype.tempDirectory = function () {
return path.resolve(this.cwd, './', this._tempDirectory)
}

NYC.prototype.mungeArgs = function (yargv) {
var argv = process.argv.slice(1)
argv = argv.slice(argv.indexOf(yargv._[0]))
return argv
}

module.exports = NYC
33 changes: 33 additions & 0 deletions lib/process-args.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
var parser = require('yargs-parser')
var commands = [
'report',
'check-coverage',
'instrument'
]

module.exports = {
// don't pass arguments that are meant
// for nyc to the bin being instrumented.
hideInstrumenterArgs: function (yargv) {
var argv = process.argv.slice(1)
argv = argv.slice(argv.indexOf(yargv._[0]))
return argv
},
// don't pass arguments for the bin being
// instrumented to nyc.
hideInstrumenteeArgs: function () {
var argv = process.argv.slice(2)
var yargv = parser(argv)
if (!yargv._.length) return argv
for (var i = 0, command; (command = yargv._[i]) !== undefined; i++) {
if (~commands.indexOf(command)) return argv
}

// drop all the arguments after the bin being
// instrumented by nyc.
argv = argv.slice(0, argv.indexOf(yargv._[0]))
argv.push(yargv._[0])

return argv
}
}
Loading