Skip to content

Commit c5a1264

Browse files
fix: allow category extraction when scope is used (#240)
This PR changes the category extraction to use a RegExp to matches [**Conventional Commits** that start with `feat:` or `fix:` (optionally with a scope like `feat(scope):`)](https://www.conventionalcommits.org/en/v1.0.0/#:~:text=A%20scope%20may%20be%20provided%20to%20a%20commit%E2%80%99s%20type%2C%20to%20provide%20additional%20contextual%20information%20and%20is%20contained%20within%20parenthesis%2C%20e.g.%2C%20feat(parser)%3A%20add%20ability%20to%20parse%20arrays.). - adds tests for getCategory to make sure all previous behaviours are preserved and new one works. - exports getCategory to make it testable. - updates getCategory to use regex to extract known category even when scope is present. ### Regex breakdown - `^` – Start of the string - `(feat|fix)` – Must start with either `feat` or `fix` - `(?:\([^)]*\))?` – Optionally match a scope in parentheses like `(bridge)` or `(ramps)` - `\s*:\s*` – Requires a colon `:` (with optional spaces before/after) - `/u` – Unicode flag (as GitHub allows PR titles to contain unicode) See https://consensys.slack.com/archives/C08N7NQRBPU/p1745578034343929 --------- Co-authored-by: Jongsun Suh <[email protected]>
1 parent 308220b commit c5a1264

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

src/update-changelog.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import { ChangeCategory } from './constants';
12
import * as ChangeLogUtils from './get-new-changes';
23
import * as ChangeLogManager from './update-changelog';
4+
import { getCategory } from './update-changelog';
35

46
const emptyChangelog = `# Changelog
57
All notable changes to this project will be documented in this file.
@@ -59,3 +61,47 @@ describe('updateChangelog', () => {
5961
expect(result).not.toContain('### Added');
6062
});
6163
});
64+
65+
describe('getCategory', () => {
66+
it('categorizes feat: prefix as Added', () => {
67+
const description = 'feat: add new feature';
68+
expect(getCategory(description)).toBe(ChangeCategory.Added);
69+
});
70+
71+
it('categorizes fix: prefix as Fixed', () => {
72+
const description = 'fix: resolve bug issue';
73+
expect(getCategory(description)).toBe(ChangeCategory.Fixed);
74+
});
75+
76+
it('finds category even if title has spaces', () => {
77+
const description = 'feat : add new feature';
78+
expect(getCategory(description)).toBe(ChangeCategory.Added);
79+
});
80+
81+
it('returns Uncategorized for unknown prefix', () => {
82+
const description = 'foo: update documentation';
83+
expect(getCategory(description)).toBe(ChangeCategory.Uncategorized);
84+
});
85+
86+
it('returns Uncategorized for title without colon', () => {
87+
const description = 'just a regular commit message';
88+
expect(getCategory(description)).toBe(ChangeCategory.Uncategorized);
89+
});
90+
91+
it('returns Uncategorized for empty title', () => {
92+
const description = '';
93+
expect(getCategory(description)).toBe(ChangeCategory.Uncategorized);
94+
});
95+
96+
it('returns category in title with multiple colons', () => {
97+
const description = 'feat: add new feature: with details';
98+
expect(getCategory(description)).toBe(ChangeCategory.Added);
99+
});
100+
101+
// according to Conventional Commit practice, category can be followed by a scope
102+
// see https://www.conventionalcommits.org/en/v1.0.0/
103+
it('returns category with category scope', () => {
104+
const description = 'feat(bridge): add new feature for the bridge scope';
105+
expect(getCategory(description)).toBe(ChangeCategory.Added);
106+
});
107+
});

src/update-changelog.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,12 @@ async function runCommand(command: string, args: string[]): Promise<string[]> {
213213
* @param description - The commit message description.
214214
* @returns The category of the change.
215215
*/
216-
function getCategory(description: string): ChangeCategory {
217-
// Check if description contains a colon
218-
if (description.includes(':')) {
219-
const [prefix] = description.split(':').map((part) => part.trim());
216+
export function getCategory(description: string): ChangeCategory {
217+
const conventionalCommitPattern = /^(feat|fix)(?:\([^)]+\))?\s*:\s*/u;
218+
const match = description.match(conventionalCommitPattern);
219+
220+
if (match) {
221+
const prefix = match.length > 1 ? match[1] : undefined;
220222
switch (prefix) {
221223
case ConventionalCommitType.Feat:
222224
return ChangeCategory.Added;

0 commit comments

Comments
 (0)