Skip to content

Commit

Permalink
fix(bootstrap): When filtering, only bootstrap filtered packages
Browse files Browse the repository at this point in the history
The remaining siblings will be installed from the configured registry.

Fixes #1421
Fixes #1766
  • Loading branch information
evocateur committed Jan 10, 2019
1 parent fc7463f commit 71174e4
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 18 deletions.
Expand Up @@ -252,15 +252,39 @@ Object {
"bar@^2.0.0",
"foo@^1.0.0",
],
"packages/package-3": Array [
"foo@0.1.12",
"@test/package-2@^1.0.0",
],
}
`;

exports[`BootstrapCommand with local package dependencies should not bootstrap ignored packages 2`] = `
Array [
Object {
"_src": "packages/package-1",
"dest": "packages/package-3/node_modules/@test/package-1",
"type": "junction",
},
]
`;

exports[`BootstrapCommand with local package dependencies should not update package.json when filtering 1`] = `
Object {
"packages/package-2": Array [
"@test/package-1@^1.0.0",
"foo@^1.0.0",
],
}
`;

exports[`BootstrapCommand with local package dependencies should not update package.json when filtering 2`] = `Array []`;

exports[`BootstrapCommand with local package dependencies should only bootstrap scoped packages 1`] = `
Object {
"packages/package-3": Array [
"@test/package-1@^1.0.0",
"@test/package-2@^1.0.0",
"foo@0.1.12",
],
"packages/package-4": Array [
Expand All @@ -271,21 +295,6 @@ Object {

exports[`BootstrapCommand with local package dependencies should only bootstrap scoped packages 2`] = `
Array [
Object {
"_src": "packages/package-1",
"dest": "packages/package-3/node_modules/@test/package-1",
"type": "junction",
},
Object {
"_src": "packages/package-2",
"dest": "packages/package-3/node_modules/@test/package-2",
"type": "junction",
},
Object {
"_src": "packages/package-2/cli.js",
"dest": "packages/package-3/node_modules/.bin/package-2",
"type": "exec",
},
Object {
"_src": "packages/package-3",
"dest": "packages/package-4/node_modules/package-3",
Expand All @@ -304,6 +313,28 @@ Array [
]
`;

exports[`BootstrapCommand with local package dependencies should respect --force-local 1`] = `
Object {
"packages/package-1": Array [
"bar@^2.0.0",
"foo@^1.0.0",
],
"packages/package-4": Array [
"package-3@^1.0.0",
],
}
`;

exports[`BootstrapCommand with local package dependencies should respect --force-local 2`] = `
Array [
Object {
"_src": "packages/package-1",
"dest": "packages/package-4/node_modules/@test/package-1",
"type": "junction",
},
]
`;

exports[`BootstrapCommand with multiple package locations bootstraps dependencies excluded by --ignore with --include-filtered-dependencies 1`] = `
Object {
"packages/package-1": Array [
Expand Down
39 changes: 37 additions & 2 deletions commands/bootstrap/__tests__/bootstrap-command.test.js
Expand Up @@ -228,7 +228,7 @@ describe("BootstrapCommand", () => {
it("should not pass subCommand to npmInstall if on npm version earlier than 5.7.0", async () => {
const testDir = await initFixture("ci");

hasNpmVersion.mockReturnValue(false);
hasNpmVersion.mockReturnValueOnce(false);

await lernaBootstrap(testDir)("--ci");

Expand Down Expand Up @@ -277,9 +277,10 @@ describe("BootstrapCommand", () => {
it("should not bootstrap ignored packages", async () => {
const testDir = await initFixture("basic");

await lernaBootstrap(testDir)("--ignore", "package-@(3|4)");
await lernaBootstrap(testDir)("--ignore", "{@test/package-2,package-4}");

expect(installedPackagesInDirectories(testDir)).toMatchSnapshot();
expect(symlinkedDirectories(testDir)).toMatchSnapshot();
});

it("should only bootstrap scoped packages", async () => {
Expand All @@ -291,6 +292,40 @@ describe("BootstrapCommand", () => {
expect(symlinkedDirectories(testDir)).toMatchSnapshot();
});

it("should respect --force-local", async () => {
const testDir = await initFixture("basic");

await lernaBootstrap(testDir)("--scope", "@test/package-1", "--scope", "package-4", "--force-local");

expect(installedPackagesInDirectories(testDir)).toMatchSnapshot();
expect(symlinkedDirectories(testDir)).toMatchSnapshot();
});

it("should not update package.json when filtering", async () => {
const testDir = await initFixture("basic");

await lernaBootstrap(testDir)("--scope", "@test/package-2", "--ci");

expect(installedPackagesInDirectories(testDir)).toMatchSnapshot();
expect(symlinkedDirectories(testDir)).toMatchSnapshot();
expect(npmInstall.dependencies.mock.calls[0][2]).toMatchObject({
subCommand: "install", // not "ci"
npmClient: "npm",
npmClientArgs: ["--no-save"],
});
});

it("should not update yarn.lock when filtering", async () => {
const testDir = await initFixture("basic");

await lernaBootstrap(testDir)("--scope", "@test/package-2", "--npm-client", "yarn", "--ci");

expect(npmInstall.dependencies.mock.calls[0][2]).toMatchObject({
npmClient: "yarn",
npmClientArgs: ["--pure-lockfile"],
});
});

it("never installs with global style", async () => {
const testDir = await initFixture("basic");

Expand Down
40 changes: 39 additions & 1 deletion commands/bootstrap/index.js
Expand Up @@ -103,9 +103,47 @@ class BootstrapCommand extends Command {

let chain = Promise.resolve();

chain = chain.then(() => getFilteredPackages(this.targetGraph, this.execOpts, this.options));
chain = chain.then(() => {
if (this.options.scope) {
this.logger.notice("filter", "including %j", this.options.scope);
}

if (this.options.ignore) {
this.logger.notice("filter", "excluding %j", this.options.ignore);
}

if (this.options.since) {
this.logger.notice("filter", "changed since %j", this.options.since);
}

if (this.options.includeFilteredDependents) {
this.logger.notice("filter", "including filtered dependents");
}

if (this.options.includeFilteredDependencies) {
this.logger.notice("filter", "including filtered dependencies");
}

return getFilteredPackages(this.targetGraph, this.execOpts, this.options);
});

chain = chain.then(filteredPackages => {
this.filteredPackages = filteredPackages;

if (filteredPackages.length !== this.targetGraph.size) {
this.logger.warn("bootstrap", "Installing local packages that do not match filters from registry");

// an explicit --scope, --ignore, or --since should only symlink the targeted packages, no others
this.targetGraph = new PackageGraph(filteredPackages, "allDependencies", this.options.forceLocal);

// never automatically --save or modify lockfiles
this.npmConfig.npmClientArgs.unshift(npmClient === "yarn" ? "--pure-lockfile" : "--no-save");

// never attempt `npm ci`, it would always fail
if (this.npmConfig.subCommand === "ci") {
this.npmConfig.subCommand = "install";
}
}
});

chain = chain.then(() => {
Expand Down

0 comments on commit 71174e4

Please sign in to comment.