-
Notifications
You must be signed in to change notification settings - Fork 338
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: basic implementation of command line config option #1080
Conversation
c138bcc
to
5552269
Compare
I took a look at what is the behavior currently implemented by the src/config.js module landed by #744
Another detail to take into account if we are going to load a config file implicitly is related to the default values displayed in the "web-ext --help" output, which can be different from the actual default values set once we load the config file implicitly, and it is likely to be confusing for the user @kumar303 Let me know how that sounds to you, e.g. if I'm not missing anything related to the plans for the "config file loading" behaviors. |
src/program.js
Outdated
options: this.options, | ||
configFileName: argv.config, | ||
}); | ||
} catch (error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By looking at the implementation and unit tests related to applyConfigToArgv
, I think that we should not try...catch
the exception that it throws, they seem to be meant to be raised to the user (e.g. UsageError
for errors that can/should be fixed by the user and WebExtError
for the unexpected errors).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rpl tbh I wrapped it this way because instead of throwing i would get UnhandledPromiseRejectionWarning
despite applyConfigToArgv
being a sync function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@saintsebastian that's because the execute
method is an async function, it should be enough to just move the code that uses loadJSConfigFile
and applyConfigToArgv
inside the existent try...catch
at line 150 of this patch (it was at line 135 before the changes applied by this patch), because it already implements the behavior that we want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rpl ah! now i see it. thanks! I will add tests and that should probably be it for this patch
Sounds good! I would suggesting keeping the features in this patch small. For example, a great start would be to simply allow an option like |
Yeah, I agree completely, it is better to keep this PR simpler and defer that behaviors as follow up issues. @saintsebastian do you mind to file this part (the "implicit config file loading") as a separate issue? (and mention #775 and this PR into its description so that they will be linked together by github). |
@saintsebastian yeah, it is definitely the issue that I wanted, it was linked to a pull request that has been closed in favor of the one that has been landed, I've also updated its description to mention this PR. |
295be34
to
1c4ffd8
Compare
03c9a6c
to
8c363e1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @saintsebastian!
This looks pretty near to its final goal, follows some additional tweaks (mostly related to the flow types and the test cases).
src/program.js
Outdated
@@ -27,6 +31,8 @@ type ExecuteOptions = { | |||
systemProcess?: typeof process, | |||
logStream?: typeof defaultLogStream, | |||
getVersion?: Function, | |||
applyConfigToArgv?: Function, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can use the more specific type: typeof defaultLoadJSConfigFile
(Function
would allow flow to consider as valid any function, besides its flow type signature).
same for loadJSConfigFile.
src/program.js
Outdated
@@ -145,6 +153,17 @@ export class Program { | |||
}); | |||
} | |||
|
|||
if (argv.config) { | |||
const configLocation = path.resolve(argv.config); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: if we call this configfileName
, then we can use the shorter syntax at line 163.
src/program.js
Outdated
argv, | ||
configObject, | ||
options: this.options, | ||
configFileName: configLocation, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move this line at line 161 to keep the keys in alphabetical order.
@@ -26,7 +26,7 @@ describe('program.Program', () => { | |||
const absolutePackageDir = path.join(__dirname, '..', '..'); | |||
return program.execute( | |||
absolutePackageDir, { | |||
getVersion: () => spy(), | |||
getVersion: () => 'not-a-real-version', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
argh... This is why it is better to use a more specific type signature instead of Function
as a flow type signature :-)
Do you mind to file a follow up issue related to a more specific type signature for getVersion
in "src/program.js" (or we can check how many flow errors it produces, if they are not too much we can fix it in this patch, on the contrary we can move it into a separate issue and pull request)
A reasonable flow type could be just () => string
(a function which takes no parameters and returns a string).
tests/unit/test.program.js
Outdated
.then(() => { | ||
const options = fakeCommands.lint.firstCall.args[0]; | ||
assert.strictEqual(options.config, fakePath); | ||
assert.ok(fakeLoadJSConfigFile.called); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should turn most of these assertion into sinon assertion (http://sinonjs.org/releases/v2.3.5/assertions/)
and matchers (http://sinonjs.org/releases/v2.3.5/matchers/).
e.g. assert.ok(fakeLoadJSConfigFile.called)
should be sinon.assert.calledOnce(fakeLoadJSConfigFile);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should probably also add some additional test cases to cover the following scenarios:
- the mocked loadJSConfigFile raises a UsageError or an unexpected exception
- the mocked applyConfigToArgv raises a UsageError or a WebExtError or an unexpected exception
And check that the behavior is the one that we expect (e.g. we can assert that these errors should make the call to reject with the expected error, and we could also check that they have been printed on the stderr, e.g. by injecting a logStream defined as const logStream = fake(new ConsoleStream());
into execProgram
)
@rpl this is now ready for a review. I think new tests are very repetitive, so maybe you have some ideas how to make them better. Also there is Travis failure on this and my other pr, it seems to be npm related. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @saintsebastian
follows some additional feedback related to the last round of changes.
I agree with you that there is a considerable amount of boilerplate code that is repeated on every one of the last group of tests, to avoid this, you can easily extract a new "test helper function" with the shared pieces and turn the parts that change into parameters of the "test helper function" (we use this approach in other test files too for the same reason).
Don't worry about the travis failure for now, it is related to the "nsp check" (which checks the npm package dependencies for known security vulnerabilities) and travis execute them before running the test suite.
src/program.js
Outdated
@@ -26,7 +31,10 @@ type ExecuteOptions = { | |||
checkForUpdates?: Function, | |||
systemProcess?: typeof process, | |||
logStream?: typeof defaultLogStream, | |||
logger?: Logger, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@saintsebastian I think that we should be able to make the test assertions related to the logged messages by turning on logStream.isCapturing
and inspecting the logStream.capturedMessages
array without injecting a fake logger instance:
Lines 44 to 45 in 177709b
isCapturing: boolean; | |
capturedMessages: Array<string>; |
tests/unit/test.program.js
Outdated
@@ -430,6 +433,203 @@ describe('program.main', () => { | |||
assert.strictEqual(options.shouldExitProgram, false); | |||
}); | |||
}); | |||
|
|||
it('applies config from config file when specified', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about "applies options from the specified config file"?
.then(() => { | ||
const options = fakeCommands.lint.firstCall.args[0]; | ||
assert.strictEqual(options.config, fakePath); | ||
sinon.assert.calledOnce(fakeLoadJSConfigFile); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to see the sinon.assert.calledOnce
and sinon.assert.calledWith
related to the same spy grouped together.
tests/unit/test.program.js
Outdated
sinon.assert.calledOnce(fakeLoadJSConfigFile); | ||
sinon.assert.calledOnce(fakeApplyConfigToArgv); | ||
sinon.assert.calledWith(fakeLoadJSConfigFile, | ||
sinon.match(resolvedFakePath)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this line should be indented so that sinon.match...
is aligned to the fakeLoadJSConfigFile
from the previous line.
tests/unit/test.program.js
Outdated
}); | ||
}); | ||
|
||
it('logs and throws when config file was not loaded', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about changing the description into something like 'throws an UsageError when the config file can't be loaded'?
tests/unit/test.program.js
Outdated
})); | ||
}); | ||
|
||
it('throws when config file loading fails', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to make it a bit more clear which is the difference between this test and the previous one,
we could rephrase this description to "throws when config file loading raises an unexpected error"
(given that we only expect it to raise a UsageError
in the known error cases)
tests/unit/test.program.js
Outdated
}); | ||
}); | ||
|
||
it('logs and throws when fakeApplyConfigToArgv throws UsageError', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about "throws a UsageError when the loaded config can't be applied"?
tests/unit/test.program.js
Outdated
})); | ||
}); | ||
|
||
it('logs and throws when fakeApplyConfigToArgv throws WebExtError', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@saintsebastian I'm wondering if we are really supposed to throw a WebExtError when a config file option is missing the type:
Lines 52 to 55 in 177709b
if (options[decamelizedOptName].type === undefined) { | |
throw new WebExtError( | |
`Option: ${option} was defined without a type.`); | |
} |
while we are raising a UsageError when the specified type is incorrect:
Lines 61 to 65 in 177709b
if (optionType !== expectedType) { | |
throw new UsageError(`The config file at ${configFileName} specified ` + | |
`the type of "${option}" incorrectly as "${optionType}"` + | |
` (expected type: "${expectedType}")`); | |
} |
it seems to me that we could/should throw a UsageError for both, @kumar303 what do you think about it?
(e.g. I'm wondering if this has been already evaluated when the config helper module has been created)
tests/unit/test.program.js
Outdated
})); | ||
}); | ||
|
||
it('logs and throws when fakeApplyConfigToArgv throws WebExtError', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be testing mostly the same scenario of the test above it, but it should probably be the test case which explicitly test what is going to happen if "fakeApplyConfigToArgv throws an unexpected error", am I right?
Hey @rpl sorry it took me so long to get to this PR
Thanks for cleaning up my wording and my tests! |
tests/unit/test.program.js
Outdated
import {ConsoleStream} from '../../src/util/logger'; | ||
|
||
import { | ||
consoleStream, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@saintsebastian nit, an inline comment here could be useful here (just to confirm to the next developer that reads this test file that we are importing both consoleStream and ConsoleStream on purpose, one to be able to inspect the messages logged by the logger instance created internally in the tested module and the other to create new fake console streams)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@saintsebastian here is a new round of review comments, they are mostly related to some fixes on the test cases (my apologies, I should have notice them in the previous review).
tests/unit/test.program.js
Outdated
}) | ||
.then(makeSureItFails()) | ||
.catch((error) => { | ||
if (!(error instanceof UsageError)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@saintsebastian This should be:
const {capturedMessages} = consoleStream;
consoleStream.stopCapturing();
if (!(error instanceof UsageError)) {
throw error;
}
assert.match(error.message, /some error/);
...
to be sure that the test still fails if an UsageError is received here.
tests/unit/test.program.js
Outdated
}) | ||
.then(makeSureItFails()) | ||
.catch((error) => { | ||
if (!(error instanceof UsageError)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as the previous comment (at line 539)
@saintsebastian no, actually you are right, we already have a test for that behavior at line 70 ( |
@rpl thanks for your reviews! hope this is ready for last reviews |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @saintsebastian , I'm excited about this patch! I have requested some changes but if you have already discussed them with @rpl just let me know what I missed.
Sorry for the delayed response. I've been busy preparing addons.mozilla.org for the Firefox Quantum launch but it's finally over!
src/config.js
Outdated
@@ -50,7 +50,7 @@ export function applyConfigToArgv({ | |||
`an unknown option: "${option}"`); | |||
} | |||
if (options[decamelizedOptName].type === undefined) { | |||
throw new WebExtError( | |||
throw new UsageError( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be a WebExtError
because when an option is defined without a type it's a programming error within web-ext itself (option types are defined at the bottom of program.js
). It's not due to incorrect usage and it's not something the developer would be able to fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kumar303 ah, you are definitely right, and this change is my fault, it is related to this comment #1080 (comment) (Sorry @saintsebastian).
Nevertheless, to prevent this check from be read wrong in the future, how about adding an inline comment near this throw
to briefly explain what this error is about?
Another interesting option (I can file a bug so that we can handle it in a follow up) would be to use a more specific type in the flow annotations here:
Line 96 in a55ee4c
setGlobalOptions(options: Object): Program { |
so that we can make flow to raise an error during its static analysis if any of the options defined in program.js is missing the type property.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rpl good idea about defining the shape of options
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kumar303 @saintsebastian we could definitely define and add the additional flow types for the options in this PR, the amount of changes should not be that big, but it could be reasonable to handle it in as a separate issue and pull requests, so that we are free to discuss the details of it without blocking this PR.
In the meantime, I added an issue related to it as #1144 (which also contains some additional info about the change, e.g. where these new flow types would be used and what their flow type definitions could probably look like).
src/program.js
Outdated
@@ -265,6 +286,13 @@ Example: $0 --help run. | |||
describe: 'Disable all features that require standard input', | |||
type: 'boolean', | |||
}, | |||
'config': { | |||
alias: 'c', | |||
describe: 'Location of the config file', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think 'Path to the config file' would be a bit more explicit
src/util/logger.js
Outdated
@@ -110,7 +110,7 @@ export type CreateBunyanLogParams = {| | |||
export type CreateBunyanLogFn = (params: CreateBunyanLogParams) => Logger; | |||
|
|||
export type CreateLoggerOptions = {| | |||
createBunyanLog: CreateBunyanLogFn, | |||
createBunyanLog?: CreateBunyanLogFn, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this type change necessary?
tests/unit/test.config.js
Outdated
}, WebExtError, | ||
'WebExtError: Option: apiUrl was defined without a type.'); | ||
}, UsageError, | ||
'UsageError: Option: apiUrl was defined without a type.'); | ||
}); | ||
|
||
it('throws an error when the type of one of them is in config' + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test looks like a duplicate of https://github.com/saintsebastian/web-ext/blob/737dd7495f090e5334b9ccd7ee8ad9a809ef4031/tests/unit/test.config.js#L640 You can delete it. It looks like the intention of the second test was to see if the code still works when one of the options has a type and the other does not but I don't think that's a useful test.
tests/unit/test.program.js
Outdated
|
||
consoleStream.stopCapturing(); | ||
consoleStream.flushCapturedLogs(); | ||
consoleStream.startCapturing(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is interesting. I see what you're doing here but I'd like to see it moved only to a single test instead of multiple tests. The test should be an assertion of how Program()
will log any UsageError
to the console. Actually, I was surprised that we did not have test coverage of this already. Good catch.
After you add a single test for this logic, your assertion of the UsageError
messages (like assert.match(error.message, /bad path/)
) will be enough. This is because we will know a thrown UsageError
will always be logged -- you don't have to test the console stream every time.
Also, you should add a comment around the stream capturing/re-capturing logic because it's not obvious that it is working around the test suite itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes a lot of sense. I was not sure what source of error should be, so I made command itself throw, let me know if it should be a dependency.
sinon.assert.calledWith(fakeLoadJSConfigFile, | ||
sinon.match(resolvedFakePath)); | ||
sinon.assert.calledOnce(fakeApplyConfigToArgv); | ||
sinon.assert.calledWith(fakeApplyConfigToArgv, sinon.match({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to check all parameters for the call to fakeApplyConfigToArgv
because Flow isn't going to catch all configuration problem, especially the options
parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume options
will always be the same (set in program.js
), but i added a check for argv
.
tests/unit/test.program.js
Outdated
}); | ||
}); | ||
|
||
it('throws a UsageError when the config file can\'t be loaded', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you need this test because the behavior of handling thrown errors is already well defined.
I can see that perhaps you wanted to be sure that the config checking code is executed from within the catch block but I don't think it's necessary to cover that logic. If one day we encounter a bug where someone accidentally moved it outside of the catch block then we could add a test for it. Until then, I think code review is a better way to make sure the config logic is executed with the catch block.
tests/unit/test.program.js
Outdated
})); | ||
}); | ||
|
||
it('throws when config file loading raises an unexpected error', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to my last comment, I also don't think you need this test.
tests/unit/test.program.js
Outdated
}); | ||
}); | ||
|
||
it('throws a UsageError when the loaded config can\'t be applied', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here :) I say delete the test.
tests/unit/test.program.js
Outdated
})); | ||
}); | ||
|
||
it('throws when fakeApplyConfigToArgv throws an unexpected error', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be deleted. I don't think it's helpful to check that an error is thrown.
e655ca4
to
a81e071
Compare
a81e071
to
67d04a8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code and tests are looking good but things aren't quite hooked up right. Here's one change I needed but there are a couple other issues too. If you try out a config file with a couple different options (a global one plus a command option) you should find the issues.
You can ignore the logging statements:
diff --git a/src/config.js b/src/config.js
index edcf65b..c92ae28 100644
--- a/src/config.js
+++ b/src/config.js
@@ -86,6 +86,7 @@ export function applyConfigToArgv({
continue;
}
+ log.debug(`Setting config option ${option} : ${configObject[option]}`);
newArgv[option] = configObject[option];
}
return newArgv;
diff --git a/src/program.js b/src/program.js
index d5143a0..5767f1f 100644
--- a/src/program.js
+++ b/src/program.js
@@ -155,18 +155,21 @@ export class Program {
});
}
+ let argvFromConfig = { ...argv };
if (argv.config) {
const configFileName = path.resolve(argv.config);
const configObject = loadJSConfigFile(configFileName);
- applyConfigToArgv({
+ log.debug('config from file', configObject);
+ argvFromConfig = applyConfigToArgv({
argv,
configFileName,
configObject,
options: this.options,
});
+ log.debug('new argv', argvFromConfig);
}
- await runCommand(argv, {shouldExitProgram});
+ await runCommand(argvFromConfig, {shouldExitProgram});
} catch (error) {
if (!(error instanceof UsageError) || argv.verbose) {
consoleStream.stopCapturing(); | ||
assert.match(error.message, /some error/); | ||
assert.ok( | ||
capturedMessages.some((message) => message.match(/some error/) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great test! Thanks
@kumar303 I fixed one broken test, but didn't notice any other errors so far, please let me know if you see any inconsistencies. |
if (argv.config) { | ||
const configFileName = path.resolve(argv.config); | ||
const configObject = loadJSConfigFile(configFileName); | ||
argvFromConfig = applyConfigToArgv({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for correcting this. It also needs test coverage. When I comment out your fix, the tests all pass -- at least one should fail.
How are you testing it out? I made a config file like this: module.exports = {
sourceDir: 'extension',
run: {
firefox: 'firefoxdeveloperedition',
},
}; When I execute it inside sound-control, I hit a couple problems with the
For sanity, you can run the same thing without a config and watch it succeed:
The first thing I am noticing is that option recursion is not implemented right. In this case, when diff --git a/src/config.js b/src/config.js
index edcf65b..4aecd70 100644
--- a/src/config.js
+++ b/src/config.js
@@ -36,7 +36,7 @@ export function applyConfigToArgv({
typeof configObject[option] === 'object') {
// Descend into the nested configuration for a sub-command.
newArgv = applyConfigToArgv({
- argv,
+ argv: newArgv,
configObject: configObject[option],
options: options[option],
configFileName}); The next thing I noticed is that option coercion needs to be implemented. Take a look at the diff --git a/src/config.js b/src/config.js
index edcf65b..701b27a 100644
--- a/src/config.js
+++ b/src/config.js
@@ -36,7 +36,7 @@ export function applyConfigToArgv({
typeof configObject[option] === 'object') {
// Descend into the nested configuration for a sub-command.
newArgv = applyConfigToArgv({
- argv,
+ argv: newArgv,
configObject: configObject[option],
options: options[option],
configFileName});
@@ -87,6 +87,11 @@ export function applyConfigToArgv({
}
newArgv[option] = configObject[option];
+ const coerce = options[decamelizedOptName].coerce;
+ if (coerce) {
+ log.debug(`Calling coerce() on ${option}`);
+ newArgv[option] = coerce(newArgv[option]);
+ }
}
return newArgv;
} This patch would need test coverage too. I hope that helps! It was tricky to track this down. I had to add a breakpoint in
|
Hi @saintsebastian , good news! @rpl and I are at the Mozilla All-Hands right now (we are missing you). We decided that we have time to work on the config features so I'm going to land the patch and help with the fixes. Thanks so much for all of your work on this. Since you added the much needed glue to hook things up, it revealed a couple hidden bugs :) |
Fixes #775
Basic version. Some question:
./web-ext-config.js
as default value for--config
option since it needs one?program.js
a good place to parse other config files from expected places like~/web-ext-config.js
and./web-ext-config.js
?