Skip to content

Commit 2eb13c6

Browse files
AndrewFinlaycoreyfarrell
authored andcommitted
feat: instrument --complete-copy implementation (#1056)
With a few caveats: * This will dereference symlinks as it copies them, in some cases this could be a problem i.e. `node_modules/.bin` * This will not copy across empty directories
1 parent c88a852 commit 2eb13c6

File tree

6 files changed

+81
-19
lines changed

6 files changed

+81
-19
lines changed

index.js

+13-9
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
/* global __coverage__ */
44

55
const cachingTransform = require('caching-transform')
6-
const util = require('util')
6+
const cpFile = require('cp-file')
77
const findCacheDir = require('find-cache-dir')
88
const fs = require('fs')
9+
const glob = require('glob')
910
const Hash = require('./lib/hash')
1011
const libCoverage = require('istanbul-lib-coverage')
1112
const libHook = require('istanbul-lib-hook')
@@ -19,6 +20,7 @@ const resolveFrom = require('resolve-from')
1920
const rimraf = require('rimraf')
2021
const SourceMaps = require('./lib/source-maps')
2122
const testExclude = require('test-exclude')
23+
const util = require('util')
2224
const uuid = require('uuid/v4')
2325

2426
const debugLog = util.debuglog('nyc')
@@ -155,7 +157,7 @@ NYC.prototype.addAllFiles = function () {
155157
this._loadAdditionalModules()
156158

157159
this.fakeRequire = true
158-
this.walkAllFiles(this.cwd, relFile => {
160+
this.exclude.globSync(this.cwd).forEach(relFile => {
159161
const filename = path.resolve(this.cwd, relFile)
160162
this.addFile(filename)
161163
const coverage = coverageFinder()
@@ -193,7 +195,15 @@ NYC.prototype.instrumentAllFiles = function (input, output, cb) {
193195
const stats = fs.lstatSync(input)
194196
if (stats.isDirectory()) {
195197
inputDir = input
196-
this.walkAllFiles(input, visitor)
198+
199+
const filesToInstrument = this.exclude.globSync(input)
200+
201+
if (this.config.completeCopy && output) {
202+
const globOptions = { dot: true, nodir: true, ignore: ['**/.git', '**/.git/**', path.join(output, '**')] }
203+
glob.sync(path.resolve(input, '**'), globOptions)
204+
.forEach(src => cpFile.sync(src, path.join(output, path.relative(input, src))))
205+
}
206+
filesToInstrument.forEach(visitor)
197207
} else {
198208
visitor(input)
199209
}
@@ -203,12 +213,6 @@ NYC.prototype.instrumentAllFiles = function (input, output, cb) {
203213
cb()
204214
}
205215

206-
NYC.prototype.walkAllFiles = function (dir, visitor) {
207-
this.exclude.globSync(dir).forEach(relFile => {
208-
visitor(relFile)
209-
})
210-
}
211-
212216
NYC.prototype._transform = function (code, filename) {
213217
const extname = path.extname(filename).toLowerCase()
214218
const transform = this.transforms[extname] || (() => null)

lib/commands/instrument.js

+5
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ exports.builder = function (yargs) {
7575
default: false,
7676
type: 'boolean'
7777
})
78+
.option('complete-copy', {
79+
describe: 'should nyc copy all files from input to output as well as instrumented files?',
80+
default: false,
81+
type: 'boolean'
82+
})
7883
.example('$0 instrument ./lib ./output', 'instrument all .js files in ./lib with coverage and output in ./output')
7984
}
8085

package-lock.json

+17
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,11 @@
6969
"archy": "^1.0.0",
7070
"caching-transform": "^3.0.2",
7171
"convert-source-map": "^1.6.0",
72+
"cp-file": "^6.2.0",
7273
"find-cache-dir": "^2.1.0",
7374
"find-up": "^3.0.0",
7475
"foreground-child": "^1.5.6",
76+
"glob": "^7.1.3",
7577
"istanbul-lib-coverage": "^2.0.4",
7678
"istanbul-lib-hook": "^2.0.5",
7779
"istanbul-lib-instrument": "^3.1.2",
@@ -93,7 +95,6 @@
9395
"any-path": "^1.3.0",
9496
"chai": "^4.2.0",
9597
"coveralls": "^3.0.3",
96-
"glob": "^7.1.3",
9798
"is-windows": "^1.0.2",
9899
"lodash": "^4.17.11",
99100
"newline-regex": "^0.2.1",

test/fixtures/cli/.instrument-nycrc

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"exclude": [
33
"**/exclude-me/**"
4-
]
4+
],
5+
"complete-copy": true
56
}

test/nyc-integration.js

+42-8
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,31 @@ describe('the nyc cli', function () {
689689
files.should.include('ignore.js')
690690
files.should.not.include('package.json')
691691
files.should.not.include('node_modules')
692+
const includeTarget = path.resolve(fixturesCLI, 'output', 'ignore.js')
693+
fs.readFileSync(includeTarget, 'utf8')
694+
.should.match(/var cov_/)
695+
done()
696+
})
697+
})
698+
699+
it('copies all files from <input> to <output> as well as those that have been instrumented', function (done) {
700+
const args = [bin, 'instrument', '--complete-copy', './nyc-config-js', './output']
701+
702+
const proc = spawn(process.execPath, args, {
703+
cwd: fixturesCLI,
704+
env: env
705+
})
706+
707+
proc.on('close', function (code) {
708+
code.should.equal(0)
709+
const files = fs.readdirSync(path.resolve(fixturesCLI, './output'))
710+
files.should.include('index.js')
711+
files.should.include('ignore.js')
712+
files.should.include('package.json')
713+
files.should.include('node_modules')
714+
const includeTarget = path.resolve(fixturesCLI, 'output', 'ignore.js')
715+
fs.readFileSync(includeTarget, 'utf8')
716+
.should.match(/var cov_/)
692717
done()
693718
})
694719
})
@@ -738,19 +763,22 @@ describe('the nyc cli', function () {
738763
code.should.equal(0)
739764
const files = fs.readdirSync(path.resolve(fixturesCLI, './output'))
740765
files.length.should.not.equal(0)
741-
files.should.not.include('exclude-me')
742-
files.should.not.include('node_modules')
766+
files.should.include('exclude-me')
767+
files.should.include('node_modules')
743768
files.should.include('index.js')
744769
files.should.include('bad.js')
745770
const includeTarget = path.resolve(fixturesCLI, 'output', 'index.js')
746771
fs.readFileSync(includeTarget, 'utf8')
747772
.should.match(/var cov_/)
773+
const excludeTarget = path.resolve(fixturesCLI, 'output', 'exclude-me', 'index.js')
774+
fs.readFileSync(excludeTarget, 'utf8')
775+
.should.not.match(/var cov_/)
748776
done()
749777
})
750778
})
751779

752780
it('allows a file to be excluded', function (done) {
753-
const args = [bin, 'instrument', '--exclude', 'exclude-me/index.js', './subdir/input-dir', './output']
781+
const args = [bin, 'instrument', '--complete-copy', '--exclude', 'exclude-me/index.js', './subdir/input-dir', './output']
754782

755783
const proc = spawn(process.execPath, args, {
756784
cwd: fixturesCLI,
@@ -761,7 +789,10 @@ describe('the nyc cli', function () {
761789
code.should.equal(0)
762790
const files = fs.readdirSync(path.resolve(fixturesCLI, './output'))
763791
files.length.should.not.equal(0)
764-
files.should.not.include('exclude-me')
792+
files.should.include('exclude-me')
793+
const excludeTarget = path.resolve(fixturesCLI, 'output', 'exclude-me', 'index.js')
794+
fs.readFileSync(excludeTarget, 'utf8')
795+
.should.not.match(/var cov_/)
765796
done()
766797
})
767798
})
@@ -787,7 +818,7 @@ describe('the nyc cli', function () {
787818
})
788819

789820
it('allows a file to be excluded from an included directory', function (done) {
790-
const args = [bin, 'instrument', '--exclude', '**/exclude-me.js', '--include', '**/include-me/**', './subdir/input-dir', './output']
821+
const args = [bin, 'instrument', '--complete-copy', '--exclude', '**/exclude-me.js', '--include', '**/include-me/**', './subdir/input-dir', './output']
791822

792823
const proc = spawn(process.execPath, args, {
793824
cwd: fixturesCLI,
@@ -802,10 +833,13 @@ describe('the nyc cli', function () {
802833
const includeMeFiles = fs.readdirSync(path.resolve(fixturesCLI, 'output', 'include-me'))
803834
includeMeFiles.length.should.not.equal(0)
804835
includeMeFiles.should.include('include-me.js')
805-
includeMeFiles.should.not.include('exclude-me.js')
806-
const instrumented = path.resolve(fixturesCLI, 'output', 'include-me', 'include-me.js')
807-
fs.readFileSync(instrumented, 'utf8')
836+
includeMeFiles.should.include('exclude-me.js')
837+
const includeTarget = path.resolve(fixturesCLI, 'output', 'include-me', 'include-me.js')
838+
fs.readFileSync(includeTarget, 'utf8')
808839
.should.match(/var cov_/)
840+
const excludeTarget = path.resolve(fixturesCLI, 'output', 'exclude-me', 'index.js')
841+
fs.readFileSync(excludeTarget, 'utf8')
842+
.should.not.match(/var cov_/)
809843
done()
810844
})
811845
})

0 commit comments

Comments
 (0)