diff --git a/libs/commands/publish/README.md b/libs/commands/publish/README.md index badb4ee6f7..1e6ae9c00e 100644 --- a/libs/commands/publish/README.md +++ b/libs/commands/publish/README.md @@ -334,7 +334,8 @@ Useful in [Continuous integration (CI)](https://en.wikipedia.org/wiki/Continuous lerna publish --canary --yes --summary-file # Will create a summary file in the provided directory, i.e. `./some/other/dir/lerna-publish-summary.json` lerna publish --canary --yes --summary-file ./some/other/dir - +# Will create a summary file with the provided name, i.e. `./some/other/dir/my-summary.json` +lerna publish --canary --yes --summary-file ./some/other/dir/my-summary.json ``` When run with this flag, a json summary report will be generated after all packages have been successfully published (see below for an example). diff --git a/libs/commands/publish/src/index.ts b/libs/commands/publish/src/index.ts index 14431130e4..910567d22f 100644 --- a/libs/commands/publish/src/index.ts +++ b/libs/commands/publish/src/index.ts @@ -415,16 +415,15 @@ class PublishCommand extends Command { output("Successfully published:"); if (this.options.summaryFile !== undefined) { - // create a json object and output it to a file location. - const filePath = this.options.summaryFile - ? `${this.options.summaryFile}/lerna-publish-summary.json` - : "./lerna-publish-summary.json"; + const filePath = this.getSummaryFilePath(); + const jsonObject = publishedPackagesSorted.map((pkg) => { return { packageName: pkg.name, version: pkg.version, }; }); + output(jsonObject); try { fs.writeFileSync(filePath, JSON.stringify(jsonObject)); @@ -1220,6 +1219,28 @@ class PublishCommand extends Command { } } } + + private getSummaryFilePath(): string { + if (this.options.summaryFile === undefined) { + throw new Error("summaryFile options is not defined. Unable to get path."); + } + + if (this.options.summaryFile === "") { + return path.join(process.cwd(), "./lerna-publish-summary.json"); + } + + const normalizedPath = path.normalize(this.options.summaryFile); + + if (normalizedPath === "") { + throw new Error("summaryFile is not a valid path."); + } + + if (normalizedPath.endsWith(".json")) { + return path.join(process.cwd(), normalizedPath); + } + + return path.join(process.cwd(), normalizedPath, "lerna-publish-summary.json"); + } } module.exports.PublishCommand = PublishCommand; diff --git a/libs/commands/publish/src/lib/publish-command.spec.ts b/libs/commands/publish/src/lib/publish-command.spec.ts index 9ec3ddc42b..a346e37886 100644 --- a/libs/commands/publish/src/lib/publish-command.spec.ts +++ b/libs/commands/publish/src/lib/publish-command.spec.ts @@ -382,7 +382,7 @@ Map { ]; expect(fsSpy).toHaveBeenCalled(); expect(fsSpy).toHaveBeenCalledWith( - "./outputs/lerna-publish-summary.json", + path.join(process.cwd(), "outputs/lerna-publish-summary.json"), JSON.stringify(expectedJsonResponse) ); }); @@ -392,6 +392,25 @@ Map { const fsSpy = jest.spyOn(fsmain, "writeFileSync"); await lernaPublish(cwd)("--summary-file"); + const expectedJsonResponse = [ + { packageName: "package-1", version: "1.0.1" }, + { packageName: "package-2", version: "1.0.1" }, + { packageName: "package-3", version: "1.0.1" }, + { packageName: "package-4", version: "1.0.1" }, + ]; + + expect(fsSpy).toHaveBeenCalled(); + expect(fsSpy).toHaveBeenCalledWith( + path.join(process.cwd(), "./lerna-publish-summary.json"), + JSON.stringify(expectedJsonResponse) + ); + }); + + it("creates the summary file in the provided file path", async () => { + const cwd = await initFixture("normal"); + const fsSpy = jest.spyOn(fsmain, "writeFileSync"); + await lernaPublish(cwd)("--summary-file", "./outputs/lerna-publish-summary.json"); + const expectedJsonResponse = [ { packageName: "package-1", version: "1.0.1" }, { packageName: "package-2", version: "1.0.1" }, @@ -400,7 +419,7 @@ Map { ]; expect(fsSpy).toHaveBeenCalled(); expect(fsSpy).toHaveBeenCalledWith( - "./lerna-publish-summary.json", + path.join(process.cwd(), "outputs/lerna-publish-summary.json"), JSON.stringify(expectedJsonResponse) ); }); diff --git a/libs/commands/version/src/index.ts b/libs/commands/version/src/index.ts index 8a7712baa1..bfa0dcfe77 100644 --- a/libs/commands/version/src/index.ts +++ b/libs/commands/version/src/index.ts @@ -117,6 +117,7 @@ class VersionCommand extends Command { signoffGitCommit?: boolean; signGitTag?: boolean; forceGitTag?: boolean; + overrideMessage?: boolean; }; savePrefix?: string; currentBranch?: string; @@ -175,12 +176,14 @@ class VersionCommand extends Command { forceGitTag, tagVersionPrefix = "v", premajorVersionBump = "default", + message, } = this.options; this.gitRemote = gitRemote; this.tagPrefix = tagVersionPrefix; this.commitAndTag = gitTagVersion; this.pushToRemote = gitTagVersion && amend !== true && push; + const overrideMessage: boolean = amend && !!message; this.premajorVersionBump = premajorVersionBump; // never automatically push to remote when amending a commit @@ -204,6 +207,7 @@ class VersionCommand extends Command { signoffGitCommit, signGitTag, forceGitTag, + overrideMessage, }; // https://docs.npmjs.com/misc/config#save-prefix diff --git a/libs/commands/version/src/lib/git-commit.ts b/libs/commands/version/src/lib/git-commit.ts index b45d11cdf2..f8f2eea339 100644 --- a/libs/commands/version/src/lib/git-commit.ts +++ b/libs/commands/version/src/lib/git-commit.ts @@ -7,6 +7,7 @@ const childProcess = require("@lerna/child-process"); export interface GitCommitOptions { amend?: boolean; + overrideMessage?: boolean; commitHooks?: boolean; signGitCommit?: boolean; signoffGitCommit?: boolean; @@ -14,7 +15,7 @@ export interface GitCommitOptions { export function gitCommit( message: string, - { amend, commitHooks, signGitCommit, signoffGitCommit }: GitCommitOptions, + { amend, commitHooks, signGitCommit, signoffGitCommit, overrideMessage }: GitCommitOptions, opts: ExecOptions ) { log.silly("gitCommit", message); @@ -32,13 +33,20 @@ export function gitCommit( args.push("--signoff"); } + const shouldChangeMessage = amend ? amend && overrideMessage : true; if (amend) { - args.push("--amend", "--no-edit"); - } else if (message.indexOf(EOL) > -1) { - // Use tempfile to allow multi\nline strings. - args.push("-F", tempWrite.sync(message, "lerna-commit.txt")); + args.push("--amend"); + } + + if (shouldChangeMessage) { + if (message.indexOf(EOL) > -1) { + // Use tempfile to allow multi\nline strings. + args.push("-F", tempWrite.sync(message, "lerna-commit.txt")); + } else { + args.push("-m", message); + } } else { - args.push("-m", message); + args.push("--no-edit"); } // TODO: refactor to address type issues diff --git a/libs/commands/version/src/lib/version-command.spec.ts b/libs/commands/version/src/lib/version-command.spec.ts index e5b2182fc9..9f4f6c6878 100644 --- a/libs/commands/version/src/lib/version-command.spec.ts +++ b/libs/commands/version/src/lib/version-command.spec.ts @@ -636,12 +636,13 @@ Changes: expect(checkWorkingTree).not.toHaveBeenCalled(); }); - it("ignores custom messages", async () => { + it("considers custom messages", async () => { const testDir = await initFixture("normal", "preserved"); - await lernaVersion(testDir)("-m", "ignored", "--amend"); + await lernaVersion(testDir)("-m", "custom", "--amend"); const message = await getCommitMessage(testDir); - expect(message).toBe("preserved"); + + expect(message).toBe("custom"); }); }); diff --git a/package-lock.json b/package-lock.json index 57640e7793..9a61341695 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6915,9 +6915,9 @@ "dev": true }, "node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", + "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -8364,14 +8364,14 @@ } }, "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dependencies": { + "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" + "parse-json": "^5.2.0" }, "engines": { "node": ">=14" @@ -13948,11 +13948,11 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -19028,7 +19028,7 @@ "console-control-strings": "^1.1.0", "conventional-changelog-core": "5.0.1", "conventional-recommended-bump": "7.0.1", - "cosmiconfig": "^8.2.0", + "cosmiconfig": "9.0.0", "dedent": "1.5.3", "execa": "5.0.0", "file-url": "3.0.0", @@ -19133,7 +19133,7 @@ "console-control-strings": "^1.1.0", "conventional-changelog-core": "5.0.1", "conventional-recommended-bump": "7.0.1", - "cosmiconfig": "^8.2.0", + "cosmiconfig": "9.0.0", "dedent": "1.5.3", "execa": "5.0.0", "fs-extra": "^11.2.0", @@ -19241,7 +19241,7 @@ "conventional-changelog-angular": "7.0.0", "conventional-changelog-core": "5.0.1", "conventional-recommended-bump": "7.0.1", - "cosmiconfig": "^8.2.0", + "cosmiconfig": "9.0.0", "dedent": "1.5.3", "envinfo": "7.13.0", "execa": "5.0.0", diff --git a/packages/legacy-package-management/package.json b/packages/legacy-package-management/package.json index 2f3436ffce..58d949aee9 100644 --- a/packages/legacy-package-management/package.json +++ b/packages/legacy-package-management/package.json @@ -41,7 +41,7 @@ "console-control-strings": "^1.1.0", "conventional-changelog-core": "5.0.1", "conventional-recommended-bump": "7.0.1", - "cosmiconfig": "^8.2.0", + "cosmiconfig": "9.0.0", "dedent": "1.5.3", "execa": "5.0.0", "file-url": "3.0.0", diff --git a/packages/legacy-structure/commands/create/package.json b/packages/legacy-structure/commands/create/package.json index 7200c83789..b07663fe82 100644 --- a/packages/legacy-structure/commands/create/package.json +++ b/packages/legacy-structure/commands/create/package.json @@ -46,7 +46,7 @@ "console-control-strings": "^1.1.0", "conventional-changelog-core": "5.0.1", "conventional-recommended-bump": "7.0.1", - "cosmiconfig": "^8.2.0", + "cosmiconfig": "9.0.0", "dedent": "1.5.3", "execa": "5.0.0", "fs-extra": "^11.2.0", diff --git a/packages/lerna/package.json b/packages/lerna/package.json index c7e4cc0100..313850a3c4 100644 --- a/packages/lerna/package.json +++ b/packages/lerna/package.json @@ -55,7 +55,7 @@ "conventional-changelog-angular": "7.0.0", "conventional-changelog-core": "5.0.1", "conventional-recommended-bump": "7.0.1", - "cosmiconfig": "^8.2.0", + "cosmiconfig": "9.0.0", "dedent": "1.5.3", "envinfo": "7.13.0", "execa": "5.0.0", diff --git a/packages/lerna/schemas/lerna-schema.json b/packages/lerna/schemas/lerna-schema.json index f5dc39609a..021cbf0914 100644 --- a/packages/lerna/schemas/lerna-schema.json +++ b/packages/lerna/schemas/lerna-schema.json @@ -9,6 +9,10 @@ "type": "string", "description": "The JSON schema version used to validate this configuration file" }, + "extends": { + "type": "string", + "description": "A shareable configuration preset that will be used as the base for this configuration" + }, "version": { "type": "string", "description": "The version of the repository, or \"independent\" for a repository with independently versioned packages.",