Skip to content

Commit 9665041

Browse files
committed
focused workspaces
1 parent 546a157 commit 9665041

File tree

95 files changed

+1021
-111
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+1021
-111
lines changed

__tests__/commands/check.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ test.concurrent('--verify-tree should report wrong version', async (): Promise<v
3333
expect(thrown).toEqual(true);
3434
});
3535

36+
test.concurrent('--verify-tree should work from a workspace cwd', async (): Promise<void> => {
37+
let thrown = false;
38+
try {
39+
await runCheck([], {verifyTree: true}, {source: 'verify-tree-workspace-cwd', cwd: '/packages/workspace-1'});
40+
} catch (e) {
41+
thrown = true;
42+
}
43+
expect(thrown).toEqual(false);
44+
});
45+
3646
test.concurrent('--verify-tree should report missing dependency', async (): Promise<void> => {
3747
let thrown = false;
3848
try {

__tests__/commands/install/bin-links.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,3 +199,20 @@ describe('with nohoist', () => {
199199
});
200200
});
201201
});
202+
203+
describe('with focus', () => {
204+
test('focus points bin links to the shallowly installed packages', (): Promise<void> => {
205+
return runInstall(
206+
{binLinks: true, focus: true},
207+
{source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-1'},
208+
async (config): Promise<void> => {
209+
expect(await fs.exists(path.join(config.cwd, 'node_modules', '.bin', 'example-yarn-workspace-2'))).toEqual(
210+
true,
211+
);
212+
expect(await linkAt(config, 'node_modules', '.bin', 'example-yarn-workspace-2')).toEqual(
213+
'../example-yarn-workspace-2/index.js',
214+
);
215+
},
216+
);
217+
});
218+
});
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
/* @flow */
2+
3+
import * as reporters from '../../../src/reporters/index.js';
4+
import * as fs from '../../../src/util/fs.js';
5+
import {runInstall} from '../_helpers.js';
6+
import {Install} from '../../../src/cli/commands/install.js';
7+
import Lockfile from '../../../src/lockfile';
8+
9+
jasmine.DEFAULT_TIMEOUT_INTERVAL = 150000;
10+
11+
const path = require('path');
12+
13+
test.concurrent('focus does not work from a non-workspaces project', async (): Promise<void> => {
14+
let error = '';
15+
const reporter = new reporters.ConsoleReporter({});
16+
try {
17+
await runInstall({focus: true}, 'install-production');
18+
} catch (e) {
19+
error = e.message;
20+
}
21+
expect(error).toContain(reporter.lang('workspacesFocusRootCheck'));
22+
});
23+
24+
test.concurrent('focus does not work from the root of a workspaces project', async (): Promise<void> => {
25+
let error = '';
26+
const reporter = new reporters.ConsoleReporter({});
27+
try {
28+
await runInstall({focus: true}, 'published-monorepo');
29+
} catch (e) {
30+
error = e.message;
31+
}
32+
expect(error).toContain(reporter.lang('workspacesFocusRootCheck'));
33+
});
34+
35+
test.concurrent('focus does a normal workspace installation', (): Promise<void> => {
36+
return runInstall(
37+
{focus: true},
38+
{source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-1'},
39+
async (config): Promise<void> => {
40+
const packageFile = await fs.readFile(
41+
path.join(config.cwd, '..', '..', 'node_modules', 'example-yarn-workspace-2', 'package.json'),
42+
);
43+
expect(JSON.parse(packageFile).version).toEqual('1.1.1');
44+
const readme = await fs.readFile(
45+
path.join(config.cwd, '..', '..', 'node_modules', 'example-yarn-workspace-2', 'README.md'),
46+
);
47+
expect(readme.split('\n')[0]).toEqual('WORKSPACES ROCK2!');
48+
},
49+
);
50+
});
51+
52+
test.concurrent('focus shallowly installs sibling workspaces under target', (): Promise<void> => {
53+
return runInstall(
54+
{focus: true},
55+
{source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-1'},
56+
async (config): Promise<void> => {
57+
const packageFile = await fs.readFile(
58+
path.join(config.cwd, 'node_modules', 'example-yarn-workspace-2', 'package.json'),
59+
);
60+
expect(JSON.parse(packageFile).version).toEqual('1.1.1');
61+
const readme = await fs.readFile(path.join(config.cwd, 'node_modules', 'example-yarn-workspace-2', 'README.md'));
62+
expect(readme.split('\n')[0]).toEqual('WORKSPACES ROCK2!');
63+
},
64+
);
65+
});
66+
67+
test.concurrent('focus should not bail out early after an un-focused install', (): Promise<void> => {
68+
return runInstall({}, 'published-monorepo', async (config, reporter) => {
69+
const oldCwd = config.cwd;
70+
71+
await fs.writeFile(path.join(oldCwd, 'node_modules', 'yarn.test'), 'YARN TEST');
72+
73+
config.cwd += '/packages/example-yarn-workspace-1';
74+
75+
const reinstall = new Install({focus: true}, config, reporter, await Lockfile.fromDirectory(oldCwd));
76+
await reinstall.init();
77+
78+
expect(await fs.exists(path.join(oldCwd, 'node_modules', 'yarn.test'))).toBeFalsy();
79+
});
80+
});
81+
82+
test.concurrent('repeated focused installs should bail out early', (): Promise<void> => {
83+
return runInstall(
84+
{focus: true},
85+
{source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-1'},
86+
async (config, reporter) => {
87+
await fs.writeFile(path.join(config.cwd, 'node_modules', 'yarn.test'), 'YARN TEST');
88+
89+
const lockfileDir = path.join(config.cwd, '..', '..');
90+
91+
const reinstall = new Install({focus: true}, config, reporter, await Lockfile.fromDirectory(lockfileDir));
92+
await reinstall.init();
93+
94+
expect(await fs.exists(path.join(config.cwd, 'node_modules', 'yarn.test'))).toBeTruthy();
95+
96+
await fs.unlink(path.join(config.cwd, 'node_modules', 'yarn.test'));
97+
},
98+
);
99+
});
100+
101+
test.concurrent('switching directories for focused installs should fail integrity checks and reinstall', (): Promise<
102+
void,
103+
> => {
104+
return runInstall(
105+
{focus: true},
106+
{source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-1'},
107+
async (config, reporter) => {
108+
const rootDir = path.join(config.cwd, '..', '..');
109+
110+
await fs.writeFile(path.join(rootDir, 'node_modules', 'yarn.test'), 'YARN TEST');
111+
112+
config.cwd = path.join(rootDir, 'packages', 'example-yarn-workspace-2');
113+
114+
const reinstall = new Install({focus: true}, config, reporter, await Lockfile.fromDirectory(rootDir));
115+
await reinstall.init();
116+
117+
expect(await fs.exists(path.join(rootDir, 'node_modules', 'yarn.test'))).toBeFalsy();
118+
},
119+
);
120+
});
121+
122+
test.concurrent(
123+
'focus shallowly installs anything that a sibling needed to shallowly install underneath that sibling',
124+
(): Promise<void> => {
125+
return runInstall(
126+
{focus: true},
127+
{source: 'focus-conflicts', cwd: '/packages/example-yarn-workspace-1'},
128+
async (config, reporter) => {
129+
const packageFile = await fs.readFile(
130+
path.join(config.cwd, 'node_modules', 'example-yarn-workspace-2', 'node_modules', 'left-pad', 'package.json'),
131+
);
132+
expect(JSON.parse(packageFile).version).toEqual('1.1.2');
133+
},
134+
);
135+
},
136+
);
137+
138+
test.concurrent("focus does not shallowly install a sibling's dev dependencies", (): Promise<void> => {
139+
return runInstall(
140+
{focus: true},
141+
{source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-4'},
142+
async (config, reporter) => {
143+
expect(
144+
await fs.exists(path.join(config.cwd, 'node_modules', 'example-yarn-workspace-3', 'node_modules', 'left-pad')),
145+
).toBeFalsy();
146+
},
147+
);
148+
});
149+
150+
test.concurrent("focus runs shallow dependencies' postinstall scripts", (): Promise<void> => {
151+
return runInstall(
152+
{focus: true},
153+
{source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-4'},
154+
async (config, reporter) => {
155+
expect(
156+
await fs.exists(path.join(config.cwd, 'node_modules', 'example-yarn-workspace-3', 'temp.out')),
157+
).toBeTruthy();
158+
},
159+
);
160+
});
161+
162+
test.concurrent('focus installs transitive dependencies shallowly', (): Promise<void> => {
163+
return runInstall(
164+
{focus: true},
165+
{source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-4'},
166+
async (config, reporter) => {
167+
expect(
168+
await fs.exists(path.join(config.cwd, 'node_modules', 'example-yarn-workspace-1', 'package.json')),
169+
).toBeTruthy();
170+
},
171+
);
172+
});
173+
174+
test.concurrent(
175+
'focus does not install transitive devdependencies shallowly (but does install non-transitive devdeps)',
176+
(): Promise<void> => {
177+
return runInstall(
178+
{focus: true},
179+
{source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-6'},
180+
async (config, reporter) => {
181+
expect(await fs.exists(path.join(config.cwd, 'node_modules', 'example-yarn-workspace-5'))).toBeTruthy();
182+
expect(
183+
await fs.exists(
184+
path.join(
185+
config.cwd,
186+
'node_modules',
187+
'example-yarn-workspace-5',
188+
'node_modules',
189+
'example-yarn-workspace-2',
190+
),
191+
),
192+
).toBeFalsy();
193+
expect(await fs.exists(path.join(config.cwd, 'node_modules', 'example-yarn-workspace-2'))).toBeFalsy();
194+
},
195+
);
196+
},
197+
);
198+
199+
test.concurrent(
200+
'focus does not shallowly install current version of sibling if another version is specified in package.json',
201+
(): Promise<void> => {
202+
return runInstall(
203+
{focus: true},
204+
{source: 'focus-different-versions', cwd: '/packages/example-yarn-workspace-1'},
205+
async (config, reporter) => {
206+
const packageFile = await fs.readFile(
207+
path.join(config.cwd, 'node_modules', 'example-yarn-workspace-2', 'package.json'),
208+
);
209+
expect(JSON.parse(packageFile).version).toEqual('1.0.1');
210+
},
211+
);
212+
},
213+
);
214+
215+
describe('nohoist', () => {
216+
test.concurrent('focus installs nohoist dependencies shallowly', (): Promise<void> => {
217+
return runInstall(
218+
{focus: true},
219+
{source: 'focus-nohoist', cwd: '/packages/example-yarn-workspace-1'},
220+
async (config, reporter) => {
221+
const moduleDir = path.join(config.cwd, 'node_modules', 'example-yarn-workspace-2');
222+
expect(await fs.exists(path.join(moduleDir, 'package.json'))).toBeTruthy();
223+
const stat = await fs.lstat(moduleDir);
224+
expect(stat.isSymbolicLink()).toEqual(false);
225+
},
226+
);
227+
});
228+
229+
test.concurrent('focus does not do nested shallow installs of transitive nohoist packages', (): Promise<void> => {
230+
return runInstall(
231+
{focus: true},
232+
{source: 'focus-nohoist', cwd: '/packages/example-yarn-workspace-3'},
233+
async (config, reporter) => {
234+
const moduleDir = path.join(
235+
config.cwd,
236+
'node_modules',
237+
'example-yarn-workspace-1',
238+
'node_modules',
239+
'example-yarn-workspace-2',
240+
);
241+
expect(await fs.exists(path.join(moduleDir, 'package.json'))).toBeFalsy();
242+
},
243+
);
244+
});
245+
246+
test.concurrent(
247+
'focus installs the correct version when a package is nohoist but differs from the workspace version',
248+
(): Promise<void> => {
249+
return runInstall(
250+
{focus: true},
251+
{source: 'focus-nohoist-different-versions', cwd: '/packages/example-yarn-workspace-6'},
252+
async (config, reporter) => {
253+
const packageFile = await fs.readFile(
254+
path.join(config.cwd, 'node_modules', 'example-yarn-workspace-2', 'package.json'),
255+
);
256+
expect(JSON.parse(packageFile).version).toEqual('1.0.0');
257+
},
258+
);
259+
},
260+
);
261+
});

__tests__/commands/install/integration.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ test('changes the cache directory when bumping the cache version', async () => {
257257
await resolver.init([{pattern: 'is-array', registry: 'npm'}]);
258258

259259
const ref = resolver.getManifests()[0]._reference;
260-
const cachePath = config.generateHardModulePath(ref, true);
260+
const cachePath = config.generateModuleCachePath(ref);
261261

262262
await fs.writeFile(path.join(cachePath, 'yarn.test'), 'YARN TEST');
263263
await fs.unlink(path.join(config.cwd, 'node_modules'));
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "my-project",
3+
"private": true,
4+
"workspaces": [
5+
"packages/*"
6+
]
7+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "left-pad",
3+
"version": "1.1.2",
4+
"description": "String left pad",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "node test",
8+
"bench": "node perf/perf.js"
9+
},
10+
"keywords": [
11+
"leftpad",
12+
"left",
13+
"pad",
14+
"padding",
15+
"string",
16+
"repeat"
17+
],
18+
"repository": {
19+
"url": "git@github.com:stevemao/left-pad.git",
20+
"type": "git"
21+
},
22+
"author": "azer",
23+
"maintainers": [
24+
{
25+
"name": "Cameron Westland",
26+
"email": "camwest@gmail.com"
27+
}
28+
],
29+
"license": "WTFPL"
30+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "workspace-1",
3+
"version": "1.0.0",
4+
"dependencies": {
5+
"left-pad": "1.1.2"
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "monorepo",
3+
"private": true,
4+
"workspaces": [
5+
"packages/*"
6+
]
7+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
WORKSPACES ROCK!
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log('p1');

0 commit comments

Comments
 (0)