Skip to content

Commit

Permalink
fix(release): changelog renderer should prefer breaking change explan…
Browse files Browse the repository at this point in the history
…ation text (#20798)
  • Loading branch information
JamesHenry authored and jaysoo committed Dec 18, 2023
1 parent a9a8d5b commit 4399355
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 5 deletions.
6 changes: 5 additions & 1 deletion e2e/release/src/release.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ describe('nx release', () => {
dependencyRelationshipLogMatch.length !== 1
) {
// From JamesHenry: explicit error to assist troubleshooting NXC-143
// Update: after seeing this error in the wild, it somehow seems to be not finding the dependency relationship sometimes
throw new Error(
`
Error: Expected to find exactly one dependency relationship log line.
Expand All @@ -128,7 +129,10 @@ If you are seeing this message then you have been impacted by some currently und
Please report the full nx release version command output below to the Nx team:
${versionOutput}`
${{
versionOutput,
pkg2Contents: readFile(`${pkg2}/package.json`),
}}`
);
}
expect(dependencyRelationshipLogMatch.length).toEqual(1);
Expand Down
121 changes: 121 additions & 0 deletions packages/nx/changelog-renderer/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -539,4 +539,125 @@ describe('defaultChangelogRenderer()', () => {
expect(markdown).toMatchInlineSnapshot(`""`);
});
});

describe('breaking changes', () => {
it('should work for breaking changes with just the ! and no explanation', async () => {
const breakingChangeCommitWithExplanation: GitCommit = {
// ! after the type, no BREAKING CHANGE: in the body
message: 'feat(WebSocketSubject)!: no longer extends `Subject`.',
shortHash: '54f2f6ed1',
author: {
name: 'James Henry',
email: 'jh@example.com',
},
body:
'M\tpackages/rxjs/src/internal/observable/dom/WebSocketSubject.ts\n' +
'"',
authors: [
{
name: 'James Henry',
email: 'jh@example.com',
},
],
description: 'no longer extends `Subject`.',
type: 'feat',
scope: 'WebSocketSubject',
references: [{ value: '54f2f6ed1', type: 'hash' }],
isBreaking: true,
revertedHashes: [],
affectedFiles: [
'packages/rxjs/src/internal/observable/dom/WebSocketSubject.ts',
],
};

const markdown = await defaultChangelogRenderer({
projectGraph,
commits: [breakingChangeCommitWithExplanation],
releaseVersion: 'v1.1.0',
project: null,
entryWhenNoChanges: false,
changelogRenderOptions: {
includeAuthors: true,
},
});

expect(markdown).toMatchInlineSnapshot(`
"## v1.1.0
### 🚀 Features
- ⚠️ **WebSocketSubject:** no longer extends \`Subject\`.
#### ⚠️ Breaking Changes
- ⚠️ **WebSocketSubject:** no longer extends \`Subject\`.
### ❤️ Thank You
- James Henry"
`);
});

it('should extract the explanation of a breaking change and render it preferentially', async () => {
const breakingChangeCommitWithExplanation: GitCommit = {
// No ! after the type, but BREAKING CHANGE: in the body
message: 'feat(WebSocketSubject): no longer extends `Subject`.',
shortHash: '54f2f6ed1',
author: {
name: 'James Henry',
email: 'jh@example.com',
},
body:
'BREAKING CHANGE: `WebSocketSubject` is no longer `instanceof Subject`. Check for `instanceof WebSocketSubject` instead.\n' +
'"\n' +
'\n' +
'M\tpackages/rxjs/src/internal/observable/dom/WebSocketSubject.ts\n' +
'"',
authors: [
{
name: 'James Henry',
email: 'jh@example.com',
},
],
description: 'no longer extends `Subject`.',
type: 'feat',
scope: 'WebSocketSubject',
references: [{ value: '54f2f6ed1', type: 'hash' }],
isBreaking: true,
revertedHashes: [],
affectedFiles: [
'packages/rxjs/src/internal/observable/dom/WebSocketSubject.ts',
],
};

const markdown = await defaultChangelogRenderer({
projectGraph,
commits: [breakingChangeCommitWithExplanation],
releaseVersion: 'v1.1.0',
project: null,
entryWhenNoChanges: false,
changelogRenderOptions: {
includeAuthors: true,
},
});

expect(markdown).toMatchInlineSnapshot(`
"## v1.1.0
### 🚀 Features
- ⚠️ **WebSocketSubject:** no longer extends \`Subject\`.
#### ⚠️ Breaking Changes
- **WebSocketSubject:** \`WebSocketSubject\` is no longer \`instanceof Subject\`. Check for \`instanceof WebSocketSubject\` instead.
### ❤️ Thank You
- James Henry"
`);
});
});
});
50 changes: 47 additions & 3 deletions packages/nx/changelog-renderer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,16 @@ const defaultChangelogRenderer: ChangelogRenderer = async ({
const line = formatCommit(commit, repoSlug);
markdownLines.push(line);
if (commit.isBreaking) {
breakingChanges.push(line);
const breakingChangeExplanation = extractBreakingChangeExplanation(
commit.body
);
breakingChanges.push(
breakingChangeExplanation
? `- ${
commit.scope ? `**${commit.scope.trim()}:** ` : ''
}${breakingChangeExplanation}`
: line
);
}
}
}
Expand Down Expand Up @@ -188,7 +197,16 @@ const defaultChangelogRenderer: ChangelogRenderer = async ({
const line = formatCommit(commit, repoSlug);
markdownLines.push(line + '\n');
if (commit.isBreaking) {
breakingChanges.push(line);
const breakingChangeExplanation = extractBreakingChangeExplanation(
commit.body
);
breakingChanges.push(
breakingChangeExplanation
? `- ${
commit.scope ? `**${commit.scope.trim()}:** ` : ''
}${breakingChangeExplanation}`
: line
);
}
}
}
Expand Down Expand Up @@ -294,11 +312,37 @@ function groupBy(items: any[], key: string) {
function formatCommit(commit: GitCommit, repoSlug?: RepoSlug): string {
let commitLine =
'- ' +
(commit.scope ? `**${commit.scope.trim()}:** ` : '') +
(commit.isBreaking ? '⚠️ ' : '') +
(commit.scope ? `**${commit.scope.trim()}:** ` : '') +
commit.description;
if (repoSlug) {
commitLine += formatReferences(commit.references, repoSlug);
}
return commitLine;
}

/**
* It is common to add further information about a breaking change in the commit body,
* and it is naturally that information that should be included in the BREAKING CHANGES
* section of changelog, rather than repeating the commit title/description.
*/
function extractBreakingChangeExplanation(message: string): string | null {
const breakingChangeIdentifier = 'BREAKING CHANGE:';
const startIndex = message.indexOf(breakingChangeIdentifier);

if (startIndex === -1) {
// "BREAKING CHANGE:" not found in the message
return null;
}

const startOfBreakingChange = startIndex + breakingChangeIdentifier.length;
const endOfBreakingChange = message.indexOf('\n', startOfBreakingChange);

if (endOfBreakingChange === -1) {
// No newline character found, extract till the end of the message
return message.substring(startOfBreakingChange).trim();
}

// Extract and return the breaking change message
return message.substring(startOfBreakingChange, endOfBreakingChange).trim();
}
3 changes: 2 additions & 1 deletion packages/nx/src/command-line/release/utils/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,8 @@ export function parseGitCommit(commit: RawGitCommit): GitCommit | null {

const scope = match.groups.scope || '';

const isBreaking = Boolean(match.groups.breaking);
const isBreaking =
Boolean(match.groups.breaking) || commit.body.includes('BREAKING CHANGE:');
let description = match.groups.description;

// Extract references from message
Expand Down

0 comments on commit 4399355

Please sign in to comment.