Skip to content

Commit

Permalink
fix(lifecycles): Avoid duplicating 'rooted leaf' lifecycles
Browse files Browse the repository at this point in the history
  • Loading branch information
evocateur committed Feb 27, 2019
1 parent 514bc57 commit a7ad9b6
Show file tree
Hide file tree
Showing 15 changed files with 114 additions and 39 deletions.
7 changes: 7 additions & 0 deletions __fixtures__/lifecycle-rooted-leaf/lerna.json
@@ -0,0 +1,7 @@
{
"packages": [
"packages/*",
"."
],
"version": "1.0.0"
}
18 changes: 18 additions & 0 deletions __fixtures__/lifecycle-rooted-leaf/package.json
@@ -0,0 +1,18 @@
{
"name": "lifecycle-rooted-leaf",
"version": "1.0.0",
"dependencies": {
"package-1": "file:packages/package-1"
},
"scripts": {
"preversion": "echo preversion-rooted-leaf",
"version": "echo version-rooted-leaf",
"postversion": "echo postversion-rooted-leaf",
"prepublish": "echo prepublish-rooted-leaf",
"prepare": "echo prepare-rooted-leaf",
"prepublishOnly": "echo prepublishOnly-rooted-leaf",
"prepack": "echo prepack-rooted-leaf",
"postpack": "echo postpack-rooted-leaf",
"postpublish": "echo postpublish-rooted-leaf"
}
}
File renamed without changes.
File renamed without changes.
13 changes: 13 additions & 0 deletions __fixtures__/lifecycle/packages/package-1/package.json
@@ -0,0 +1,13 @@
{
"name": "package-1",
"version": "1.0.0",
"scripts": {
"preversion": "echo preversion-package-1",
"version": "echo version-package-1",
"postversion": "echo postversion-package-1",
"prepare": "echo prepare-package-1",
"prepublishOnly": "echo prepublishOnly-package-1",
"prepack": "echo prepack-package-1",
"postpublish": "echo postpublish-package-1"
}
}

This file was deleted.

This file was deleted.

3 changes: 0 additions & 3 deletions commands/publish/__tests__/__fixtures__/lifecycle/lerna.json

This file was deleted.

18 changes: 18 additions & 0 deletions commands/publish/__tests__/publish-lifecycle-scripts.test.js
Expand Up @@ -90,4 +90,22 @@ Map {
["lifecycle", "postpack"],
]);
});

it("does not duplicate rooted leaf scripts", async () => {
const cwd = await initFixture("lifecycle-rooted-leaf");

await lernaPublish(cwd)();

expect(runLifecycle.getOrderedCalls()).toEqual([
// TODO: separate from VersionCommand details
["package-1", "preversion"],
["package-1", "version"],
["lifecycle-rooted-leaf", "preversion"],
["lifecycle-rooted-leaf", "version"],
["lifecycle-rooted-leaf", "postversion"],
["package-1", "postversion"],
// NO publish-specific root lifecycles should be duplicated
// (they are all run by pack-directory and npm-publish)
]);
});
});
33 changes: 23 additions & 10 deletions commands/publish/index.js
Expand Up @@ -114,6 +114,13 @@ class PublishCommand extends Command {
this.conf.set("tag", distTag.trim(), "cli");
}

// a "rooted leaf" is the regrettable pattern of adding "." to the "packages" config in lerna.json
this.hasRootedLeaf = this.packageGraph.has(this.project.manifest.name);

if (this.hasRootedLeaf) {
this.logger.info("publish", "rooted leaf detected, skipping synthetic root lifecycles");
}

this.runPackageLifecycle = createRunner(this.options);

// don't execute recursively if run from a poorly-named script
Expand Down Expand Up @@ -572,13 +579,15 @@ class PublishCommand extends Command {

chain = chain.then(() => createTempLicenses(this.project.licensePath, this.packagesToBeLicensed));

// despite being deprecated for years...
chain = chain.then(() => this.runRootLifecycle("prepublish"));
if (!this.hasRootedLeaf) {
// despite being deprecated for years...
chain = chain.then(() => this.runRootLifecycle("prepublish"));

// these lifecycles _should_ never be employed to run `lerna publish`...
chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, "prepare"));
chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, "prepublishOnly"));
chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, "prepack"));
// these lifecycles _should_ never be employed to run `lerna publish`...
chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, "prepare"));
chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, "prepublishOnly"));
chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, "prepack"));
}

const { contents } = this.options;
const getLocation = contents ? pkg => path.resolve(pkg.location, contents) : pkg => pkg.location;
Expand Down Expand Up @@ -611,7 +620,9 @@ class PublishCommand extends Command {
// remove temporary license files if _any_ error occurs _anywhere_ in the promise chain
chain = chain.catch(error => this.removeTempLicensesOnError(error));

chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, "postpack"));
if (!this.hasRootedLeaf) {
chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, "postpack"));
}

return pFinally(chain, () => tracker.finish());
}
Expand Down Expand Up @@ -647,9 +658,11 @@ class PublishCommand extends Command {

chain = chain.then(() => runParallelBatches(this.batchedPackages, this.concurrency, mapper));

// cyclical "publish" lifecycles are automatically skipped
chain = chain.then(() => this.runRootLifecycle("publish"));
chain = chain.then(() => this.runRootLifecycle("postpublish"));
if (!this.hasRootedLeaf) {
// cyclical "publish" lifecycles are automatically skipped
chain = chain.then(() => this.runRootLifecycle("publish"));
chain = chain.then(() => this.runRootLifecycle("postpublish"));
}

return pFinally(chain, () => tracker.finish());
}
Expand Down
19 changes: 16 additions & 3 deletions commands/version/__tests__/version-lifecycle-scripts.test.js
Expand Up @@ -6,14 +6,12 @@ jest.mock("../lib/is-anything-committed");
jest.mock("../lib/is-behind-upstream");
jest.mock("../lib/remote-branch-exists");

const path = require("path");

// mocked modules
const runLifecycle = require("@lerna/run-lifecycle");
const loadJsonFile = require("load-json-file");

// helpers
const initFixture = require("@lerna-test/init-fixture")(path.resolve(__dirname, "../../publish/__tests__"));
const initFixture = require("@lerna-test/init-fixture")(__dirname);

// test command
const lernaVersion = require("@lerna-test/command-runner")(require("../command"));
Expand Down Expand Up @@ -74,4 +72,19 @@ Map {
["package-1", "postversion"],
]);
});

it("does not duplicate rooted leaf scripts", async () => {
const cwd = await initFixture("lifecycle-rooted-leaf");

await lernaVersion(cwd)();

expect(runLifecycle.getOrderedCalls()).toEqual([
["package-1", "preversion"],
["package-1", "version"],
["lifecycle-rooted-leaf", "preversion"],
["lifecycle-rooted-leaf", "version"],
["lifecycle-rooted-leaf", "postversion"],
["package-1", "postversion"],
]);
});
});
25 changes: 19 additions & 6 deletions commands/version/index.js
Expand Up @@ -207,6 +207,13 @@ class VersionCommand extends Command {
return false;
}

// a "rooted leaf" is the regrettable pattern of adding "." to the "packages" config in lerna.json
this.hasRootedLeaf = this.packageGraph.has(this.project.manifest.name);

if (this.hasRootedLeaf && !this.composed) {
this.logger.info("version", "rooted leaf detected, skipping synthetic root lifecycles");
}

this.runPackageLifecycle = createRunner(this.options);

// don't execute recursively if run from a poorly-named script
Expand Down Expand Up @@ -450,8 +457,10 @@ class VersionCommand extends Command {
// postversion: Run AFTER bumping the package version, and AFTER commit.
// @see https://docs.npmjs.com/misc/scripts

// exec preversion lifecycle in root (before all updates)
chain = chain.then(() => this.runRootLifecycle("preversion"));
if (!this.hasRootedLeaf) {
// exec preversion lifecycle in root (before all updates)
chain = chain.then(() => this.runRootLifecycle("preversion"));
}

const actions = [
pkg => this.runPackageLifecycle(pkg, "preversion").then(() => pkg),
Expand Down Expand Up @@ -548,8 +557,10 @@ class VersionCommand extends Command {
);
}

// exec version lifecycle in root (after all updates)
chain = chain.then(() => this.runRootLifecycle("version"));
if (!this.hasRootedLeaf) {
// exec version lifecycle in root (after all updates)
chain = chain.then(() => this.runRootLifecycle("version"));
}

if (this.commitAndTag) {
chain = chain.then(() => gitAdd(Array.from(changedFiles), this.execOpts));
Expand All @@ -576,8 +587,10 @@ class VersionCommand extends Command {
pMap(this.packagesToVersion, pkg => this.runPackageLifecycle(pkg, "postversion"))
);

// run postversion, if set, in the root directory
chain = chain.then(() => this.runRootLifecycle("postversion"));
if (!this.hasRootedLeaf) {
// run postversion, if set, in the root directory
chain = chain.then(() => this.runRootLifecycle("postversion"));
}

return chain;
}
Expand Down

0 comments on commit a7ad9b6

Please sign in to comment.