Skip to content

Commit

Permalink
feat(release): support Revert commits in changelog renderer (#20663)
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesHenry authored and jaysoo committed Dec 18, 2023
1 parent 93ad8a9 commit a9a8d5b
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 2 deletions.
161 changes: 161 additions & 0 deletions packages/nx/changelog-renderer/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ describe('defaultChangelogRenderer()', () => {
},
],
isBreaking: false,
revertedHashes: [],
affectedFiles: [
'packages/pkg-a/src/index.ts',
'packages/pkg-b/src/index.ts',
Expand Down Expand Up @@ -82,6 +83,7 @@ describe('defaultChangelogRenderer()', () => {
},
],
isBreaking: false,
revertedHashes: [],
affectedFiles: ['packages/pkg-b/src/index.ts'],
},
{
Expand All @@ -108,6 +110,7 @@ describe('defaultChangelogRenderer()', () => {
},
],
isBreaking: false,
revertedHashes: [],
affectedFiles: ['packages/pkg-a/src/index.ts'],
},
{
Expand All @@ -134,6 +137,7 @@ describe('defaultChangelogRenderer()', () => {
},
],
isBreaking: false,
revertedHashes: [],
affectedFiles: ['packages/pkg-b/src/index.ts'],
},
{
Expand All @@ -160,6 +164,7 @@ describe('defaultChangelogRenderer()', () => {
},
],
isBreaking: false,
revertedHashes: [],
affectedFiles: ['packages/pkg-a/src/index.ts'],
},
];
Expand Down Expand Up @@ -378,4 +383,160 @@ describe('defaultChangelogRenderer()', () => {
).toMatchInlineSnapshot(`""`);
});
});

describe('revert commits', () => {
it('should generate a Revert section for the changelog if the reverted commit is not part of the same release', async () => {
const commitsWithOnlyRevert: GitCommit[] = [
{
message:
'Revert "fix(release): do not update dependents when they already use "*" (#20607)"',
shortHash: '6528e88aa',
author: {
name: 'James Henry',
email: 'jh@example.com',
},
body: 'This reverts commit 6d68236d467812aba4557a2bc7f667157de80fdb.\n"\n\nM\tpackages/js/src/generators/release-version/release-version.spec.ts\nM\tpackages/js/src/generators/release-version/release-version.ts\n',
authors: [
{
name: 'James Henry',
email: 'jh@example.com',
},
],
description:
'Revert "fix(release): do not update dependents when they already use "*" (#20607)"',
type: 'revert',
scope: 'release',
references: [
{
type: 'pull-request',
value: '#20607',
},
{
value: '6528e88aa',
type: 'hash',
},
],
isBreaking: false,
revertedHashes: ['6d68236d467812aba4557a2bc7f667157de80fdb'],
affectedFiles: [
'packages/js/src/generators/release-version/release-version.spec.ts',
'packages/js/src/generators/release-version/release-version.ts',
],
},
];

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

expect(markdown).toMatchInlineSnapshot(`
"## v1.1.0
### ⏪ Revert
- **release:** Revert "fix(release): do not update dependents when they already use "*" (#20607)"
### ❤️ Thank You
- James Henry"
`);
});

it('should strip both the original commit and its revert if they are both included in the current range of commits', async () => {
const commitsWithRevertAndOriginal: GitCommit[] = [
{
message:
'Revert "fix(release): do not update dependents when they already use "*" (#20607)"',
shortHash: '6528e88aa',
author: {
name: 'James Henry',
email: 'jh@example.com',
},
body: 'This reverts commit 6d68236d467812aba4557a2bc7f667157de80fdb.\n"\n\nM\tpackages/js/src/generators/release-version/release-version.spec.ts\nM\tpackages/js/src/generators/release-version/release-version.ts\n',
authors: [
{
name: 'James Henry',
email: 'jh@example.com',
},
],
description:
'Revert "fix(release): do not update dependents when they already use "*" (#20607)"',
type: 'revert',
scope: 'release',
references: [
{
type: 'pull-request',
value: '#20607',
},
{
value: '6528e88aa',
type: 'hash',
},
],
isBreaking: false,
revertedHashes: ['6d68236d467812aba4557a2bc7f667157de80fdb'],
affectedFiles: [
'packages/js/src/generators/release-version/release-version.spec.ts',
'packages/js/src/generators/release-version/release-version.ts',
],
},
{
message:
'fix(release): do not update dependents when they already use "*" (#20607)',
shortHash: '6d68236d4',
author: {
name: 'James Henry',
email: 'jh@example.com',
},
body: '"\n\nM\tpackages/js/src/generators/release-version/release-version.spec.ts\nM\tpackages/js/src/generators/release-version/release-version.ts\n',
authors: [
{
name: 'James Henry',
email: 'jh@example.com',
},
],
description: 'do not update dependents when they already use "*"',
type: 'fix',
scope: 'release',
references: [
{
type: 'pull-request',
value: '#20607',
},
{
value: '6d68236d4',
type: 'hash',
},
],
isBreaking: false,
revertedHashes: [],
affectedFiles: [
'packages/js/src/generators/release-version/release-version.spec.ts',
'packages/js/src/generators/release-version/release-version.ts',
],
},
];

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

expect(markdown).toMatchInlineSnapshot(`""`);
});
});
});
16 changes: 16 additions & 0 deletions packages/nx/changelog-renderer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,24 @@ const defaultChangelogRenderer: ChangelogRenderer = async ({
test: { title: '✅ Tests' },
style: { title: '🎨 Styles' },
ci: { title: '🤖 CI' },
revert: { title: '⏪ Revert' },
};

// If the current range of commits contains both a commit and its revert, we strip them both from the final list
for (const commit of commits) {
if (commit.type === 'revert') {
for (const revertedHash of commit.revertedHashes) {
const revertedCommit = commits.find((c) =>
revertedHash.startsWith(c.shortHash)
);
if (revertedCommit) {
commits.splice(commits.indexOf(revertedCommit), 1);
commits.splice(commits.indexOf(commit), 1);
}
}
}
}

// workspace root level changelog
if (project === null) {
// No changes for the workspace
Expand Down
17 changes: 15 additions & 2 deletions packages/nx/src/command-line/release/utils/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface GitCommit extends RawGitCommit {
authors: GitCommitAuthor[];
isBreaking: boolean;
affectedFiles: string[];
revertedHashes: string[];
}

function escapeRegExp(string) {
Expand Down Expand Up @@ -274,15 +275,14 @@ const CoAuthoredByRegex = /co-authored-by:\s*(?<name>.+)(<(?<email>.+)>)/gim;
const PullRequestRE = /\([ a-z]*(#\d+)\s*\)/gm;
const IssueRE = /(#\d+)/gm;
const ChangedFileRegex = /(A|M|D|R\d*|C\d*)\t([^\t\n]*)\t?(.*)?/gm;
const RevertHashRE = /This reverts commit (?<hash>[\da-f]{40})./gm;

export function parseGitCommit(commit: RawGitCommit): GitCommit | null {
const match = commit.message.match(ConventionalCommitRegex);
if (!match) {
return null;
}

const type = match.groups.type;

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

const isBreaking = Boolean(match.groups.breaking);
Expand All @@ -303,6 +303,18 @@ export function parseGitCommit(commit: RawGitCommit): GitCommit | null {
// Remove references and normalize
description = description.replace(PullRequestRE, '').trim();

let type = match.groups.type;
// Extract any reverted hashes, if applicable
const revertedHashes = [];
const matchedHashes = commit.body.matchAll(RevertHashRE);
for (const matchedHash of matchedHashes) {
revertedHashes.push(matchedHash.groups.hash);
}
if (revertedHashes.length) {
type = 'revert';
description = commit.message;
}

// Find all authors
const authors: GitCommitAuthor[] = [commit.author];
for (const match of commit.body.matchAll(CoAuthoredByRegex)) {
Expand Down Expand Up @@ -333,6 +345,7 @@ export function parseGitCommit(commit: RawGitCommit): GitCommit | null {
scope,
references,
isBreaking,
revertedHashes,
affectedFiles,
};
}
Expand Down

0 comments on commit a9a8d5b

Please sign in to comment.