Skip to content

Commit 1aa4419

Browse files
committed
migrate release-notes.mts
1 parent da9c15f commit 1aa4419

File tree

1 file changed

+110
-50
lines changed

1 file changed

+110
-50
lines changed

scripts/internal/release-notes.mts

Lines changed: 110 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,115 @@
11
/**
22
* This script is only used to help write release announcements.
33
*/
4-
// @ts-expect-error Could not find a declaration file for module
5-
import { generateNotes } from "@semantic-release/release-notes-generator";
64
import { spawn } from "node:child_process";
75
import * as path from "node:path";
8-
import { URL, fileURLToPath } from "node:url";
9-
import { readJSONFile } from "../helpers.js";
10-
import type { Manifest } from "../types.js";
11-
12-
function reformat(
13-
output: string,
14-
lastRelease: string,
15-
nextRelease: string
16-
): string {
17-
const replacements: [RegExp, string][] = [
18-
[/^# .*/m, `📣 react-native-test-app ${nextRelease}`],
19-
[/^### .*/m, `Other fixes since ${lastRelease}:`],
20-
[/^\* \*\*android:\*\*/gm, "* **Android:**"],
21-
[/^\* \*\*apple:\*\*/gm, "* **Apple:**"],
22-
[/^\* \*\*ios:\*\*/gm, "* **iOS:**"],
23-
[/^\* \*\*macos:\*\*/gm, "* **macOS:**"],
24-
[/^\* \*\*visionos:\*\*/gm, "* **visionOS:**"],
25-
[/^\* \*\*windows:\*\*/gm, "* **Windows:**"],
26-
[/\s*\(\[#\d+\]\(https:\/\/github.com.*/gm, ""],
27-
];
28-
return replacements
29-
.reduce(
30-
(output, [search, replace]) => output.replace(search, replace),
31-
output
32-
)
33-
.trim();
6+
import { fileURLToPath } from "node:url";
7+
8+
type Group =
9+
| "general"
10+
| "android"
11+
| "apple"
12+
| "ios"
13+
| "macos"
14+
| "visionos"
15+
| "windows";
16+
17+
type Changes = Record<string, Record<Group, string[]>>;
18+
19+
function assertCategory(category: string): asserts category is "feat" | "fix" {
20+
if (category !== "feat" && category !== "fix") {
21+
throw new Error(`Unknown category: ${category}`);
22+
}
3423
}
3524

36-
function repositoryUrl() {
37-
const p = fileURLToPath(new URL("../../package.json", import.meta.url));
38-
const manifest = readJSONFile<Manifest>(p);
39-
return manifest.repository?.url;
25+
function capitalize(s: string): string {
26+
return String(s[0]).toUpperCase() + s.substring(1);
27+
}
28+
29+
function sanitizeGroup(group: string): Group {
30+
switch (group) {
31+
case "android":
32+
case "apple":
33+
case "ios":
34+
case "macos":
35+
case "visionos":
36+
case "windows":
37+
return group;
38+
default:
39+
return "general";
40+
}
41+
}
42+
43+
function parseCommits(commits: { message: string }[]): Changes {
44+
const changes: Changes = {
45+
feat: {
46+
general: [],
47+
android: [],
48+
apple: [],
49+
ios: [],
50+
macos: [],
51+
visionos: [],
52+
windows: [],
53+
},
54+
fix: {
55+
general: [],
56+
android: [],
57+
apple: [],
58+
ios: [],
59+
macos: [],
60+
visionos: [],
61+
windows: [],
62+
},
63+
};
64+
65+
for (const { message } of commits) {
66+
const m = message.match(/^(feat|fix)(?:\((.*?)\))?: (.*)$/);
67+
if (m) {
68+
const [, cat, group, message] = m;
69+
assertCategory(cat);
70+
changes[cat][sanitizeGroup(group)].push(message);
71+
}
72+
}
73+
74+
return changes;
75+
}
76+
77+
function renderGroup(group: string): string {
78+
switch (group) {
79+
case "android":
80+
return "**Android:** ";
81+
case "apple":
82+
return "**Apple:** ";
83+
case "ios":
84+
return "**iOS:**";
85+
case "macos":
86+
return "**macOS:**";
87+
case "visionos":
88+
return "**visionOS:**";
89+
case "windows":
90+
return "**Windows:**";
91+
default:
92+
return "";
93+
}
94+
}
95+
96+
function renderCategory(
97+
header: string,
98+
changes: Changes[string],
99+
output: string[]
100+
): string[] {
101+
const groups = Object.entries(changes);
102+
if (groups.length > 0) {
103+
output.push("", header, "");
104+
for (const [group, entries] of groups) {
105+
for (const entry of entries) {
106+
output.push(`- ${renderGroup(group)}${capitalize(entry)}`);
107+
}
108+
}
109+
}
110+
return output;
40111
}
41112

42-
/**
43-
* @param {string} lastRelease
44-
* @param {string} nextRelease
45-
*/
46113
function main(lastRelease: string, nextRelease: string): void {
47114
const args = [
48115
"log",
@@ -73,20 +140,13 @@ function main(lastRelease: string, nextRelease: string): void {
73140
return;
74141
}
75142

76-
const context = {
77-
commits,
78-
lastRelease: { gitTag: lastRelease },
79-
nextRelease: { gitTag: nextRelease },
80-
options: {
81-
repositoryUrl: repositoryUrl(),
82-
},
83-
cwd: process.cwd(),
84-
};
85-
86-
const releaseNotes: Promise<string> = generateNotes({}, context);
87-
releaseNotes
88-
.then((output) => reformat(output, lastRelease, nextRelease))
89-
.then((output) => console.log(output));
143+
const { feat, fix } = parseCommits(commits);
144+
145+
const lines = [`📣 react-native-test-app ${nextRelease}`];
146+
renderCategory("New features:", feat, lines);
147+
renderCategory(`Fixes since ${lastRelease}:`, fix, lines);
148+
149+
console.log(lines.join("\n"));
90150
});
91151
}
92152

0 commit comments

Comments
 (0)