diff --git a/libs/commands/version/README.md b/libs/commands/version/README.md index 72492afcd9..cc6340d066 100644 --- a/libs/commands/version/README.md +++ b/libs/commands/version/README.md @@ -53,6 +53,7 @@ Running `lerna version --conventional-commits` without the above flags will rele - [`--amend`](#--amend) - [`--build-metadata `](#--build-metadata) - [`--changelog-preset`](#--changelog-preset) + - [`--changelog-entry-additional-markdown`](#--changelog-entry-additional-markdown) - [`--conventional-commits`](#--conventional-commits) - [`--conventional-graduate`](#--conventional-graduate) - [`--conventional-prerelease`](#--conventional-prerelease) @@ -178,6 +179,26 @@ If the preset exports a builder function (e.g. `conventional-changelog-conventio } ``` +### `--changelog-entry-additional-markdown` + +```sh +lerna version --conventional-commits --changelog-entry-additional-markdown "### Some title\n\nSome *paragraph*" +``` + +This option allows you to optionally append additional markdown contents to the new changelog entry for the current release, for example if you want to add additional documentation, or link off to a reference site or video. + +If your text is static, and does not change from release to release, you could choose to set it in your `lerna.json`. + +```json +{ + "command": { + "version": { + "changelogEntryAdditionalMarkdown": "### Some title\n\nSome *paragraph*" + } + } +} +``` + ### `--conventional-commits` ```sh diff --git a/libs/commands/version/src/command.ts b/libs/commands/version/src/command.ts index f71c1a3652..fc1b9712c7 100644 --- a/libs/commands/version/src/command.ts +++ b/libs/commands/version/src/command.ts @@ -69,6 +69,10 @@ const command: CommandModule = { requiresArg: true, defaultDescription: "angular", }, + "changelog-entry-additional-markdown": { + describe: "Additional markdown to add to CHANGELOG.md entries.", + type: "string", + }, exact: { describe: "Specify cross-dependency version numbers exactly rather than with a caret (^).", type: "boolean", diff --git a/libs/commands/version/src/index.ts b/libs/commands/version/src/index.ts index a4664869bd..eb0d4eb9f9 100644 --- a/libs/commands/version/src/index.ts +++ b/libs/commands/version/src/index.ts @@ -84,6 +84,7 @@ interface VersionCommandConfigOptions extends CommandConfigOptions { message?: string; npmClientArgs?: string[]; changelogPreset?: string; + changelogEntryAdditionalMarkdown?: string; conventionalBumpPrerelease?: boolean; yes?: boolean; rejectCycles?: boolean; @@ -626,7 +627,12 @@ class VersionCommand extends Command { } async updatePackageVersions() { - const { conventionalCommits, changelogPreset, changelog = true } = this.options; + const { + conventionalCommits, + changelogPreset, + changelogEntryAdditionalMarkdown, + changelog = true, + } = this.options; const independentVersions = this.project.isIndependent(); const rootPath = this.project.manifest.location; const changedFiles = new Set(); @@ -678,6 +684,7 @@ class VersionCommand extends Command { actions.push((node) => updateChangelog(getPackage(node), type, { changelogPreset, + changelogEntryAdditionalMarkdown, rootPath, tagPrefix: this.tagPrefix, }).then(({ logPath, newEntry }) => { @@ -710,6 +717,7 @@ class VersionCommand extends Command { if (conventionalCommits && changelog) { const { logPath, newEntry } = await updateChangelog(this.project.manifest, "root", { changelogPreset, + changelogEntryAdditionalMarkdown, rootPath, tagPrefix: this.tagPrefix, version: this.globalVersion, diff --git a/libs/core/src/lib/conventional-commits/constants.ts b/libs/core/src/lib/conventional-commits/constants.ts index 0b3a26bddb..eafd953cbe 100644 --- a/libs/core/src/lib/conventional-commits/constants.ts +++ b/libs/core/src/lib/conventional-commits/constants.ts @@ -3,6 +3,7 @@ export type ChangelogType = "fixed" | "independent" | "root"; export type ChangelogPresetConfig = string | { name: string; [key: string]: unknown }; export type BaseChangelogOptions = { changelogPreset?: ChangelogPresetConfig; + changelogEntryAdditionalMarkdown?: string; rootPath: string; tagPrefix?: string; conventionalBumpPrerelease?: boolean; diff --git a/libs/core/src/lib/conventional-commits/index.spec.ts b/libs/core/src/lib/conventional-commits/index.spec.ts index 928e7209e1..6438488d9e 100644 --- a/libs/core/src/lib/conventional-commits/index.spec.ts +++ b/libs/core/src/lib/conventional-commits/index.spec.ts @@ -715,6 +715,64 @@ describe("conventional-commits", () => { * **thing:** added ([SHA](COMMIT_URL)) `); }); + + it("supports changelogEntryAdditionalMarkdown", async () => { + const cwd = await initFixture("fixed"); + const rootPkg = { + // no name + location: cwd, + }; + + await gitTag(cwd, "v1.0.0"); + + const [pkg1] = await getPackages(cwd); + + // make a change in package-1 + await pkg1.set("changed", 1).serialize(); + await gitAdd(cwd, pkg1.manifestLocation); + await gitCommit(cwd, "fix: A second commit for our CHANGELOG"); + + // update version + await pkg1.set("version", "1.0.1").serialize(); + + const [rootChangelogContent] = await Promise.all([ + updateChangelog(rootPkg, "root", { + version: "1.0.1", + changelogEntryAdditionalMarkdown: "#### Some title\n\nSome *paragraph*", + }).then(getFileContent), + ]); + + expect(rootChangelogContent).toMatchInlineSnapshot(` + # Change Log + + All notable changes to this project will be documented in this file. + See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + + ## [1.0.1](/compare/v1.0.0...v1.0.1) (YYYY-MM-DD) + + + ### Bug Fixes + + * A second commit for our CHANGELOG ([SHA](COMMIT_URL)) + + #### Some title + + Some *paragraph* + + + + + + + + # 1.0.0 (YYYY-MM-DD) + + ### Features + + * I should be placed in the CHANGELOG + + `); + }); }); describe("applyBuildMetadata", () => { diff --git a/libs/core/src/lib/conventional-commits/update-changelog.ts b/libs/core/src/lib/conventional-commits/update-changelog.ts index 585686bbd2..c2a27c5d2c 100644 --- a/libs/core/src/lib/conventional-commits/update-changelog.ts +++ b/libs/core/src/lib/conventional-commits/update-changelog.ts @@ -11,7 +11,13 @@ import { readExistingChangelog } from "./read-existing-changelog"; export function updateChangelog( pkg: Package, type: ChangelogType, - { changelogPreset, rootPath, tagPrefix = "v", version }: BaseChangelogOptions & { version?: string } + { + changelogPreset, + changelogEntryAdditionalMarkdown, + rootPath, + tagPrefix = "v", + version, + }: BaseChangelogOptions & { version?: string } ) { log.silly(type, "for %s at %s", pkg.name, pkg.location); @@ -62,6 +68,16 @@ export function updateChangelog( getStream(changelogStream).then(makeBumpOnlyFilter(pkg)), readExistingChangelog(pkg), ]).then(([newEntry, [changelogFileLoc, changelogContents]]) => { + // Append any additional markdown to the new entry, if provided + if (changelogEntryAdditionalMarkdown) { + // capture trailing whitespace on the newEntry and apply the additional markdown before it and reapply it + const trailingWhitespace = newEntry.match(/\s*$/); + newEntry = newEntry.replace( + /\s*$/, + BLANK_LINE + changelogEntryAdditionalMarkdown + trailingWhitespace + ); + } + log.silly(type, "writing new entry: %j", newEntry); const content = [CHANGELOG_HEADER, newEntry, changelogContents].join(BLANK_LINE); diff --git a/packages/lerna/schemas/lerna-schema.json b/packages/lerna/schemas/lerna-schema.json index bd08da3968..ee3db7199f 100644 --- a/packages/lerna/schemas/lerna-schema.json +++ b/packages/lerna/schemas/lerna-schema.json @@ -1668,6 +1668,10 @@ ], "description": "For `lerna version`, the custom conventional-changelog preset." }, + "changelogEntryAdditionalMarkdown": { + "type": "string", + "description": "Additional markdown to add to CHANGELOG.md entries." + }, "gitRemote": { "type": "string", "description": "During `lerna version`, push git changes to the specified remote."