Skip to content

Commit 1b334e6

Browse files
rally25rsarcanis
authored andcommitted
fix(workspaces): Pass args following "--" when running workspace scripts (#7786)
* fix(workspaces): Passes arguments follwing "--" when running a workspace script Passes arguments follwing `--` when running a workspace script (`yarn workspace pkg run command -- arg`). Previously these parameters were being trimmed off and ignored. fixes #7776 * fix spelling in changelog * fix(workspaces): fix(workspaces): Passes arguments follwing "--" when running a workspace script Passes arguments follwing `--` when running a workspace script (`yarn workspace pkg run command -- arg`). Previously these parameters were being trimmed off and ignored. fixes #7776 * don't ignore a parameter when running 'node' command
1 parent 2c8e97e commit 1b334e6

File tree

10 files changed

+125
-29
lines changed

10 files changed

+125
-29
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ Please add one entry in this file for each change in Yarn's behavior. Use the sa
44

55
## Master
66

7+
- Passes arguments following `--` when running a workspace script (`yarn workspace pkg run command -- arg`)
8+
9+
[#7776](https://github.com/yarnpkg/yarn/pull/7776) - [**Jeff Valore**](https://twitter.com/rally25rs)
10+
711
- Prints workspace names with `yarn workspaces` (silence with `-s`)
812

913
[#7722](https://github.com/yarnpkg/yarn/pull/7722) - [**Orta**](https://twitter.com/orta)

__tests__/commands/workspace.js

+2-7
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,8 @@ async function runWorkspace(
3838
}
3939
}
4040

41-
// The unit tests don't use commander.js for argument parsing.
42-
// `originalArgs` is normally passed by index.js so we just simulate it in the tests.
43-
4441
test('workspace run command', (): Promise<void> => {
45-
const originalArgs = ['workspace-1', 'run', 'script'];
46-
return runWorkspace({originalArgs}, ['workspace-1', 'run', 'script'], 'run-basic', config => {
42+
return runWorkspace({}, ['workspace-1', 'run', 'script'], 'run-basic', config => {
4743
expect(spawn).toHaveBeenCalledWith(NODE_BIN_PATH, [YARN_BIN_PATH, 'run', 'script'], {
4844
stdio: 'inherit',
4945
cwd: path.join(fixturesLoc, 'run-basic', 'packages', 'workspace-child-1'),
@@ -52,8 +48,7 @@ test('workspace run command', (): Promise<void> => {
5248
});
5349

5450
test('workspace run command forwards raw arguments', (): Promise<void> => {
55-
const originalArgs = ['workspace-1', 'run', 'script', 'arg1', '--flag1'];
56-
return runWorkspace({originalArgs}, ['workspace-1', 'run', 'script'], 'run-basic', config => {
51+
return runWorkspace({}, ['workspace-1', 'run', 'script', 'arg1', '--flag1'], 'run-basic', config => {
5752
expect(spawn).toHaveBeenCalledWith(NODE_BIN_PATH, [YARN_BIN_PATH, 'run', 'script', 'arg1', '--flag1'], {
5853
stdio: 'inherit',
5954
cwd: path.join(fixturesLoc, 'run-basic', 'packages', 'workspace-child-1'),

__tests__/commands/workspaces.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,12 @@ test('workspaces info should list the workspaces', (): Promise<void> => {
4949
});
5050

5151
test('workspaces run should spawn command for each workspace', (): Promise<void> => {
52-
const originalArgs = ['run', 'script', 'arg1', '--flag1'];
53-
return runWorkspaces({originalArgs}, ['run', 'script', 'arg1', '--flag1'], 'run-basic', config => {
54-
expect(spawn).toHaveBeenCalledWith(NODE_BIN_PATH, [YARN_BIN_PATH, 'script', 'arg1', '--flag1'], {
52+
return runWorkspaces({}, ['run', 'script', 'arg1', '--flag1'], 'run-basic', config => {
53+
expect(spawn).toHaveBeenCalledWith(NODE_BIN_PATH, [YARN_BIN_PATH, 'run', 'script', 'arg1', '--flag1'], {
5554
stdio: 'inherit',
5655
cwd: path.join(fixturesLoc, 'run-basic', 'packages', 'workspace-child-1'),
5756
});
58-
expect(spawn).toHaveBeenCalledWith(NODE_BIN_PATH, [YARN_BIN_PATH, 'script', 'arg1', '--flag1'], {
57+
expect(spawn).toHaveBeenCalledWith(NODE_BIN_PATH, [YARN_BIN_PATH, 'run', 'script', 'arg1', '--flag1'], {
5958
stdio: 'inherit',
6059
cwd: path.join(fixturesLoc, 'run-basic', 'packages', 'workspace-child-2'),
6160
});

__tests__/fixtures/index/run-workspace/packages/workspace-child-1/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
"prescript": "echo workspace-1 prescript",
66
"script": "echo workspace-1 script",
77
"postscript": "echo workspace-1 postscript",
8-
"check": "echo $1"
8+
"check": "echo ARGS:"
99
}
1010
}

__tests__/fixtures/index/run-workspace/packages/workspace-child-2/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"scripts": {
55
"prescript": "echo workspace-2 prescript",
66
"script": "echo workspace-2 script",
7-
"postscript": "echo workspace-2 postscript"
7+
"postscript": "echo workspace-2 postscript",
8+
"check": "echo WORKSPACE-CHILD-2 ARGS:"
89
},
910
"dependencies": {
1011
"workspace-1": "1.0.0"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
HTTP/1.1 200 OK
2+
Server: nginx
3+
Date: Sun, 29 Dec 2019 14:24:54 GMT
4+
Content-Type: text/plain; charset=utf-8
5+
Content-Length: 1181
6+
Cache-Control: max-age=3600, public
7+
Content-Disposition: inline
8+
Etag: W/"78309fbf8af4479c47eca65b0c5e3f51"
9+
Referrer-Policy: strict-origin-when-cross-origin
10+
Set-Cookie: experimentation_subject_id=IjJjZjk1MWRjLWUzMDgtNDc3ZC05MTlkLTA0MGU5MWFjY2VlOCI%3D--64f51f0ae3455ebf84d41c0a0a6723703e719689; domain=.gitlab.com; path=/; expires=Thu, 29 Dec 2039 14:24:54 -0000; secure; HttpOnly
11+
X-Content-Type-Options: nosniff
12+
X-Download-Options: noopen
13+
X-Frame-Options: DENY
14+
X-Permitted-Cross-Domain-Policies: none
15+
X-Request-Id: xcIbPa5i6G2
16+
X-Runtime: 0.056763
17+
X-Ua-Compatible: IE=edge
18+
X-Xss-Protection: 1; mode=block
19+
Strict-Transport-Security: max-age=31536000
20+
Referrer-Policy: strict-origin-when-cross-origin
21+
GitLab-LB: fe-07-lb-gprd
22+
GitLab-SV: web-28-sv-gprd
23+
24+
{
25+
"name": "kanban",
26+
"version": "0.0.1",
27+
"repository": "gitlab.com/leanlabsio/kanban",
28+
"scripts": {
29+
"install": "npm install",
30+
"build": "grunt build",
31+
"watch": "grunt watch"
32+
},
33+
"devDependencies": {
34+
"grunt": "~0.4.1",
35+
"grunt-cli": "~0.1.13",
36+
"grunt-contrib-copy": "^0.5.0",
37+
"grunt-contrib-concat": "~0.5.0",
38+
"grunt-contrib-watch": "~0.5.3",
39+
"grunt-contrib-uglify": "~0.7.0",
40+
"grunt-sass": "1.0.0",
41+
"grunt-contrib-connect": "~0.8.0",
42+
"grunt-connect-proxy": "~0.1.11"
43+
},
44+
"dependencies": {
45+
"angular": "=1.5.6",
46+
"angular-lodash": "https://github.com/EMSSConsulting/angular-lodash.git#68a726c",
47+
"foundation-sites": "5.5.2",
48+
"angular-foundation": "https://github.com/pineconellc/angular-foundation.git#8f3f260",
49+
"angular-loading-bar": "=0.5.2",
50+
"angular-storage": "=0.0.6",
51+
"angular-ui-router": "=0.3.0",
52+
"angularjs-datepicker": "=0.2.15",
53+
"font-awesome": "=4.6.3",
54+
"markdown-it": "=5.0.2",
55+
"markdown-it-emoji": "=1.1.0",
56+
"ng-sortable": "=1.3.6",
57+
"sass-flex-mixin": "=1.0.3",
58+
"lodash": "=4.13.1",
59+
"twemoji": "=2.1.0",
60+
"angular-file-upload": "=2.3.4"
61+
}
62+
}

__tests__/index.js

+34-1
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,39 @@ test.concurrent('should run help for camelised command', async () => {
355355
// but actual flags on the command line are passed.
356356
test.concurrent('should not pass yarnrc flags to workspace command', async () => {
357357
const stdout = await execCommand('workspace', ['workspace-1', 'run', 'check', '--x'], 'run-workspace', true);
358-
const params = stdout.find(x => x && x.indexOf('--x') >= 0);
358+
const params = stdout.find(x => x && x.indexOf('ARGS:') === 0);
359359
expect(params).not.toMatch(/emoji/);
360360
});
361+
362+
// regression test for #7776
363+
test.concurrent('should pass args to workspace command without need for "--"', async () => {
364+
const stdout = await execCommand('workspace', ['workspace-1', 'run', 'check', '--x', 'y'], 'run-workspace', true);
365+
const params = stdout.find(x => x && x.indexOf('ARGS:') === 0);
366+
expect(params).toEqual('ARGS: --x y');
367+
});
368+
369+
// regression test for #7776
370+
test.concurrent('should pass args after "--" to workspace command', async () => {
371+
const stdout = await execCommand(
372+
'workspace',
373+
['workspace-1', 'run', 'check', '--', 'x', '-y'],
374+
'run-workspace',
375+
true,
376+
);
377+
const params = stdout.find(x => x && x.indexOf('ARGS:') === 0);
378+
expect(params).toEqual('ARGS: x -y');
379+
});
380+
381+
// regression test for #7776
382+
test.concurrent('should pass args to workspaces command without need for "--"', async () => {
383+
const stdout = await execCommand('workspaces', ['run', 'check', '--x', 'y'], 'run-workspace', true);
384+
const params = stdout.find(x => x && x.indexOf('ARGS:') === 0);
385+
expect(params).toEqual('ARGS: --x y');
386+
});
387+
388+
// regression test for #7776
389+
test.concurrent('should pass args after "--" to workspaces command', async () => {
390+
const stdout = await execCommand('workspaces', ['run', 'check', '--', 'x', '-y'], 'run-workspace', true);
391+
const params = stdout.find(x => x && x.indexOf('ARGS:') === 0);
392+
expect(params).toEqual('ARGS: x -y');
393+
});

src/cli/commands/workspace.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,19 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg
2121
throw new MessageError(reporter.lang('workspaceRootNotFound', config.cwd));
2222
}
2323

24-
if (flags.originalArgs < 1) {
24+
if (args.length < 1) {
2525
throw new MessageError(reporter.lang('workspaceMissingWorkspace'));
2626
}
2727

28-
if (flags.originalArgs < 2) {
28+
if (args.length < 2) {
2929
throw new MessageError(reporter.lang('workspaceMissingCommand'));
3030
}
3131

3232
const manifest = await config.findManifest(workspaceRootFolder, false);
3333
invariant(manifest && manifest.workspaces, 'We must find a manifest with a "workspaces" property');
3434

3535
const workspaces = await config.resolveWorkspaces(workspaceRootFolder, manifest);
36-
const [workspaceName, ...rest] = flags.originalArgs || [];
36+
const [workspaceName, ...rest] = args || [];
3737

3838
if (!Object.prototype.hasOwnProperty.call(workspaces, workspaceName)) {
3939
throw new MessageError(reporter.lang('workspaceUnknownWorkspace', workspaceName));

src/cli/commands/workspaces.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,10 @@ export async function runScript(config: Config, reporter: Reporter, flags: Objec
7676
const workspaces = await config.resolveWorkspaces(workspaceRootFolder, manifest);
7777

7878
try {
79-
const [_, ...rest] = flags.originalArgs || [];
80-
8179
for (const workspaceName of Object.keys(workspaces)) {
8280
const {loc} = workspaces[workspaceName];
8381
reporter.log(`${os.EOL}> ${workspaceName}`);
84-
await child.spawn(NODE_BIN_PATH, [YARN_BIN_PATH, ...rest], {
82+
await child.spawn(NODE_BIN_PATH, [YARN_BIN_PATH, 'run', ...args], {
8583
stdio: 'inherit',
8684
cwd: loc,
8785
});

src/cli/index.js

+13-9
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,20 @@ export async function main({
198198
let warnAboutRunDashDash = false;
199199
// we are using "yarn <script> -abc", "yarn run <script> -abc", or "yarn node -abc", we want -abc
200200
// to be script options, not yarn options
201-
const PROXY_COMMANDS = new Set([`run`, `create`, `node`]);
202-
if (PROXY_COMMANDS.has(commandName)) {
201+
202+
// PROXY_COMMANDS is a map of command name to the number of preservedArgs
203+
const PROXY_COMMANDS = {
204+
run: 1, // yarn run {command}
205+
create: 1, // yarn create {project}
206+
node: 0, // yarn node
207+
workspaces: 1, // yarn workspaces {command}
208+
workspace: 2, // yarn workspace {package} {command}
209+
};
210+
if (PROXY_COMMANDS.hasOwnProperty(commandName)) {
203211
if (endArgs.length === 0) {
204-
let preservedArgs = 0;
205-
// the "run" and "create" command take one argument that we want to parse as usual (the
206-
// script/package name), hence the splice(1)
207-
if (command === commands.run || command === commands.create) {
208-
preservedArgs += 1;
209-
}
212+
// $FlowFixMe doesn't like that PROXY_COMMANDS doesn't have keys for all commands.
213+
let preservedArgs = PROXY_COMMANDS[commandName];
214+
210215
// If the --into option immediately follows the command (or the script name in the "run/create"
211216
// case), we parse them as regular options so that we can cd into them
212217
if (args[preservedArgs] === `--into`) {
@@ -218,7 +223,6 @@ export async function main({
218223
}
219224
}
220225

221-
commander.originalArgs = args;
222226
args = [...preCommandArgs, ...args];
223227

224228
command.setFlags(commander);

0 commit comments

Comments
 (0)