Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(version): add flag to include changelog commit author, close #248 #253

Merged
merged 11 commits into from
Jul 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
"createRelease": "github",
"gitDryRun": false,
"syncWorkspaceLock": true,
"message": "chore(release): publish new version %v",
"changelogHeaderMessage": "### Automate your Workspace Versions, Changelogs & Publish with [Lerna-Lite](https://github.com/ghiscoding/lerna-lite) 🚀"
"changelogIncludeCommitAuthor": true,
"changelogHeaderMessage": "### Automate your Workspace Versions, Changelogs & Publish with [Lerna-Lite](https://github.com/ghiscoding/lerna-lite) 🚀",
"message": "chore(release): publish new version %v"
},
"run": {
"cmdDryRun": false
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"normalize-newline": "^3.0.0",
"normalize-path": "^3.0.0",
"npm-run-all": "^4.1.5",
"npmlog": "^6.0.2",
"nx": "14.4.2",
"prettier": "^2.7.1",
"rimraf": "^3.0.2",
Expand Down
6 changes: 6 additions & 0 deletions packages/cli/src/cli-commands/cli-version-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ export default {
requiresArg: true,
type: 'string',
},
'changelog-include-commit-author': {
describe:
"Specify if we want to include the commit author's name when using conventional-commits with changelog",
group: 'Version Command Options:',
type: 'boolean',
},
'changelog-version-message': {
describe:
'Add a custom message as a prefix to each new version in your "changelog.md" which is located in the root of your project. This option only works when using --conventional-commits.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,76 @@ describe('conventional-commits', () => {
`);
});

it('supports custom tagPrefix in fixed mode and include commit author', async () => {
const cwd = await initFixture('fixed');

await gitTag(cwd, 'dragons-are-awesome1.0.0');

const [pkg1] = await Project.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 [leafChangelog, rootChangelog] = await Promise.all([
updateChangelog(pkg1, 'fixed', {
changelogIncludeCommitAuthor: true,
tagPrefix: 'dragons-are-awesome',
}),
updateChangelog({ location: cwd } as Package, 'root', {
changelogIncludeCommitAuthor: true,
tagPrefix: 'dragons-are-awesome',
version: '1.0.1',
}),
]);

expect(leafChangelog.newEntry.trimRight()).toMatchInlineSnapshot(`
## [1.0.1](/compare/dragons-are-awesome1.0.0...dragons-are-awesome1.0.1) (YYYY-MM-DD)


### Bug Fixes

* A second commit for our CHANGELOG ([SHA](https://github.com/lerna/conventional-commits-fixed/commit/GIT_HEAD)) (@Tester-McPerson)
`);
expect(rootChangelog.newEntry.trimRight()).toMatchInlineSnapshot(`
## [1.0.1](/compare/dragons-are-awesome1.0.0...dragons-are-awesome1.0.1) (YYYY-MM-DD)


### Bug Fixes

* A second commit for our CHANGELOG ([SHA](https://github.com/lerna/conventional-commits-fixed/commit/GIT_HEAD)) (@Tester-McPerson)
`);

await gitAdd(cwd, pkg1.manifestLocation);
await gitCommit(cwd, 'chore(release): Publish v1.0.1');
await gitTag(cwd, 'dragons-are-awesome1.0.1');

// subsequent change
await pkg1.set('changed', 2).serialize();
await gitAdd(cwd, pkg1.manifestLocation);
await gitCommit(cwd, 'fix: A third commit for our CHANGELOG');

const lastRootChangelog = await updateChangelog({ location: cwd } as Package, 'root', {
changelogIncludeCommitAuthor: true,
tagPrefix: 'dragons-are-awesome',
version: '1.0.2',
});

// second commit should not show up again
expect(lastRootChangelog.newEntry.trimRight()).toMatchInlineSnapshot(`
## [1.0.2](/compare/dragons-are-awesome1.0.1...dragons-are-awesome1.0.2) (YYYY-MM-DD)


### Bug Fixes

* A third commit for our CHANGELOG ([SHA](https://github.com/lerna/conventional-commits-fixed/commit/GIT_HEAD)) (@Tester-McPerson)
`);
});

it('appends version bump message if no commits have been recorded', async () => {
const cwd = await initFixture('fixed');

Expand Down Expand Up @@ -585,5 +655,54 @@ describe('conventional-commits', () => {
* **thing:** added ([SHA](https://github.com/lerna/conventional-commits-independent/commit/GIT_HEAD))
`);
});

it('updates independent changelogs and include commit author', async () => {
const cwd = await initFixture('independent');

await gitTag(cwd, 'package-1@1.0.0');
await gitTag(cwd, 'package-2@1.0.0');

const [pkg1, pkg2] = await Project.getPackages(cwd);

// make a change in package-1 and package-2
await pkg1.set('changed', 1).serialize();
await pkg2.set('changed', 2).serialize();

await gitAdd(cwd, pkg1.manifestLocation);
await gitCommit(cwd, 'fix(stuff): changed');

await gitAdd(cwd, pkg2.manifestLocation);
await gitCommit(cwd, 'feat(thing): added');

// update versions
await pkg1.set('version', '1.0.1').serialize();
await pkg2.set('version', '1.1.0').serialize();

const opts = {
changelogPreset: 'conventional-changelog-angular',
changelogIncludeCommitAuthor: true,
};
const [changelogOne, changelogTwo] = await Promise.all([
updateChangelog(pkg1, 'independent', opts),
updateChangelog(pkg2, 'independent', opts),
]);

expect(changelogOne.newEntry.trimRight()).toMatchInlineSnapshot(`
## [1.0.1](/compare/package-1@1.0.0...package-1@1.0.1) (YYYY-MM-DD)


### Bug Fixes

* **stuff:** changed ([SHA](https://github.com/lerna/conventional-commits-independent/commit/GIT_HEAD)) (@Tester-McPerson)
`);
expect(changelogTwo.newEntry.trimRight()).toMatchInlineSnapshot(`
# [1.1.0](/compare/package-2@1.0.0...package-2@1.1.0) (YYYY-MM-DD)


### Features

* **thing:** added ([SHA](https://github.com/lerna/conventional-commits-independent/commit/GIT_HEAD)) (@Tester-McPerson)
`);
});
});
});
48 changes: 46 additions & 2 deletions packages/core/src/conventional-commits/update-changelog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export async function updateChangelog(
rootPath,
tagPrefix = 'v',
version = undefined,
changelogIncludeCommitAuthor = false,
changelogHeaderMessage = '',
changelogVersionMessage = '',
} = updateOptions;
Expand All @@ -47,6 +48,15 @@ export async function updateChangelog(
// NOTE: must pass as positional argument due to weird bug in merge-config
const gitRawCommitsOpts = Object.assign({}, options.config.gitRawCommitsOpts);

// when including commit author's name, we need to change the conventional commit format
// available formats can be found at Git's url: https://git-scm.com/docs/git-log#_pretty_formats
// we will later extract a defined token from the string, of ">>author=%an<<",
// and reformat the string to get a commit string that would add (@authorName) to the end of the commit string, ie:
// **deps:** update all non-major dependencies ([ed1db35](https://github.com/ghiscoding/lerna-lite/commit/ed1db35)) (@Renovate-Bot)
if (changelogIncludeCommitAuthor) {
gitRawCommitsOpts.format = '%B%n-hash-%n%H>>author=%an<<';
}

if (type === 'root') {
context.version = version;

Expand Down Expand Up @@ -76,9 +86,13 @@ export async function updateChangelog(
const changelogStream = conventionalChangelogCore(options, context, gitRawCommitsOpts);

return Promise.all([
(getStream as any)(changelogStream).then(makeBumpOnlyFilter(pkg)),
// prettier-ignore
getStream(changelogStream).then(makeBumpOnlyFilter(pkg)),
readExistingChangelog(pkg),
]).then(([newEntry, [changelogFileLoc, changelogContents]]) => {
]).then(([inputEntry, [changelogFileLoc, changelogContents]]) => {
// are we including commit author's name in changelog?
const newEntry = changelogIncludeCommitAuthor ? parseChangelogCommitAuthorName(inputEntry) : inputEntry;

log.silly(type, 'writing new entry: %j', newEntry);

const changelogVersion = type === 'root' ? changelogVersionMessage : '';
Expand All @@ -102,3 +116,33 @@ export async function updateChangelog(
});
});
}

/**
* From an input entry string that most often, not always, include commit author's name within defined tokens ">>author=AUTHOR_NAME<<"
* We will want to extract the author's name from the commit url and recreate the commit url string and add its author to the end of the string.
* You might be wondering, WHY is the commit author part of the commit url?
* Mainly because it seems that adding a `format` to the `conventional-changelog-core` of `gitRawCommitsOpts`
* will always include it as part of the final commit url because of this line where it parses the template and always seems to include whatever we add into the commit url
* https://github.com/conventional-changelog/conventional-changelog/blob/master/packages/git-raw-commits/index.js#L27
*
* We will transform a string that looks like this:
* "deps: update all non-major dependencies ([ed1db35](https://github.com/ghiscoding/lerna-lite/commit/ed1db35>>author=Renovate Bot<<))"
* then extract the commit author's name and transform it into a new string that will look like below
* "deps: update all non-major dependencies ([ed1db35](https://github.com/ghiscoding/lerna-lite/commit/ed1db35)) (@Renovate-Bot)"
* @param changelogEntry - changelog entry of a version being released which can contain multiple line entries
* @returns
*/
function parseChangelogCommitAuthorName(changelogEntry: string) {
// to transform the string into what we want, we need to move the substring outside of the url and remove extra search tokens
// from this:
// "...ed1db35>>author=Renovate Bot<<))"
// into this:
// "...ed1db35)) (@Renovate-Bot)"
return changelogEntry.replace(
/(.*)(>>author=)(.*)(<<)(.*)/g,
(_: string, lineStart: string, _tokenStart?: string, author?: string, _tokenEnd?: string, lineEnd?: string) => {
// rebuild the commit string, we'll also replace any whitespaces to hypen in author's name to make it a valid "@" user ref
return `${lineStart}${lineEnd || ''} (@${author?.replace(/\s/g, '-') ?? ''})`;
}
);
}
3 changes: 3 additions & 0 deletions packages/core/src/models/command-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ export interface VersionCommandOption {
/** Add a custom message at the top of your "changelog.md" which is located in the root of your project. This option only works when using --conventional-commits. */
changelogHeaderMessage?: string;

/** Specify if we want to include the commit author's name when using conventional-commits with changelog */
changelogIncludeCommitAuthor?: boolean;

/** Add a custom message as a prefix to each new version in your "changelog.md" which is located in the root of your project. This option only works when using --conventional-commits. */
changelogVersionMessage?: string;

Expand Down
1 change: 1 addition & 0 deletions packages/core/src/models/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export interface UpdateChangelogOption {
changelogHeaderMessage?: string;
changelogVersionMessage?: string;
changelogPreset?: string;
changelogIncludeCommitAuthor?: boolean;
rootPath?: string;
tagPrefix?: string;
version?: string;
Expand Down
17 changes: 15 additions & 2 deletions packages/version/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ Running `lerna version --conventional-commits` without the above flags will rele
- [`--conventional-commits`](#--conventional-commits)
- [`--conventional-graduate`](#--conventional-graduate)
- [`--conventional-prerelease`](#--conventional-prerelease)
- [`--changelog-include-commit-author`](#--changelog-include-commit-author) (new)
- [`--changelog-header-message <msg>`](#--changelog-header-message-msg) (new)
- [`--changelog-version-message <msg>`](#--changelog-version-message-msg) (new)
- [`--create-release <type>`](#--create-release-type)
Expand Down Expand Up @@ -229,20 +230,32 @@ lerna version --conventional-commits --conventional-prerelease

When run with this flag, `lerna version` will release with prerelease versions the specified packages (comma-separated) or all packages using `*`. Releases all unreleased changes as pre(patch/minor/major/release) by prefixing the version recommendation from `conventional-commits` with `pre`, eg. if present changes include a feature commit, the recommended bump will be `minor`, so this flag will result in a `preminor` release. If changes are present for packages that are not specified (if specifying packages), or for packages that are already in prerelease, those packages will be versioned as they normally would using `--conventional-commits`.

### `--changelog-include-commit-author`
Specify if we want to include the commit author's name, at the end of each commit entry, when using `--conventional-commits` with changelogs.

```sh
lerna version --conventional-commits --changelog-include-commit-author
```

See below for a sample of a changelog entry with author (note the url was shorten up for simplicity)
```sh
* **deps:** update dependency git-url-parse to v12 ([978bf36](https://github.com/ghiscoding/lerna-lite/commit/978bf36)) (@Renovate-Bot)
```

### `--changelog-header-message <msg>`

Add a custom message at the top of your "changelog.md" which is located in the root of your project. This option only works when using `--conventional-commits` and will only impact your project root "changelog.md".

```sh
lerna version --changelog-header-message "My Custom Header Message"
lerna version --conventional-commits --changelog-header-message "My Custom Header Message"
```

### `--changelog-version-message <msg>`

Add a custom message as a prefix to your new version in your "changelog.md" which is located in the root of your project. This option only works when using `--conventional-commits` and will only impact your project root "changelog.md".

```sh
lerna version --changelog-version-message "My Great New Version Message"
lerna version --conventional-commits --changelog-version-message "My Great New Version Message"
```

### `--create-release <type>`
Expand Down
2 changes: 2 additions & 0 deletions packages/version/src/version-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,7 @@ export class VersionCommand extends Command<VersionCommandOption> {
changelogPreset,
rootPath,
tagPrefix: this.tagPrefix,
changelogIncludeCommitAuthor: this.options.changelogIncludeCommitAuthor,
changelogHeaderMessage: this.options.changelogHeaderMessage,
changelogVersionMessage: this.options.changelogVersionMessage,
}).then(({ logPath, newEntry }) => {
Expand Down Expand Up @@ -683,6 +684,7 @@ export class VersionCommand extends Command<VersionCommandOption> {
rootPath,
tagPrefix: this.tagPrefix,
version: this.globalVersion,
changelogIncludeCommitAuthor: this.options.changelogIncludeCommitAuthor,
changelogHeaderMessage: this.options.changelogHeaderMessage,
changelogVersionMessage: this.options.changelogVersionMessage,
}).then(({ logPath, newEntry }) => {
Expand Down
2 changes: 2 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.