Skip to content

Commit 56445d9

Browse files
committed
focused workspaces
1 parent cbc6c88 commit 56445d9

File tree

23 files changed

+454
-111
lines changed

23 files changed

+454
-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/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+
}

__tests__/package-hoister.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ function createTestFixture(
4646
getFolder(): string {
4747
return 'node_modules';
4848
},
49-
generateHardModulePath(pkg: ?PackageReference): string {
49+
generateModuleCachePath(pkg: ?PackageReference): string {
5050
return pkg ? pkg.uid : '';
5151
},
5252
getWorkspaces(manifest: ?Manifest): ?WorkspacesConfig {

__tests__/package-resolver.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ function addTest(pattern, registry = 'npm', init: ?(cacheFolder: string) => Prom
5151
await resolver.init([{pattern, registry}]);
5252

5353
const ref = resolver.getManifests()[0]._reference;
54-
const cachePath = config.generateHardModulePath(ref, true);
54+
const cachePath = config.generateModuleCachePath(ref);
5555
expect(cachePath).toMatch(cachePathRe);
5656

5757
await reporter.close();

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
"release-branch": "./scripts/release-branch.sh",
118118
"test": "yarn lint && yarn test-only",
119119
"test-only": "node --max_old_space_size=4096 node_modules/jest/bin/jest.js --verbose",
120+
"test-only-debug": "node --inspect-brk --max_old_space_size=4096 node_modules/jest/bin/jest.js --runInBand --verbose",
120121
"test-coverage": "node --max_old_space_size=4096 node_modules/jest/bin/jest.js --coverage --verbose",
121122
"watch": "gulp watch",
122123
"commit": "git-cz"

src/cli/commands/check.js

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ export async function verifyTreeCheck(
3939
// check all dependencies recursively without relying on internal resolver
4040
const registryName = 'yarn';
4141
const registry = config.registries[registryName];
42-
const rootManifest = await config.readManifest(registry.cwd, registryName);
42+
const cwd = config.workspaceRootFolder ? config.lockfileFolder : config.cwd;
43+
const rootManifest = await config.readManifest(cwd, registryName);
4344

4445
type PackageToVerify = {
4546
name: string,
@@ -59,7 +60,7 @@ export async function verifyTreeCheck(
5960
dependenciesToCheckVersion.push({
6061
name,
6162
originalKey: name,
62-
parentCwd: registry.cwd,
63+
parentCwd: cwd,
6364
version,
6465
});
6566
}
@@ -75,7 +76,7 @@ export async function verifyTreeCheck(
7576
dependenciesToCheckVersion.push({
7677
name,
7778
originalKey: name,
78-
parentCwd: registry.cwd,
79+
parentCwd: cwd,
7980
version,
8081
});
8182
}
@@ -109,19 +110,15 @@ export async function verifyTreeCheck(
109110
for (const subdep in dependencies) {
110111
const subDepPath = path.join(manifestLoc, registry.folder, subdep);
111112
let found = false;
112-
const relative = path.relative(registry.cwd, subDepPath);
113+
const relative = path.relative(cwd, subDepPath);
113114
const locations = path.normalize(relative).split(registry.folder + path.sep).filter(dir => !!dir);
114115
locations.pop();
115116
while (locations.length >= 0) {
116117
let possiblePath;
117118
if (locations.length > 0) {
118-
possiblePath = path.join(
119-
registry.cwd,
120-
registry.folder,
121-
locations.join(path.sep + registry.folder + path.sep),
122-
);
119+
possiblePath = path.join(cwd, registry.folder, locations.join(path.sep + registry.folder + path.sep));
123120
} else {
124-
possiblePath = registry.cwd;
121+
possiblePath = cwd;
125122
}
126123
if (await fs.exists(path.join(possiblePath, registry.folder, subdep))) {
127124
dependenciesToCheckVersion.push({

src/cli/commands/install.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,11 @@ type Flags = {
7575
// outdated, update-interactive
7676
includeWorkspaceDeps: boolean,
7777

78-
// remove, upgrade
78+
// add, remove, upgrade
7979
workspaceRootIsCwd: boolean,
80+
81+
// focus
82+
focus: boolean,
8083
};
8184

8285
/**
@@ -155,6 +158,9 @@ function normalizeFlags(config: Config, rawFlags: Object): Flags {
155158

156159
// add, remove, update
157160
workspaceRootIsCwd: rawFlags.workspaceRootIsCwd !== false,
161+
162+
// focus
163+
focus: !!rawFlags.focus,
158164
};
159165

160166
if (config.getOption('ignore-scripts')) {
@@ -514,6 +520,11 @@ export class Install {
514520
this.reporter.warn(this.reporter.lang('shrinkwrapWarning'));
515521
}
516522

523+
// running a focused install in a workspace root is not allowed
524+
if (this.flags.focus && (!this.config.workspaceRootFolder || this.config.cwd === this.config.workspaceRootFolder)) {
525+
throw new MessageError(this.reporter.lang('workspacesFocusRootCheck'));
526+
}
527+
517528
let flattenedTopLevelPatterns: Array<string> = [];
518529
const steps: Array<(curr: number, total: number) => Promise<{bailout: boolean} | void>> = [];
519530
const {
@@ -545,6 +556,7 @@ export class Install {
545556
isFlat: this.flags.flat,
546557
isFrozen: this.flags.frozenLockfile,
547558
workspaceLayout,
559+
focus: this.flags.focus,
548560
});
549561
topLevelPatterns = this.preparePatterns(rawPatterns);
550562
flattenedTopLevelPatterns = await this.flatten(topLevelPatterns);
@@ -575,6 +587,7 @@ export class Install {
575587
await this.linker.init(flattenedTopLevelPatterns, workspaceLayout, {
576588
linkDuplicates: this.flags.linkDuplicates,
577589
ignoreOptional: this.flags.ignoreOptional,
590+
focus: this.flags.focus,
578591
});
579592
}),
580593
);
@@ -633,7 +646,7 @@ export class Install {
633646
(await fs.exists(path.join(this.config.lockfileFolder, constants.LOCKFILE_FILENAME)))
634647
) {
635648
await this.saveLockfileAndIntegrity(topLevelPatterns, workspaceLayout);
636-
} else {
649+
} else if (!this.flags.focus) {
637650
this.reporter.info(this.reporter.lang('notSavedLockfileNoDependencies'));
638651
}
639652
this.maybeOutputUpdate();
@@ -805,7 +818,7 @@ export class Install {
805818
this.scripts.getArtifacts(),
806819
);
807820

808-
// --no-lockfile or --pure-lockfile or --frozen-lockfile flag
821+
// --no-lockfile or --pure-lockfile or --frozen-lockfile or --focus flag
809822
if (this.flags.lockfile === false || this.flags.pureLockfile || this.flags.frozenLockfile) {
810823
return;
811824
}
@@ -884,7 +897,7 @@ export class Install {
884897
}
885898
loc = ref.remote.reference;
886899
} else {
887-
loc = this.config.generateHardModulePath(ref);
900+
loc = this.config.generateModuleCachePath(ref);
888901
}
889902
const newPkg = await this.config.readManifest(loc);
890903
await this.resolver.updateManifest(ref, newPkg);
@@ -973,6 +986,7 @@ export function hasWrapper(commander: Object, args: Array<string>): boolean {
973986
export function setFlags(commander: Object) {
974987
commander.description('Yarn install is used to install all dependencies for a project.');
975988
commander.usage('install [flags]');
989+
commander.option('--focus', 'Focus on a single workspace by installing remote copies of its sibling workspaces.');
976990
commander.option('-g, --global', 'DEPRECATED');
977991
commander.option('-S, --save', 'DEPRECATED - save package to your `dependencies`');
978992
commander.option('-D, --save-dev', 'DEPRECATED - save package to your `devDependencies`');

0 commit comments

Comments
 (0)