Skip to content

Commit 6922b19

Browse files
committed
feat: fixes for conventional-commit to use ADO links
1 parent 463e115 commit 6922b19

File tree

6 files changed

+1856
-693
lines changed

6 files changed

+1856
-693
lines changed

CHANGELOG.md

Lines changed: 433 additions & 485 deletions
Large diffs are not rendered by default.

api/cdk/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313
"prettier:check": "prettier . --check --ignore-path=./.eslintignore"
1414
},
1515
"devDependencies": {
16-
"@jest/globals": "^30.1.2",
16+
"@jest/globals": "30.1.2",
1717
"@types/jest": "29.5.14",
1818
"@types/node": "24.1.0",
1919
"@typescript-eslint/eslint-plugin": "7.18.0",
2020
"@typescript-eslint/parser": "7.18.0",
2121
"aws-cdk": "2.1033.0",
22-
"aws-cdk-lib": "^2.215.0",
23-
"esbuild": "^0.27.0",
22+
"aws-cdk-lib": "2.215.0",
23+
"esbuild": "0.27.0",
2424
"eslint": "8.57.1",
2525
"eslint-config-prettier": "9.1.2",
2626
"eslint-plugin-jest": "27.9.0",
@@ -34,6 +34,6 @@
3434
"typescript": "5.9.3"
3535
},
3636
"dependencies": {
37-
"constructs": "^10.0.0"
37+
"constructs": "10.0.0"
3838
}
3939
}

api/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
"zod": "4.3.5"
6262
},
6363
"devDependencies": {
64-
"@aws-sdk/client-cognito-identity-provider": "^3.777.0",
64+
"@aws-sdk/client-cognito-identity-provider": "3.777.0",
6565
"@businessnjgovnavigator/shared": "*",
6666
"@jest/types": "29.6.3",
6767
"@types/cors": "2.8.19",
@@ -76,11 +76,11 @@
7676
"@types/xml2js": "0.4.14",
7777
"@typescript-eslint/eslint-plugin": "7.18.0",
7878
"@typescript-eslint/parser": "7.18.0",
79-
"concurrently": "^9.2.1",
79+
"concurrently": "9.2.1",
8080
"cross-env": "10.1.0",
8181
"dependency-cruiser": "17.3.1",
8282
"dotenv": "17.2.3",
83-
"esbuild": "^0.27.0",
83+
"esbuild": "0.27.0",
8484
"eslint": "8.57.1",
8585
"eslint-config-prettier": "9.1.2",
8686
"eslint-plugin-jest": "27.9.0",

package.json

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
"babel-jest": "29.7.0",
7777
"body-parser": "1.20.3",
7878
"broken-link-checker": "0.7.8",
79-
"constructs": "^10.0.0",
79+
"constructs": "10.0.0",
8080
"cors": "2.8.5",
8181
"cypress-axe": "1.7.0",
8282
"dayjs": "1.11.19",
@@ -120,13 +120,13 @@
120120
"zod": "4.3.5"
121121
},
122122
"devDependencies": {
123-
"@aws-sdk/client-cognito-identity-provider": "^3.777.0",
123+
"@aws-sdk/client-cognito-identity-provider": "3.777.0",
124124
"@aws-sdk/types": "3.893.0",
125125
"@babel/core": "7.28.5",
126126
"@businessnjgovnavigator/shared": "*",
127127
"@cypress-audit/lighthouse": "1.4.2",
128128
"@cypress-audit/pa11y": "1.4.2",
129-
"@jest/globals": "^30.1.2",
129+
"@jest/globals": "30.1.2",
130130
"@jest/types": "29.6.3",
131131
"@mui/system": "5.18.0",
132132
"@next/bundle-analyzer": "16.1.1",
@@ -156,6 +156,8 @@
156156
"@testing-library/react": "16.3.0",
157157
"@testing-library/user-event": "14.6.1",
158158
"@types/broken-link-checker": "0.7.3",
159+
"@types/conventional-changelog-writer": "4.0.11",
160+
"@types/conventional-commits-parser": "5.0.2",
159161
"@types/cors": "2.8.19",
160162
"@types/cypress-dotenv": "2.0.3",
161163
"@types/dedent": "0.7.2",
@@ -171,7 +173,7 @@
171173
"@types/react-swipeable-views": "0.13.6",
172174
"@types/react-transition-group": "4.4.12",
173175
"@types/remove-markdown": "0.3.4",
174-
"@types/seedrandom": "^3.0.8",
176+
"@types/seedrandom": "3.0.8",
175177
"@types/simple-oauth2": "5.0.7",
176178
"@types/supertest": "6.0.3",
177179
"@types/testing-library__jest-dom": "5.14.9",
@@ -181,12 +183,12 @@
181183
"@typescript-eslint/parser": "7.18.0",
182184
"@vitest/coverage-v8": "2.1.8",
183185
"aws-cdk": "2.1033.0",
184-
"aws-cdk-lib": "^2.215.0",
186+
"aws-cdk-lib": "2.215.0",
185187
"babel-loader": "10.0.0",
186188
"cat": "0.2.0",
187189
"check-node-version": "4.2.1",
188190
"clean-webpack-plugin": "4.0.0",
189-
"concurrently": "^9.2.1",
191+
"concurrently": "9.2.1",
190192
"copy-webpack-plugin": "13.0.1",
191193
"cross-env": "10.1.0",
192194
"cspell": "9.3.2",
@@ -196,7 +198,7 @@
196198
"dependency-cruiser": "17.3.1",
197199
"dotenv": "17.2.3",
198200
"dynamodb-admin": "5.1.3",
199-
"esbuild": "^0.27.0",
201+
"esbuild": "0.27.0",
200202
"eslint": "8.57.1",
201203
"eslint-config-next": "15.5.6",
202204
"eslint-config-prettier": "9.1.2",
@@ -229,15 +231,15 @@
229231
"rimraf": "6.1.2",
230232
"sass": "1.94.2",
231233
"sass-loader": "16.0.6",
232-
"seedrandom": "^3.0.5",
234+
"seedrandom": "3.0.5",
233235
"semantic-release": "19.0.5",
234236
"storybook": "7.6.21",
235237
"style-loader": "4.0.0",
236238
"supertest": "7.2.2",
237239
"ts-jest": "29.4.5",
238240
"ts-loader": "9.5.4",
239241
"ts-node": "10.9.2",
240-
"ts-node-dev": "^2.0.0",
242+
"ts-node-dev": "2.0.0",
241243
"tsconfig-paths": "4.2.0",
242244
"tsx": "4.21.0",
243245
"typescript": "5.9.3",
@@ -276,38 +278,6 @@
276278
],
277279
"*.{css,md,scss,yml,yaml}": "prettier --write"
278280
},
279-
"release": {
280-
"baseBranch": "main",
281-
"plugins": [
282-
[
283-
"@semantic-release/commit-analyzer",
284-
{
285-
"preset": "angular",
286-
"parserOpts": {
287-
"noteKeywords": [
288-
"BREAKING CHANGE",
289-
"BREAKING CHANGES"
290-
]
291-
}
292-
}
293-
],
294-
[
295-
"@semantic-release/release-notes-generator",
296-
{
297-
"preset": "angular"
298-
}
299-
],
300-
"@semantic-release/npm",
301-
"@semantic-release/changelog",
302-
[
303-
"@semantic-release/github",
304-
{
305-
"successComment": false
306-
}
307-
],
308-
"@semantic-release/git"
309-
]
310-
},
311281
"packageManager": "yarn@4.9.4",
312282
"resolutions": {
313283
"trim@0.0.1": "1.0.1",

release.config.cjs

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// ---------------------------------------------------------------------------
2+
// JSDoc types
3+
// ---------------------------------------------------------------------------
4+
5+
/** @typedef {import('conventional-commits-parser').Commit} Commit */
6+
/** @typedef {import('conventional-changelog-writer').Context} WriterContext */
7+
8+
// ---------------------------------------------------------------------------
9+
// Constants
10+
// ---------------------------------------------------------------------------
11+
12+
const ADO_BASE = "https://dev.azure.com/NJInnovation/Business%20First%20Stop/_workitems/edit";
13+
14+
// ---------------------------------------------------------------------------
15+
// Pure helper functions
16+
// ---------------------------------------------------------------------------
17+
18+
/**
19+
* Returns true if the commit should be omitted from the changelog.
20+
* Commits with breaking-change notes are always kept; otherwise only
21+
* feat / fix / perf / revert are included.
22+
*
23+
* @param {Commit} commit
24+
* @returns {boolean}
25+
*/
26+
const shouldDiscard = (commit) => {
27+
if (commit.notes.length > 0) return false;
28+
const releasable = ["feat", "fix", "perf", "revert"];
29+
return !releasable.includes(commit.type) && !commit.revert;
30+
};
31+
32+
/**
33+
* Maps a conventional-commit type token to its changelog section label.
34+
* Preserves the original Angular preset's if-else order so that the
35+
* `revert || commit.revert` edge case is handled identically.
36+
*
37+
* @param {Commit} commit
38+
* @returns {string | null}
39+
*/
40+
const resolveType = (commit) => {
41+
if (commit.type === "feat") return "Features";
42+
if (commit.type === "fix") return "Bug Fixes";
43+
if (commit.type === "perf") return "Performance Improvements";
44+
if (commit.type === "revert" || commit.revert) return "Reverts";
45+
if (commit.type === "docs") return "Documentation";
46+
if (commit.type === "style") return "Styles";
47+
if (commit.type === "refactor") return "Code Refactoring";
48+
if (commit.type === "test") return "Tests";
49+
if (commit.type === "build") return "Build System";
50+
if (commit.type === "ci") return "Continuous Integration";
51+
return commit.type;
52+
};
53+
54+
/**
55+
* Replaces `[AB#N]` with an Azure DevOps work-item link and bare `#N` with a
56+
* GitHub issue link in a single regex pass (preventing the ADO-embedded `#N`
57+
* from being re-matched by the GitHub branch of the alternation).
58+
*
59+
* @param {string} subject
60+
* @param {string | undefined} repoBase e.g. "https://github.com/org/repo"
61+
* @returns {{ subject: string, issues: string[] }}
62+
*/
63+
const linkifyIssues = (subject, repoBase) => {
64+
const issues = [];
65+
const result = subject.replace(/\[AB#(\d+)\]|#([0-9]+)/g, (match, adoIssue, ghIssue) => {
66+
if (adoIssue !== undefined) {
67+
issues.push(adoIssue);
68+
return `[AB#${adoIssue}](${ADO_BASE}/${adoIssue})`;
69+
}
70+
if (ghIssue !== undefined && repoBase) {
71+
issues.push(ghIssue);
72+
return `[#${ghIssue}](${repoBase}/issues/${ghIssue})`;
73+
}
74+
return match;
75+
});
76+
return { subject: result, issues };
77+
};
78+
79+
/**
80+
* Replaces `@username` mentions with Markdown profile links.
81+
* Org-scoped handles (`@org/team`) are left as plain text.
82+
*
83+
* @param {string} subject
84+
* @param {string} host e.g. "https://github.com"
85+
* @returns {string}
86+
*/
87+
const linkifyMentions = (subject, host) =>
88+
subject.replace(/\B@([a-z0-9](?:-?[a-z0-9/]){0,38})/g, (_, username) =>
89+
username.includes("/") ? `@${username}` : `[@${username}](${host}/${username})`,
90+
);
91+
92+
// ---------------------------------------------------------------------------
93+
// Transform
94+
// ---------------------------------------------------------------------------
95+
96+
/**
97+
* Transform function for `conventional-changelog-writer`.
98+
* Replicates the Angular preset's transform with ADO work-item links
99+
* replacing GitHub issue links for `[AB#N]` references.
100+
*
101+
* @param {Commit} commit
102+
* @param {WriterContext} context
103+
* @returns {Commit | undefined}
104+
*/
105+
const adoTransform = (commit, context) => {
106+
commit.notes.forEach((note) => {
107+
note.title = "BREAKING CHANGES";
108+
});
109+
110+
if (shouldDiscard(commit)) return;
111+
112+
commit.type = resolveType(commit);
113+
if (commit.scope === "*") commit.scope = "";
114+
if (typeof commit.hash === "string") commit.shortHash = commit.hash.substring(0, 7);
115+
116+
if (typeof commit.subject === "string") {
117+
const repoBase = context.repository
118+
? `${context.host}/${context.owner}/${context.repository}`
119+
: context.repoUrl;
120+
121+
const { subject, issues } = linkifyIssues(commit.subject, repoBase);
122+
commit.subject = context.host ? linkifyMentions(subject, context.host) : subject;
123+
commit.references = commit.references.filter((ref) => !issues.includes(ref.issue));
124+
}
125+
126+
return commit;
127+
};
128+
129+
// ---------------------------------------------------------------------------
130+
// Config
131+
// ---------------------------------------------------------------------------
132+
133+
module.exports = {
134+
branches: ["main"],
135+
plugins: [
136+
[
137+
"@semantic-release/commit-analyzer",
138+
{
139+
preset: "angular",
140+
parserOpts: { noteKeywords: ["BREAKING CHANGE", "BREAKING CHANGES"] },
141+
},
142+
],
143+
[
144+
"@semantic-release/release-notes-generator",
145+
{
146+
preset: "angular",
147+
writerOpts: { transform: adoTransform },
148+
},
149+
],
150+
"@semantic-release/npm",
151+
"@semantic-release/changelog",
152+
["@semantic-release/github", { successComment: false }],
153+
"@semantic-release/git",
154+
],
155+
};

0 commit comments

Comments
 (0)