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: adds instrument command line option #298

Merged
merged 4 commits into from
Jul 7, 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
33 changes: 21 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
[![Windows Tests](https://img.shields.io/appveyor/ci/bcoe/nyc-ilw23/master.svg?label=Windows%20Tests)](https://ci.appveyor.com/project/bcoe/nyc-ilw23)
[![Standard Version](https://img.shields.io/badge/release-standard%20version-brightgreen.svg)](https://github.com/conventional-changelog/standard-version)

Istanbul's high-tech command line interface, with support for:
Istanbul's state of the art command line interface, with support for:

* applications that spawn subprocesses.
* ES2015 transforms, via [babel-plugin-istanbul](https://github.com/istanbuljs/babel-plugin-istanbul), or source-maps.

## Instrumenting Your Code
## Instrumenting your code

You can install nyc as a development dependency and add it to the test stanza
in your package.json.
Expand Down Expand Up @@ -50,10 +50,10 @@ and a `text-lcov` coverage report.
nyc --reporter=lcov --reporter=text-lcov npm test
```

## Support For Custom Require Hooks (Babel! ES2015!)
## Support for custom require hooks (babel, webpack, etc.)

nyc supports custom require hooks like
[`babel-register`](http://babeljs.io/docs/usage/require/). If necessary nyc can
[`babel-register`](http://babeljs.io/docs/usage/require/). nyc can
load the hooks for you, [using the `--require`
flag](#require-additional-modules).

Expand All @@ -62,7 +62,7 @@ of the pre-transpiled code. You'll have to configure your custom require hook
to inline the source map in the transpiled code. For Babel that means setting
the `sourceMaps` option to `inline`.

## Use with babel-plugin-istanbul for Better ES6/ES7 Support
## Use with babel-plugin-istanbul for ES6/ES7/ES2015 Support

[`babel-plugin-istanbul`](https://github.com/istanbuljs/babel-plugin-istanbul) can be used to enable better first-class ES6 support.

Expand Down Expand Up @@ -107,7 +107,7 @@ That's all there is to it, better ES6 syntax highlighting awaits:

<img width="500" src="screen2.png">

## Support For Custom File Extensions (.jsx, .es6)
## Support for alternate file extensions (.jsx, .es6)

Supporting file extensions can be configured through either the configuration arguments or with the `nyc` config section in `package.json`.

Expand All @@ -126,7 +126,7 @@ nyc --extension .jsx --extension .es6 npm test
}
```

## Checking Coverage
## Checking coverage

nyc can fail tests if coverage falls below a threshold.
After running your tests with nyc, simply run:
Expand All @@ -144,7 +144,7 @@ nyc --check-coverage --lines 100 npm test

The above check fails if coverage falls below 100%.

## Running Reports
## Running reports

Once you've run your tests with nyc, simply run:

Expand All @@ -162,7 +162,7 @@ you can use any reporters that are supported by istanbul:
nyc report --reporter=lcov
```

## Excluding Files
## Excluding files

You can tell nyc to exclude specific files and directories by adding
an `nyc.exclude` array to your `package.json`. Each element of
Expand Down Expand Up @@ -192,7 +192,7 @@ directory:
which would exclude `test`/`__tests__` directories as well as `test.js`, `*.test.js`,
and `test-*.js` files. Specifying your own exclude property overrides these defaults.

## Including Files
## Including files

As an alternative to providing a list of files to `exclude`, you can provide
an `include` key to specify specific files that should be covered:
Expand All @@ -207,7 +207,7 @@ an `include` key to specify specific files that should be covered:

> Note: include defaults to `['**']`

## Include Reports For Files That Are Not Required
## Include reports for files that are not required

By default nyc does not collect coverage for files that have not
been required, run nyc with the flag `--all` to enable this.
Expand Down Expand Up @@ -240,7 +240,16 @@ can also be specified in the `nyc` stanza of your package.json:
}
```

## Integrating With Coveralls
## Instrumenting source files

nyc's `instrument` command can be used to instrument
source files outside of the context of your unit-tests:

__instrument the entire ./lib folder:__

`nyc instrument ./lib ./output`

## Integrating with coveralls

[coveralls.io](https://coveralls.io) is a great tool for adding
coverage reports to your GitHub project. Here's how to get nyc
Expand Down
52 changes: 37 additions & 15 deletions bin/nyc.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,47 @@ var yargs = require('yargs/yargs')(process.argv.slice(2))
.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'
})
.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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. Is there a reason this is 90 instead of 0?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just picking defaults based on personal preference, I tend to find a project with 90%+ test coverage is pretty healthy.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Maybe I'm misunderstanding what these numbers mean, but shouldn't that be true of the other thresholds as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're right, just not as experienced with the other thresholds.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, me either. I only think that I sort of understand what they really mean, but I'm not certain...

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',
global: true
default: 'text'
})
.option('report-dir', {
describe: 'default directory to output coverage reports in',
default: 'coverage',
global: true
describe: 'directory to output coverage reports in',
default: 'coverage'
})
.option('silent', {
alias: 's',
Expand Down Expand Up @@ -67,7 +91,7 @@ var yargs = require('yargs/yargs')(process.argv.slice(2))
type: 'boolean',
describe: 'cache instrumentation results for improved performance'
})
.options('extension', {
.option('extension', {
alias: 'e',
default: [],
describe: 'a list of extensions that nyc should handle in addition to .js'
Expand All @@ -79,23 +103,19 @@ var yargs = require('yargs/yargs')(process.argv.slice(2))
})
.option('branches', {
default: 0,
description: 'what % of branches must be covered?',
global: true
description: 'what % of branches must be covered?'
})
.option('functions', {
default: 0,
description: 'what % of functions must be covered?',
global: true
description: 'what % of functions must be covered?'
})
.option('lines', {
default: 90,
description: 'what % of lines must be covered?',
global: true
description: 'what % of lines must be covered?'
})
.option('statements', {
default: 0,
description: 'what % of statements must be covered?',
global: true
description: 'what % of statements must be covered?'
})
.option('source-map', {
default: true,
Expand All @@ -112,7 +132,7 @@ var yargs = require('yargs/yargs')(process.argv.slice(2))
.version()
.pkgConf('nyc', process.cwd())
.example('$0 npm test', 'instrument your tests with coverage')
.example('$0 --require --require babel-core/register npm test', 'instrument your tests with coverage and babel')
.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')

Expand All @@ -125,6 +145,8 @@ if (argv._[0] === 'report') {
report(argv)
} else if (argv._[0] === 'check-coverage') {
checkCoverage(argv)
} else if (argv._[0] === 'instrument') {
// noop, let the command handler do its thing.
} else if (argv._.length) {
// wrap subprocesses and execute argv[1]
argv.require = arrify(argv.require)
Expand Down
67 changes: 58 additions & 9 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,18 +157,10 @@ NYC.prototype.addAllFiles = function () {

this._loadAdditionalModules()

var pattern = null
if (this.extensions.length === 1) {
pattern = '**/*' + this.extensions[0]
} else {
pattern = '**/*{' + this.extensions.join() + '}'
}

this.fakeRequire = true
glob.sync(pattern, {cwd: this.cwd, nodir: true, ignore: this.exclude.exclude}).forEach(function (filename) {
this.walkAllFiles(this.cwd, function (filename) {
filename = path.resolve(_this.cwd, filename)
_this.addFile(filename)

var coverage = coverageFinder()
var lastCoverage = _this.instrumenter().lastFileCoverage()
if (lastCoverage && _this.exclude.shouldInstrument(filename)) {
Expand All @@ -180,6 +172,63 @@ NYC.prototype.addAllFiles = function () {
this.writeCoverageFile()
}

NYC.prototype.instrumentAllFiles = function (input, output, cb) {
var _this = this
var inputDir = '.' + path.sep
var visitor = function (filename) {
var ext
var transform
var inFile = path.relative(_this.cwd, path.resolve(inputDir, filename))
var code = fs.readFileSync(inFile, 'utf-8')

for (ext in _this.transforms) {
if (filename.toLowerCase().substr(-ext.length) === ext) {
transform = _this.transforms[ext]
break
}
}

if (transform) {
code = transform(code, {filename: filename, relFile: inFile})
}

if (!output) {
console.log(code)
} else {
var outFile = path.relative(_this.cwd, path.resolve(output, filename))
mkdirp.sync(path.dirname(outFile))
fs.writeFileSync(outFile, code, 'utf-8')
}
}

this._loadAdditionalModules()

try {
var stats = fs.lstatSync(input)
if (stats.isDirectory()) {
inputDir = input
this.walkAllFiles(input, visitor)
} else {
visitor(input)
}
} catch (err) {
return cb(err)
}
}

NYC.prototype.walkAllFiles = function (dir, visitor) {
var pattern = null
if (this.extensions.length === 1) {
pattern = '**/*' + this.extensions[0]
} else {
pattern = '**/*{' + this.extensions.join() + '}'
}

glob.sync(pattern, {cwd: dir, nodir: true, ignore: this.exclude.exclude}).forEach(function (filename) {
visitor(filename)
})
}

NYC.prototype._maybeInstrumentSource = function (code, filename, relFile) {
var instrument = this.exclude.shouldInstrument(filename, relFile)
if (!instrument) {
Expand Down
55 changes: 55 additions & 0 deletions lib/commands/instrument.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
var NYC
try {
NYC = require('../../index.covered.js')
} catch (e) {
NYC = require('../../index.js')
}

exports.command = 'instrument <input> [output]'

exports.describe = 'instruments a file or a directory tree and writes the instrumented code to the desired output location'

exports.builder = function (yargs) {
return yargs
.usage('$0 instrument <input> [output]')
.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('extension', {
alias: 'e',
default: [],
describe: 'a list of extensions that nyc should handle in addition to .js'
})
.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?'
})
.example('$0 instrument ./lib ./output', 'instrument all .js files in ./lib with coverage and output in ./output')
}

exports.handler = function (argv) {
// if instrument is set to false,
// enable a noop instrumenter.
if (!argv.instrument) argv.instrumenter = './lib/instrumenters/noop'
else argv.instrumenter = './lib/instrumenters/istanbul'

var nyc = new NYC({
instrumenter: argv.instrumenter,
sourceMap: argv.sourceMap,
extension: argv.extension,
require: argv.require
})

nyc.instrumentAllFiles(argv.input, argv.output, function (err) {
if (err) console.error(err.message)
process.exit(1)
})
}
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@
"istanbul-lib-instrument": "^1.1.0-alpha.1",
"istanbul-lib-report": "^1.0.0-alpha.3",
"istanbul-lib-source-maps": "^1.0.0-alpha.10",
"istanbul-reports": "^1.0.0-alpha.6",
"istanbul-reports": "^1.0.0-alpha.7",
"md5-hex": "^1.2.0",
"micromatch": "^2.3.7",
"mkdirp": "^0.5.0",
"pkg-up": "^1.0.0",
"resolve-from": "^2.0.0",
"rimraf": "^2.5.0",
"rimraf": "^2.5.3",
"signal-exit": "^3.0.0",
"spawn-wrap": "^1.2.2",
"test-exclude": "^1.1.0",
Expand Down Expand Up @@ -147,4 +147,4 @@
"test-exclude",
"yargs"
]
}
}
Loading