Skip to content

Fix: Prevents interpreting run options as yarn options #4152

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

Merged
merged 7 commits into from
Aug 22, 2017

Conversation

arcanis
Copy link
Member

@arcanis arcanis commented Aug 11, 2017

Summary

Running the following command doesn't have the expected effect, because the --no-coverage option is interpreter by Yarn instead of being forwarded to the script. This patch fix this.

$> yarn test-only --no-coverage     # currently bad
$> yarn test-only -- --no-coverage  # currently good

This is a breaking change: it will change some edge-case behaviors.

@BYK
Copy link
Member

BYK commented Aug 11, 2017

I remember talking about this but couldn't find the issue. Do you know if we have an open or closed issue around this? The problem with this approach is it makes yarn take no arguments at all such as --prefix or --modules-folder etc. so although I like the easier and cleaner invocation, I have serious doubts about whether we should do this or not.

@BYK
Copy link
Member

BYK commented Aug 11, 2017

Also, tests or didn't happen.

@arcanis
Copy link
Member Author

arcanis commented Aug 11, 2017

Do you know if we have an open or closed issue around this?

No, this is an issue reported by the Oculus people, and something I personally struggle with on a daily basis. :p

The problem with this approach is it makes yarn take no arguments at all such as --prefix or --modules-folder.

Not really an issue since the only potential option concerned is --prefix, which is not implemented and has its own set of issues + the solution is obvious: any option before the script name would have to be yarn options. We currently don't need this behavior, tho.

@kaylie-alexa
Copy link
Member

Although it's convenient to not have to use the --, this would change the behavior from npm and how we write scripts inside package.json, so I'd prefer it if we could keep them the same.

@arcanis
Copy link
Member Author

arcanis commented Aug 14, 2017

Hm I don't know, this behavior really is a pain, especially since it is completely silent, which means that unless people actually look at the command executed, they won't see that the options have been ignored. It's potentially dangerous (just imagine something like yarn rm / --dry-run being executed).

A less invasive possibility would be to only add this behavior when running yarn <pkg>. Running yarn run <pkg> would still require the --. I don't really like this because it causes an unnecessary split between the two commands behaviors, but maybe it's still better than the alternative.

@cpojer
Copy link
Contributor

cpojer commented Aug 15, 2017

I think I'm on board with this change, but agree that we need tests for it. We had an internal discussion about this at FB previously and would like to make sure other people are involved in a vote for this feature. I seem to remember that there were some issues with this approach that made this less workable, but I do think that yarn --options run --foo makes a lot of sense to overall and will definitely be a better UX for beginners. Can we make this work at all in a backwards compatible way at all?

@kaylieEB I think diverging here is ok, given that in scripts you'd write "yarn run …" instead of "npm run" or a generic command, like just "run", so it's clear that you are using either tool.

@arcanis
Copy link
Member Author

arcanis commented Aug 15, 2017

I don't think we can - the only way I could see this working would be to add some kind of "if the command line doesn't begins with --, add one" (so that we wouldn't break people already using --), but that seems extremely confusing and unexpected.

@BYK
Copy link
Member

BYK commented Aug 15, 2017

I think the point we ended up is pretty great so 👍 . Thanks everyone, especially @arcanis. We need to be very loud and clear about this change though.

@cpojer
Copy link
Contributor

cpojer commented Aug 15, 2017

I think that's confusing and will break projects with people on different versions of Yarn. Can we add a deprecation warning to 1.0 if the command starts with <bin> run -- and continue on with the old behavior? I understand it is confusing, but I think breaking this in the 1.0 release will cause more pain than it provides value.

@arcanis arcanis mentioned this pull request Aug 15, 2017
@kaylie-alexa
Copy link
Member

Can we add a deprecation warning to 1.0 if the command starts with run -- and continue on with the old behavior?

I think if this could be supported, it would be great since devs don't have to alter their current use habits, similar to how we support both yarn [command] and yarn run [command]. If not, definitely a big warning would be helpful.

@arcanis arcanis force-pushed the yarn-run branch 2 times, most recently from a1549ce to e620c48 Compare August 17, 2017 17:06
@BYK BYK self-assigned this Aug 18, 2017
@arcanis arcanis force-pushed the yarn-run branch 2 times, most recently from e620c48 to 8dff818 Compare August 18, 2017 12:49
@arcanis
Copy link
Member Author

arcanis commented Aug 18, 2017

@BYK @kaylieEB good for review - added a deprecation warning when manually using --

@@ -188,6 +188,8 @@ const messages = {

execMissingCommand: 'Missing command name.',

dashDashDeprecation:
"Using -- to pass arguments to your scripts isn't required anymore. Doing this may cause issues in future versions.",
Copy link
Contributor

Choose a reason for hiding this comment

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

How about: "Yarn does not require `--` to pass arguments to scripts. In a future version of Yarn, passing `--` will fail with an error." ?

Copy link
Member Author

@arcanis arcanis Aug 18, 2017

Choose a reason for hiding this comment

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

It won't fail, it will just be forwarded to the binary as-is.

$> yarn test -- --no-coverage

will become

$> jest -- --no-coverage

instead of (as before this PR, and until the deprecation wears off)

$> jest --no-coverage

This is important because in some case you really want to prevent something from being interpreted as an option.

Copy link
Contributor

Choose a reason for hiding this comment

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

Right, in that case then, maybe this: "From Yarn 1.0, scripts do not require `--` to be passed. In a future version of Yarn, passing `--` will be forwarded to the script directly." ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Much better than the current text, thanks 👍

src/cli/index.js Outdated
@@ -403,7 +418,7 @@ export default function start() {
const doubleDashIndex = process.argv.findIndex(element => element === '--');
const startArgs = process.argv.slice(0, 2);
const args = process.argv.slice(2, doubleDashIndex === -1 ? process.argv.length : doubleDashIndex);
const endArgs = doubleDashIndex === -1 ? [] : process.argv.slice(doubleDashIndex + 1, process.argv.length);
const endArgs = doubleDashIndex === -1 ? [] : process.argv.slice(doubleDashIndex, process.argv.length);
Copy link
Member

Choose a reason for hiding this comment

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

can you do process.argv.slice(doubleDashIndex) since it'll just default to length of the array?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure thing 👍

src/cli/index.js Outdated
// we using "yarn <script> -abc" or "yarn run <script> -abc", we want -abc to be script options, not yarn options
if (command === commands.run) {
if (endArgs.length === 0) {
endArgs = ['--', ...args.splice(1, args.length)];
Copy link
Member

Choose a reason for hiding this comment

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

same for here? args.splice(1)?

Copy link
Member

@kaylie-alexa kaylie-alexa left a comment

Choose a reason for hiding this comment

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

looks great!

Copy link
Member

@BYK BYK left a comment

Choose a reason for hiding this comment

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

This looks pretty nice but it is also a hack on the existing system that relies on -- style still. Do we have a long-term plan for making this more maintainable?

@@ -73,6 +73,62 @@ test('--mutex network', async () => {
]);
});

// Windows doesn't have the "echo" utility
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 node -p -e "process.argv.slice(1)" for cross-platform compatibility? ;)

const stdoutPromise = misc.consumeStream(stdout);
const stderrPromise = misc.consumeStream(stderr);

const [stdoutOutput, stderrOutput] = await Promise.all([stdoutPromise, stderrPromise]);
Copy link
Member

Choose a reason for hiding this comment

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

Is there an advantage to this indirection instead of just doing

const stdoutOutput = await misc.consumeStream(stdout);
const stderrOutput = await misc.consumeStream(stderr);

Copy link
Member Author

Choose a reason for hiding this comment

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

Problem with this writing is that it doesn't work, because the stdin and stdout streams are started and stopped as soon as the event loop gets a chance, ie. before the second line gets executed. Before of this, the second consumeStream call never receives the end event, and never returns. The synchronous version makes sure we attach both of our listeners before allowing the event loop to continue.

Copy link
Member

Choose a reason for hiding this comment

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

Got it. I think this deserves a comment. Even better, find a way that doesn't require this workaround (not necessarily in this patch). Maybe use something else rather than the stream consumer? This may also help: https://nodejs.org/api/stream.html#stream_readable_resume


const [stdoutOutput, stderrOutput] = await Promise.all([stdoutPromise, stderrPromise]);

expect(stdoutOutput.toString().trim()).toEqual('--opt');
Copy link
Member

Choose a reason for hiding this comment

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

Are we testing the "$ " echo string here? If so we may wanna add a comment since this may change.

Copy link
Member Author

Choose a reason for hiding this comment

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

No, because we run with YARN_SILENT: 1, so Yarn doesn't print the yarn run header.

Copy link
Member

@BYK BYK Aug 21, 2017

Choose a reason for hiding this comment

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

Oh, nice. Then what are we testing here? I'm confused :D

const stdoutPromise = misc.consumeStream(stdout);
const stderrPromise = misc.consumeStream(stderr);

const [stdoutOutput, stderrOutput] = await Promise.all([stdoutPromise, stderrPromise]);
Copy link
Member

Choose a reason for hiding this comment

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

Lots of repeated code here. You may clean it up with beforeEach and afterEach hooks with a describe('run with arguments', block.

src/cli/index.js Outdated
@@ -110,6 +110,16 @@ export function main({
command = commands.run;
}

let warnAboutRunDashDash = false;
// we using "yarn <script> -abc" or "yarn run <script> -abc", we want -abc to be script options, not yarn options
Copy link
Member

Choose a reason for hiding this comment

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

we are using

Copy link
Member Author

Choose a reason for hiding this comment

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

me hulk

@@ -171,6 +181,11 @@ export function main({
//
const run = (): Promise<void> => {
invariant(command, 'missing command');

if (warnAboutRunDashDash) {
reporter.warn(reporter.lang('dashDashDeprecation'));
Copy link
Member

Choose a reason for hiding this comment

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

Arguably, this should be an info message, not a warning since with the --strict option it will break and I don't think should break just because you are still using the harmless -- thing. What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

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

Makes sense, but the PR that will implement the --strict feature will need to revisit all the loglevels anyway.

Copy link
Member

@BYK BYK Aug 21, 2017

Choose a reason for hiding this comment

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

Eh, fair point. I'd still get certain things "right" from the start. That said we don't show info messages in normal mode, are we? Then I'm okay with warnings.

@arcanis
Copy link
Member Author

arcanis commented Aug 21, 2017

@BYK Long term plan is to switch to a different command line parser more suited to our use cases. I have it on my backlog, but time has been a scarce resource lately :p

@BYK
Copy link
Member

BYK commented Aug 21, 2017

I have it on my backlog, but time has been a scarce resource lately :p

Shall we make it explicit by creating an issue?

@arcanis
Copy link
Member Author

arcanis commented Aug 22, 2017

@BYK #4225

@arcanis arcanis merged commit 52a35c9 into yarnpkg:master Aug 22, 2017
BYK added a commit that referenced this pull request Sep 10, 2017
**Summary**

Fixes #4383. This patch makes argument parsing a bit tidier, and
starts supporting `yarn --silent custom-script` style commands as
initiall intended by #4152.

**Test plan**

Existing unit tests.
BYK added a commit that referenced this pull request Sep 12, 2017
**Summary**

Fixes #4383. This patch makes argument parsing a bit tidier, and
starts supporting `yarn --silent custom-script` style commands as
initiall intended by #4152.

**Test plan**

Existing unit tests. Should ideally add a few more.
joaolucasl pushed a commit to joaolucasl/yarn that referenced this pull request Oct 27, 2017
* Prevents interpreting run options as yarn options

* Implements a deprecation warning

* Adds tests

* Feedback

* Wording

* Enables a test on Linux

* Disables the tests again on Windows
joaolucasl pushed a commit to joaolucasl/yarn that referenced this pull request Oct 27, 2017
**Summary**

Fixes yarnpkg#4383. This patch makes argument parsing a bit tidier, and
starts supporting `yarn --silent custom-script` style commands as
initiall intended by yarnpkg#4152.

**Test plan**

Existing unit tests. Should ideally add a few more.
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.

4 participants