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: add include and exclude options to instrument command #1007

Merged

Conversation

AndrewFinlay
Copy link
Contributor

@AndrewFinlay AndrewFinlay commented Mar 1, 2019

This allows you to better select which files are instrumented when running the instrument command. It's a pretty minimal implementation to make it as easy as possible to integrate with other proposed changes. Test support is included with this change.

Fixes #596, fixes #890

This allows you to better select which files are instrumented when running the instrument command.  It's a pretty minimal implementation to make it as easy as possible to integrate with other proposed changes.  Test support is included with this change.
@coveralls
Copy link

Coverage Status

Coverage increased (+0.02%) to 96.657% when pulling d576e44 on AndrewFinlay:instrument-include-exclude-option into b64d921 on istanbuljs:master.

4 similar comments
@coveralls
Copy link

Coverage Status

Coverage increased (+0.02%) to 96.657% when pulling d576e44 on AndrewFinlay:instrument-include-exclude-option into b64d921 on istanbuljs:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.02%) to 96.657% when pulling d576e44 on AndrewFinlay:instrument-include-exclude-option into b64d921 on istanbuljs:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.02%) to 96.657% when pulling d576e44 on AndrewFinlay:instrument-include-exclude-option into b64d921 on istanbuljs:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.02%) to 96.657% when pulling d576e44 on AndrewFinlay:instrument-include-exclude-option into b64d921 on istanbuljs:master.

@coveralls
Copy link

coveralls commented Mar 1, 2019

Coverage Status

Coverage increased (+0.08%) to 96.429% when pulling 8903365 on AndrewFinlay:instrument-include-exclude-option into 31817de on istanbuljs:master.

@coreyfarrell

This comment has been minimized.

Copy link
Member

@coreyfarrell coreyfarrell left a comment

Choose a reason for hiding this comment

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

I like this, lets get the conflicts resolved, let it run through CI again then assuming it still passes we can merge.

# Conflicts:
#	lib/commands/instrument.js
@coreyfarrell
Copy link
Member

Hold off a minute, I may have noticed something.

Copy link
Member

@coreyfarrell coreyfarrell left a comment

Choose a reason for hiding this comment

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

So for taking back my first review.

index.js Outdated
if (!_this.exclude.shouldInstrument(filename)) {
return
}

var code = fs.readFileSync(inFile, 'utf-8')

for (ext in _this.transforms) {
Copy link
Member

Choose a reason for hiding this comment

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

This results in no output for files that are not instrumented. But if I have:

src/index.js
src/no-coverage.js

With src/no-coverage.js excluded, I think I still need both dest/index.js and dest/no-coverage.js to be created, just dest/no-coverage.js should be unmodified. Same if I run nyc instrument src/no-coverage.js - that should print the original source.

So I'm thinking:

if (_this.exclude.shouldInstrument) {
  for (ext in ...) { ... }
}

I suspect this will change some of the tests, you will have to look for cov_ or not in the output files for example instead of checking if the file exists/doesn't.

Copy link
Member

Choose a reason for hiding this comment

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

If I understand correctly, you're thinking your point is that dest/ should have a fully functional codebase, just some files will be instrumented and some won't. I agree, it would be a bit shocking to be missing files, it makes it impossible to import the library.

I believe we check for the cov__ global in a few other tests, I'd look for an existing test using this approach.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, though this idea might require bypassing walkAllFiles entirely, just using:

glob.sync('**/*', { cwd: input, nodir: true }).forEach(visitor)

Specifically walkAllFiles uses the extension and exclude filters which we don't really want if we're attempting to copy everything from src to dest. This could be problematic though when using npx nyc instrument . dest as that would include node_modules. Maybe nyc instrument needs a --full-copy option? If enabled we directly use glob.sync to capture all files, if not then we use testExclude.globSync. I'm leaning towards leaving that option disabled by default.

Possibly future enhancement: when nyc instrument copies files which have chmod +x enabled should we do the same for the copied file?

Copy link
Member

Choose a reason for hiding this comment

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

Let's create an issue for keeping the perms the same; I think it would potentially even be worth splitting this into its own library -- it sounds like we want something like cpr that:

  • allows us to apply our own include/exclude rules.
  • maintains file permissions.

Definitely beyond the scope of this pull however; although I think maintaining the existing behavior of copying over the whole directory is smart.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've pushed a new commit that addresses some of these concerns, namely copying all existing files in input to output before instrumentation and replacing output files in place. To do this I've brought in fs-extra as it seems like a popular and maintained module, but I'm not particularly attached to it so if it needs to change let me know of your preferred replacement.

# Conflicts:
#	lib/commands/instrument.js
@AndrewFinlay AndrewFinlay changed the title feat: add include and exclude options to instrument command WIP: feat: add include and exclude options to instrument command Mar 12, 2019
Andrew Finlay added 3 commits March 20, 2019 13:36
# Conflicts:
#	index.js
#	lib/commands/instrument.js
#	test/nyc-integration.js
…nstrumented versions where needed

So I've implemented this using `fs-extra`, not sure if that's the module you wish to go with here.
This is now relying on `testExclude.globSync` to get the correct files for instrumentation, so no more `shouldInstrument`
There's quite a few test changes in here, as `fs-extra.copySync` won't let you copy from `./` to `./outputMkdirHere`, but they're probably for the best anyway.
This also means that any attempt to store the instrumentation result in a subdir of the input dir will fail.
index.js Outdated
@@ -200,6 +200,10 @@ NYC.prototype.instrumentAllFiles = function (input, output, cb) {
try {
const stats = fs.lstatSync(input)
if (stats.isDirectory()) {
if (output) {
fs.copySync(input, output)
Copy link
Member

Choose a reason for hiding this comment

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

With the current nyc if I just did the following:

mkdir -p tmp/bin
touch tmp/bin/nyc.js
chmod a+x tmp/bin/nyc.js
./bin/nyc.js instrument bin/nyc.js tmp

This resulted in tmp/bin/nyc.js containing the instrumented script with chmod a+x. In theory fs.copySync should copy the chmod flags from input to output. I'd like to see a test to verify this (probably have to skip that test for Windows).

Oddly enough I also tried:

./bin/nyc.js instrument bin tmp

This resulted in creation of tmp/nyc.js and tmp/wrap.js, though I expected it to create tmp/bin/*.js. Probably deal with this inconsistency in a follow-up.

Copy link
Member

Choose a reason for hiding this comment

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

A potential issue with this approach:

nyc instrument --delete . self-coverage

This would result in copying the entire project into ./self-coverage, which would be correct. The issue is that this.walkAllFiles happens after these files are created. I think we need to stop using this.walkAllFiles, instead perform:

const files = this.exclude.globSync(input);
if (output) {
  fs.copySync(input, output);
}
files.forEach(relFile => {
  visitor(relFile);
})

This way testExclude.globSync is run before we create any files. I know this shouldn't matter as someone following the above example should add self-coverage to the exclude list, but I think it will turn into an issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, fs-extra.copySync currently prevents this from happening as it won't let you copy . into ./dest. It seems a more custom solution without fs-extra.copySync may be a better approach.

Copy link
Member

Choose a reason for hiding this comment

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

One other though, should the copy skip the .git/ folder?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Most likely, I can't think of a use case where you'd need to copy the .git/ folder from . to ./dest while instrumenting files.

index.js Outdated Show resolved Hide resolved
lib/commands/instrument.js Show resolved Hide resolved
test/nyc-integration.js Outdated Show resolved Hide resolved
Andrew Finlay added 5 commits March 22, 2019 14:13
…o `output` dir

It ignores files in the `.git` folder and copies empty directories
Unfortunately I had to keep `fs-extra`, although this should be easy to drop when the project moves to node 8+ when `fs.copyFileSync` is made available.
We need to use `fs.chmodSync` to set the mode as any `write` mode flags get filtered when trying to set them through `fs.writeFileSync`.

What's missing?
 * No check to see where the working directory is relative to the project root directory
 * Tests confirming includes/excludes can be set in a config file or stanza and are observed by the instrument command
 * Tests confirming file permissions match between files in the input and output directories
 * Tests confirming we can't instrument outside of the project root directory
…tside of cwd

Tests include
  * using a `.nycrc` file to specify excludes
  * checking that file mode is preserved after instrumentation,
  * copying all uninstrumented files across to the output directory
  * Ensure that we can't instrument in place, overwriting the existing source
  * Ensure that we can't instrument source from outside the project root directory
A file `node_modules` file involved in the tests was being git ignored
@JaKXz
Copy link
Member

JaKXz commented Mar 28, 2019

@AndrewFinlay can we get these changes rebased and merged? :) cc @coreyfarrell @bcoe

Copy link
Member

@coreyfarrell coreyfarrell left a comment

Choose a reason for hiding this comment

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

I'd say we can drop the WIP label and merge this. I'd like to see follow-up done to simplify the copy logic and ensure we maintain chmod flags in instrumented scripts.

index.js Outdated Show resolved Hide resolved
@coreyfarrell coreyfarrell requested a review from JaKXz April 1, 2019 20:26
@coreyfarrell
Copy link
Member

@JaKXz or @bcoe can I get a second review on this? Thanks.

In the last attempt at this I was jumping through hoops trying to maintain empty folders and structure etc.  Turns out none of that is necessary.
So this change runs the instrumentation process over the included files, then copies across anything remaining excluding freshly created output directory.
@AndrewFinlay AndrewFinlay changed the title WIP: feat: add include and exclude options to instrument command feat: add include and exclude options to instrument command Apr 2, 2019
index.js Outdated
files.map(file => path.relative(input, file))
.forEach(file => { copySync(path.join(input, file), path.join(output, file), { overwrite: false }) })
if (output) {
const globOptions = { dot: true, ignore: ['**/.git', `**/${path.basename(output)}`] }
Copy link
Member

Choose a reason for hiding this comment

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

I suspect this is a problem for nyc instrument . output if ./lib/output/data.json exists (that output folder should be copied). Instead of ignoring **/${path.basename(output)} couldn't we just ignore output?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This only produces a list of top level files using glob.sync(`${path.resolve(input)}/*`, ...), so the inclusion of **/${path.basename(output)} won't exclude any further sub-dirs. The recursive copy of each top level sub-dir is then handled by fs-extra.copySync. I agree it looks a little silly and should really be just output, but I couldn't get it to work with glob.sync. I should point out that this also means we're only ignoring .git directories at the top level in this implementation.

Anyway I'll see if I can come up with a nicer solution here, in the meantime I'll drop in the change below and rebase

Copy link
Member

Choose a reason for hiding this comment

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

What if someone does nyc instrument . subdir/output? In that case wouldn't we need to ignore subdir, not output? I ask due to the use of path.basename.

test/nyc-integration.js Outdated Show resolved Hide resolved
@JaKXz
Copy link
Member

JaKXz commented Apr 2, 2019

@coreyfarrell I'm going to defer my review to @bcoe, I'm not quite familiar enough atm and don't have the cycles this week

@coreyfarrell coreyfarrell mentioned this pull request Apr 3, 2019
Andrew Finlay added 2 commits April 4, 2019 08:36
…ude`

Previously this was adding `nyc instrument` full copy of `src` to `dst` as well as `include`/`exclude`
The full copy work was proving troublesome so it's been moved to it's own branch/PR
This commit removes the full copy, removes now unused dependencies, and updates tests accordingly
@AndrewFinlay
Copy link
Contributor Author

This PR has been split up so that it only adds support for nyc instrument --include --exclude. nyc instrument copy all functionality will be in a separate PR.

@coreyfarrell coreyfarrell merged commit 8da097e into istanbuljs:master Apr 4, 2019
@coreyfarrell
Copy link
Member

@AndrewFinlay Thanks for working with me to figure out scope of this change and how to deal with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants