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: Added --ignore-files option and build now ignores artifacts folder #753

Merged
merged 42 commits into from
Feb 1, 2017

Conversation

eight04
Copy link
Contributor

@eight04 eight04 commented Jan 15, 2017

Fixes #131, Fixes #186

@coveralls
Copy link

coveralls commented Jan 15, 2017

Coverage Status

Coverage remained the same at 100.0% when pulling c497465 on eight04:dev-file-filter into 7d20a3c on mozilla:master.

@kumar303 kumar303 changed the title Add --ignore-files option & ignore artifacts folder feat: Added --ignore-files option and build now ignores artifacts folder Jan 15, 2017
Copy link
Contributor

@kumar303 kumar303 left a comment

Choose a reason for hiding this comment

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

Hi, thanks for digging into this issue!

It's on the right track but here are some change requests:

  • --ignore-files should be a global option so that other commands can benefit from it
  • The ignoreFiles and artifactsDir logic needs to move out of build and into FileFilter directly since both lint and run's file watcher use the FileFilter too. Both of those commands will need the same ignoreFiles and artifactsDir logic.

@kumar303 kumar303 self-assigned this Jan 15, 2017
@eight04
Copy link
Contributor Author

eight04 commented Jan 15, 2017

Seems that there are only 2 tests using filesToIgnore option. Can we replace it completely with ignoreFiles?
https://github.com/mozilla/web-ext/search?utf8=%E2%9C%93&q=filesToIgnore

@coveralls
Copy link

coveralls commented Jan 16, 2017

Coverage Status

Coverage decreased (-0.9%) to 99.14% when pulling cae516e on eight04:dev-file-filter into 7d20a3c on mozilla:master.

@kumar303
Copy link
Contributor

Seems that there are only 2 tests using filesToIgnore option. Can we replace it completely with ignoreFiles?

I think so. It is only used by build to set some defaults but it currently relies on minimatch patterns for nested directories.

Copy link
Contributor

@kumar303 kumar303 left a comment

Choose a reason for hiding this comment

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

This is on the right track, thanks! Let me know if you get stuck.

src/cmd/run.js Outdated
@@ -257,14 +262,21 @@ export default async function run(
}

log.info('The extension will reload if any source file changes');
const createWatcher = (...args) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

The coverage report says this function never gets executed by the test suite. I think you'd have two options:

  • Try to think of a test that calls run() that covers it
  • Replace createWatcher with a dependency injection parameter and write a separate unit test for it. This is the typical pattern we use elsewhere because it usually means the tests are easier to write.

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 have to solve #751 to do the "run" test.

Copy link
Contributor

Choose a reason for hiding this comment

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

ah, yes of course! OK, let's try to land #751 first so you can merge it into this branch when it hits master.

src/cmd/run.js Outdated
@@ -257,14 +262,21 @@ export default async function run(
}

log.info('The extension will reload if any source file changes');
const createWatcher = (...args) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd rather not see args get mutated because who knows what babel does to it under the hood. Could it be done more directly, like:

const createWatcher = (watcherParams, ...args) => {
  // ...
  return defaultWatcherCreator({
    ...watcherParams,
    shouldWatchFile: (file) => fileFilter.wantFile(file),
  }, ...args);
}

src/cmd/run.js Outdated
});
args[0].shouldWatchFile = (file) => fileFilter.wantFile(file);
return defaultWatcherCreator(...args);
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this callback necessary? I see that sourceDir and artifactsDir are already passed to reloadStrategy and eventually the watcher where it instantiates its own FileFilter anyway (in lieu of a callback). Maybe you can just pass ignoreFiles all the way through? Sorry, this code has been rewritten a couple times to try and alleviate the headache (but it still hurts).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right. I should make reloadStrategy accept ignoreFiles and build shouldWatchFile inside reloadStrategy.

Also maybe we should remove FileFilter from the watcher so it doesn't depend on FileFilter anymore. Make shouldWatchFile default to () => true.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, there is probably a bit too much complexity here.

src/program.js Outdated
@@ -246,6 +246,12 @@ Example: $0 --help run.
describe: 'Show verbose output',
type: 'boolean',
},
'ignore-files': {
alias: 'i',
describe: 'Files to ignore.',
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be more explicit and should show an example of ignoring multiple files. It should say that the file must be an absolute path. I think an example of multiple paths would look like this, no? --ignore-files /path/to/first.js /path/to/second.js

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It can be relative path. FileFilter resolves it with sourceDir.

@@ -48,6 +53,50 @@ describe('build', () => {
);
});

it('ignore artifacts dir if included by source dir when zipping', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

rejoice! Since you moved all of the ignoring logic, you no longer need such a heavyweight test. Here's what you can do:

  • you can delete all of the fixture directories (with the manifest, etc)
  • you can simply assert that build is configuring the file watcher correctly with its value of ignoreFiles. Here are some examples of how we do things like that.

@@ -0,0 +1,87 @@
/* @flow */
Copy link
Contributor

Choose a reason for hiding this comment

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

Good call on moving this to its own file. You also need to move the tests out of test.build.js. The new ignoreFiles needs test coverage too.

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 found some bugs when writing tests for FileFilter.

    it('ignore artifactsDir and its content', () => {
      const filter = new FileFilter({
        artifactsDir: 'artifacts',
      });
      assert.equal(filter.wantFile('artifacts'), false);
      assert.equal(filter.wantFile('artifacts/some.js'), false); // assertion error
    });

It might be fine for build.js, since the zipDir will skip the content if the parent dir is skipped.

But it cause problem for watcher.js. Make the content inside artifactsDir becomes wanted files. This bug applies to .git and node_modules folders as well.

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'm not sure how should we fix it. Just explicitly ignore all content inside the folder?

    filesToIgnore = [
      '**/*.xpi',
      '**/*.zip',
      '**/.*', // any hidden file
+     '**/.*/**/*', // any content in the hidden folder
      '**/node_modules',
+     '**/node_modules/**/*',
    ],

Copy link
Contributor

Choose a reason for hiding this comment

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

These issues are both resolved in the patch now.

@coveralls
Copy link

coveralls commented Jan 17, 2017

Coverage Status

Coverage decreased (-0.1%) to 99.858% when pulling 6e4d8ae on eight04:dev-file-filter into 7d20a3c on mozilla:master.

@coveralls
Copy link

coveralls commented Jan 17, 2017

Coverage Status

Coverage decreased (-0.1%) to 99.858% when pulling 452e382 on eight04:dev-file-filter into 7d20a3c on mozilla:master.

@eight04
Copy link
Contributor Author

eight04 commented Jan 25, 2017

How do I fix this error?

BTW, what does the vertical bar mean in type definition? I can't find them in flow's document.

exports type ... = {|
	...
|};

@kumar303
Copy link
Contributor

How do I fix this error?

Huh, looks like a Flow bug. Flow is smart enough to see that you checked the type of the variable in an if statement but it seems to forget the if statement after one line of code. I moved the resolve() call right under the if statement and it worked. However, you can see that the second line still needs protection against undefined values (which is a Flow bug). Here's my patch:

diff --git a/src/util/file-filter.js b/src/util/file-filter.js
index 23a941d..13d046a 100644
--- a/src/util/file-filter.js
+++ b/src/util/file-filter.js
@@ -68,11 +68,13 @@ export class FileFilter {
    *  Resolve relative path to absolute path if sourceDir is setted.
    */
   resolve(file: string): string {
-    if (typeof this.sourceDir === 'string') {
+    if (this.sourceDir !== undefined) {
+      const resolvedPath = path.resolve(this.sourceDir, file);
       log.debug(
-        `Adding sourceDir ${this.sourceDir} to the beginning of file ${file}`
+        `Resolved path ${file} with sourceDir ${this.sourceDir || ''} ` +
+        `to ${resolvedPath}`
       );
-      return path.resolve(this.sourceDir, file);
+      return resolvedPath;
     }
     return normalizeResolve(file);
   }

I also made the debug statement more verbose to help detect the situation you mentioned above when the path is absolute (which is when it won't be pre-pended with sourceDir).

@kumar303
Copy link
Contributor

BTW, what does the vertical bar mean in type definition?

Sigh, I can't find it in the docs either. It's a very important feature. If you have a function like this:

type Params = {|
  size: 'small' | 'large',
|}

function render({size}: Params) {
}

And you call it like this:

render({size: 'small', color: 'blue'});

then Flow will raise an error because color is not a valid parameter. If you do not use the pipes when defining Params, Flow will not raise an error. I think this was a pretty major flaw in Flow's original implementation but they couldn't fix it without new syntax because of backwards compatibility. All object types should always use pipes (except there are a few open bugs).

*/
export class FileFilter {
filesToIgnore: Array<string>;
sourceDir: string | typeof undefined;
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess this works. I suggested the wrong thing originally but I was thinking of:

sourceDir: ?string;

They are pretty much the same though. The one with the question marks allows it to be null which is the only difference.

@coveralls
Copy link

coveralls commented Jan 25, 2017

Coverage Status

Coverage remained the same at 100.0% when pulling 1795c0e on eight04:dev-file-filter into b558ec8 on mozilla:master.

Copy link
Contributor

@kumar303 kumar303 left a comment

Choose a reason for hiding this comment

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

Thanks again for all the quick turnarounds! This looks good to me but because it touches so many commands, I'd like @rpl to also review it.

Copy link
Member

@rpl rpl left a comment

Choose a reason for hiding this comment

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

Hi @eight04
My apologies for the waiting time, this PR looks almost great, thanks for working on it!

I've added some comments related to some minor changes (most of them are small nits, the most important ones are related to the yargs configuration of the new cli option).

Let me know if any of the comment is not clear enough or if you disagree with any of the requested changes.

@@ -49,6 +49,27 @@ describe('build', () => {
);
});

it('configures a build', () => {
Copy link
Member

Choose a reason for hiding this comment

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

this test case description could probably be a bit more specific (e.g. it('configures a build command with the expected fileFilter', ...))

@@ -299,6 +300,23 @@ describe('run', () => {
assert.typeOf(callArgs.onChange, 'function');
});

it('configure fileFilter, shouldWatchFile', () => {
Copy link
Member

Choose a reason for hiding this comment

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

how about it('configures a run command with the expected fileFilter', ...))?

assert.equal(fileFilter.wantFile.called, true);
assert.equal(fileFilter.wantFile.firstCall.args[0], 'manifest.json');
});
it('configures and passes a fileFilter to the linter', () => {
Copy link
Member

Choose a reason for hiding this comment

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

how about it('configures a lint command with the expected fileFilter', ...)?

paths.forEach((file) => {
assert.equal(
path.resolve(src, file),
path.resolve(src) + path.sep + normalizeResolve(file)
Copy link
Member

Choose a reason for hiding this comment

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

can we use path.join(path.resolve(src), normalizeResolve(file)) here?

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 guess it's OK? This test is to make sure:

normalizeResolve(relativePath) == stripRoot(path.resolve(root, relativePath), root)

@@ -246,6 +246,14 @@ Example: $0 --help run.
describe: 'Show verbose output',
type: 'boolean',
},
'ignore-files': {
Copy link
Member

Choose a reason for hiding this comment

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

this options should require an argument (by adding the requiresArg: true to the yargs properties for the option).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It seems that setting requiresArg would force yargs to validate ignoreFiles is not a empty list. Since the ignoreFiles defaults to an empty list, this make yargs always argue Missing argument value: ignore-files.

Copy link
Member

Choose a reason for hiding this comment

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

This comment is supposed to be part of the last review comments but it has not been submitted by github, and so I added it here as a separate comment.

@eight04 yargs can be very annoying sometimes :-)

Anyway, it looks like that we can use a combination of yargs option config properties to make it work as expected:

    'ignore-files': {
      alias: 'i',
      describe: '...',
      demand: false,
      requiresArg: true,
      type: 'array',
    },

Basically it seems that we have to:

  • omit the empty array currently set as its default value
  • add a demand: false config to allow the --ignore-files option to be undefined (which is going to mean "that the option has not been specified")
  • add the requiresArg: true which force "--ignore-files" to have a value when specified

I briefly tried the above config locally and it seems to work as expected,
let me know if it doesn't for you.

src/program.js Outdated
alias: 'i',
describe: 'A list of glob patterns to define which files should be ' +
'ignored. (Example: --ignore-files=path/to/first.js ' +
'path/to/second.js **/*.log)',
Copy link
Member

Choose a reason for hiding this comment

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

In the help message we should suggest to quote the patterns (e.g. the **/*.log), or what is going to happen in most of the shells is that "the glob pattern will be expanded up front and a long list of the resulting files will be passed to the web-ext command" (instead of the single glob entry as expected).
e.g. --ignore-files=path/to/file.js "**/*.log"

sourceDir: ?string;

constructor({
filesToIgnore = [
Copy link
Member

Choose a reason for hiding this comment

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

The FileFilter now takes two parameters with two very similar names but they have different meaning, it would be nice to make it more clear by make the names a bit more descriptive (e.g. filesToIgnore renamed to defaultFilesToIgnore, and ignoreFiles renamed to customFilesToIgnore?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we change ignoreFiles to customFilesToIgnore, every calls to createFileFilter would also need to be changed to createFileFilter({sourceDir, artifactsDir, customFilesToIgnore: ignoreFiles}).

How about to change filesToIgnore to defaultIgnorePatterns and keep ignoreFiles so createFileFilter could be called nicely as createFileFilter({sourceDir, artifactsDir, ignoreFiles})?

Copy link
Member

Choose a reason for hiding this comment

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

@eight04 yeah, I agree that not being able to use the ES6 syntax shortcut is a pity.

What I'd like to achieve is to make it clear that the FileFilter constructor property currently named filesToIgnore is not overridden by the new ignoreFiles property, but extended.

How about rename filesToIgnore to baseIgnoredPatterns (or commonIgnoredPatterns) and leave ignoreFiles unmodified?

@coveralls
Copy link

coveralls commented Feb 1, 2017

Coverage Status

Coverage remained the same at 100.0% when pulling 09bee46 on eight04:dev-file-filter into b558ec8 on mozilla:master.

Copy link
Member

@rpl rpl left a comment

Choose a reason for hiding this comment

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

Hi @eight04
Thanks for the last round of updates, This is almost ready!
Follows some additional comments on the last two pending issues (the FileFilter contructor property names and the requiresArg option on the yargs option configuration).

sourceDir: ?string;

constructor({
filesToIgnore = [
Copy link
Member

Choose a reason for hiding this comment

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

@eight04 yeah, I agree that not being able to use the ES6 syntax shortcut is a pity.

What I'd like to achieve is to make it clear that the FileFilter constructor property currently named filesToIgnore is not overridden by the new ignoreFiles property, but extended.

How about rename filesToIgnore to baseIgnoredPatterns (or commonIgnoredPatterns) and leave ignoreFiles unmodified?

@coveralls
Copy link

Coverage Status

Coverage remained the same at 100.0% when pulling 6e45154 on eight04:dev-file-filter into b558ec8 on mozilla:master.

1 similar comment
@coveralls
Copy link

Coverage Status

Coverage remained the same at 100.0% when pulling 6e45154 on eight04:dev-file-filter into b558ec8 on mozilla:master.

Copy link
Member

@rpl rpl left a comment

Choose a reason for hiding this comment

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

This PR looks great, thanks @eight04!

@kumar303
Copy link
Contributor

kumar303 commented Feb 1, 2017

Thanks again for all your work on this and especially for all the quick turnarounds.

@kumar303 kumar303 merged commit be62a54 into mozilla:master Feb 1, 2017
@caitmuenster
Copy link

Nice work! 👍

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

Successfully merging this pull request may close these issues.

7 participants