Skip to content

Commit

Permalink
feat(version): add --generate-release-notes for GitHub release (#798)
Browse files Browse the repository at this point in the history
* feat(version): add `--generate-release-notes` for GitHub release
  • Loading branch information
ghiscoding authored Jan 6, 2024
1 parent 0e2c04b commit 96d4a61
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 7 deletions.
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"version": {
"conventionalCommits": true,
"createRelease": "github",
"changelogIncludeCommitsClientLogin": " - by @%l",
"generateReleaseNotes": true,
"changelogHeaderMessage": "## Automate your Workspace Versioning, Publishing & Changelogs with [Lerna-Lite](https://github.com/lerna-lite/lerna-lite) 📦🚀",
"message": "chore(release): publish new version %v"
}
Expand Down
4 changes: 4 additions & 0 deletions packages/cli/schemas/lerna-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1314,6 +1314,10 @@
"type": "string",
"description": "Create a GitHub Discussion from the new release (note that createRelease must be enabled for this to work)."
},
"generateReleaseNotes": {
"type": "boolean",
"description": "Provides an alternative to create a GitHub release by letting GitHub automatically generate the name and body for the new release."
},
"message": {
"type": "string",
"description": "For `lerna version`, the custom commit message to use when creating the version commit."
Expand Down
5 changes: 5 additions & 0 deletions packages/cli/src/cli-commands/cli-version-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ export default {
describe: 'Create a GitHub Discussion from the new release (note that createRelease must be enabled for this to work).',
type: 'string',
},
'generate-release-notes': {
describe:
'Provides an alternative to create a GitHub release by letting GitHub automatically generate the name and body for the new release.',
type: 'boolean',
},
'ignore-changes': {
describe: [
'Ignore changes in files matched by glob(s) when detecting changed packages.',
Expand Down
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 @@ -193,6 +193,9 @@ export interface VersionCommandOption {
/** Create a GitHub Discussion from the new release (note that createRelease must be enabled for this to work and it only works with GitHub at the moment). */
createReleaseDiscussion?: string;

/** Provides an alternative to create a GitHub release by letting GitHub automatically generate the name and body for the new release. */
generateReleaseNotes?: boolean;

/** Specify cross-dependency version numbers exactly rather than with a caret (^). */
exact?: boolean;

Expand Down
12 changes: 11 additions & 1 deletion packages/version/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ Running `lerna version --conventional-commits` without the above flags will rele
- [`--changelog-header-message <msg>`](#--changelog-header-message-msg)
- [`--create-release <type>`](#--create-release-type)
- [`--create-release-discussion <name>`](#--create-release-discussion-name)
- [`--generate-release-notes`](#--generate-release-notes)
- [`--skip-bump-only-releases`](#--skip-bump-only-releases)
- [`--describe-tag <pattern>`](#--describe-tag-pattern)
- [`--exact`](#--exact)
Expand Down Expand Up @@ -417,8 +418,17 @@ Create a discussion for this release, this will create both a Release and a Disc
lerna version --conventional-commits --create-release github --create-release-discussion announcement
```

> **Note** currently only available for GitHub Releases following this GitHub blog post [You can now link discussions to new releases](https://github.blog/changelog/2021-04-06-releases-support-comments-and-reactions-with-discussion-linking/)
> **Note** this option is currently only available for GitHub Releases following this GitHub blog post [You can now link discussions to new releases](https://github.blog/changelog/2021-04-06-releases-support-comments-and-reactions-with-discussion-linking/)
### `--generate-release-notes`

When run with this flag, `lerna version` will create an official GitHub release by automatically generating the name and body for the new release.

```sh
lerna version --conventional-commits --create-release github --generate-release-notes
```

> **Note** this option is currently only available for GitHub Releases, more info can be found in this GitHub documentation page [Automatically generated release notes](https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes)
### `--skip-bump-only-releases`

Expand Down
32 changes: 32 additions & 0 deletions packages/version/src/__tests__/version-create-release.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ describe.each([
expect(client.releases.size).toBe(0);
});

it('throws an error if --generate-release-notes is provided without defining --create-release', async () => {
const cwd = await initFixture('independent');
const command = lernaVersion(cwd)('--generate-release-notes');

await expect(command).rejects.toThrow('To generate release notes, you must define --create-release');

expect(client.releases.size).toBe(0);
});

it('throws an error if --create-release-discussion is provided without defining --create-release', async () => {
const cwd = await initFixture('independent');
const command = lernaVersion(cwd)('--create-release-discussion', 'some-discussion');
Expand Down Expand Up @@ -377,6 +386,29 @@ it('should create a github release discussion when enabled', async () => {
});
});

it('should create a github release and generate release notes', async () => {
process.env.GH_TOKEN = 'TOKEN';
const createReleaseMock = vi.fn(() => Promise.resolve(true));
(createReleaseClient as Mock).mockImplementation(() => Promise.resolve({ repos: { createRelease: createReleaseMock } }));

const cwd = await initFixture('normal');

(recommendVersion as Mock).mockResolvedValueOnce('1.1.0');

const command = new VersionCommand(createArgv(cwd, '--create-release', 'github', '--conventional-commits', '--generate-release-notes'));
await command;
await command.execute();

expect(createReleaseMock).toHaveBeenCalledWith({
owner: 'lerna',
repo: 'lerna',
tag_name: 'v1.1.0',
draft: false,
generate_release_notes: true,
prerelease: false,
});
});

it('should log an error when createRelease throws', async () => {
process.env.GITHUB_TOKEN = 'TOKEN';
(createReleaseClient as Mock).mockImplementation(() => Promise.resolve({ repos: { createRelease: vi.fn(() => Promise.reject('some error')) } }));
Expand Down
17 changes: 14 additions & 3 deletions packages/version/src/lib/create-release.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ export async function createReleaseClient(type: 'github' | 'gitlab'): Promise<Gi

/** Create a release on a remote client (github or gitlab) */
export function createRelease(
{ client, releaseDiscussion }: { client: GitCreateReleaseClientOutput; releaseDiscussion?: string },
{
client,
generateReleaseNotes,
releaseDiscussion,
}: { client: GitCreateReleaseClientOutput; generateReleaseNotes?: boolean; releaseDiscussion?: string },
{ tags, releaseNotes }: ReleaseCommandProps,
{ gitRemote, execOpts, skipBumpOnlyReleases }: ReleaseOptions,
dryRun = false
Expand Down Expand Up @@ -61,8 +65,6 @@ export function createRelease(
owner: repo.owner,
repo: repo.name,
tag_name: tag,
name: tag,
body: notes,
draft: false,
prerelease: prereleaseParts.length > 0,
};
Expand All @@ -72,6 +74,15 @@ export function createRelease(
releaseOptions.discussion_category_name = releaseDiscussion;
}

// whether to automatically generate the `name` and `body` for this release
// else we'll add the notes as the release description body & tag as the name
if (generateReleaseNotes) {
releaseOptions.generate_release_notes = generateReleaseNotes;
} else {
releaseOptions.name = tag;
releaseOptions.body = notes;
}

if (dryRun) {
log.info(chalk.bold.magenta('[dry-run] >'), `Create Release with repo options: `, JSON.stringify(releaseOptions));
return Promise.resolve();
Expand Down
3 changes: 2 additions & 1 deletion packages/version/src/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,11 @@ export interface GitClientReleaseOption {
owner: string;
repo: string;
tag_name: string;
name: string;
name?: string;
body?: string;
draft?: boolean;
prerelease?: boolean;
generate_release_notes?: boolean;
discussion_category_name?: string;
}

Expand Down
10 changes: 9 additions & 1 deletion packages/version/src/version-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ export class VersionCommand extends Command<VersionCommandOption> {
throw new ValidationError('ERELEASE', 'To create a release, you must enable --conventional-commits');
}

if (this.options.generateReleaseNotes && !this.options.createRelease) {
throw new ValidationError('ERELEASE', 'To generate release notes, you must define --create-release');
}

if (this.options.createReleaseDiscussion && !this.options.createRelease) {
throw new ValidationError('ERELEASE', 'To create a release discussion, you must define --create-release');
}
Expand Down Expand Up @@ -376,7 +380,11 @@ export class VersionCommand extends Command<VersionCommandOption> {
this.logger.info('execute', 'Creating releases...');
try {
await createRelease(
{ client: this.releaseClient, releaseDiscussion: this.options.createReleaseDiscussion },
{
client: this.releaseClient,
generateReleaseNotes: this.options.generateReleaseNotes,
releaseDiscussion: this.options.createReleaseDiscussion,
},
{ tags: this.tags, releaseNotes: this.releaseNotes },
{
gitRemote: this.options.gitRemote,
Expand Down

0 comments on commit 96d4a61

Please sign in to comment.