@williamthorsen/release-kit 5.0.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/CHANGELOG.md +149 -49
  2. package/README.md +275 -78
  3. package/cliff.toml.template +26 -17
  4. package/dist/esm/.cache +1 -1
  5. package/dist/esm/assertCleanWorkingTree.js +1 -1
  6. package/dist/esm/bin/release-kit.js +97 -4
  7. package/dist/esm/buildChangelogEntries.d.ts +4 -0
  8. package/dist/esm/buildChangelogEntries.js +173 -0
  9. package/dist/esm/buildDependencyGraph.d.ts +1 -0
  10. package/dist/esm/buildDependencyGraph.js +8 -1
  11. package/dist/esm/buildReleaseSummary.js +9 -1
  12. package/dist/esm/buildSyntheticChangelogEntry.d.ts +5 -0
  13. package/dist/esm/buildSyntheticChangelogEntry.js +13 -0
  14. package/dist/esm/changelogJsonFile.d.ts +4 -0
  15. package/dist/esm/changelogJsonFile.js +68 -0
  16. package/dist/esm/checkWorkTypesDrift.d.ts +11 -0
  17. package/dist/esm/checkWorkTypesDrift.js +110 -0
  18. package/dist/esm/collectPolicyViolations.d.ts +6 -0
  19. package/dist/esm/collectPolicyViolations.js +15 -0
  20. package/dist/esm/createGithubRelease.d.ts +12 -2
  21. package/dist/esm/createGithubRelease.js +12 -8
  22. package/dist/esm/createGithubReleaseCommand.js +10 -6
  23. package/dist/esm/decideRelease.d.ts +28 -0
  24. package/dist/esm/decideRelease.js +44 -0
  25. package/dist/esm/defaults.d.ts +8 -0
  26. package/dist/esm/defaults.js +43 -20
  27. package/dist/esm/deriveWorkspaceConfig.js +3 -0
  28. package/dist/esm/determineBumpFromCommits.d.ts +6 -1
  29. package/dist/esm/determineBumpFromCommits.js +9 -3
  30. package/dist/esm/generateChangelogs.js +14 -29
  31. package/dist/esm/index.d.ts +2 -43
  32. package/dist/esm/index.js +0 -82
  33. package/dist/esm/init/templates.js +2 -2
  34. package/dist/esm/loadConfig.d.ts +10 -1
  35. package/dist/esm/loadConfig.js +110 -24
  36. package/dist/esm/parseCommitMessage.d.ts +8 -2
  37. package/dist/esm/parseCommitMessage.js +32 -3
  38. package/dist/esm/prepareCommand.js +51 -9
  39. package/dist/esm/publish.d.ts +0 -1
  40. package/dist/esm/publish.js +3 -3
  41. package/dist/esm/publishCommand.js +31 -3
  42. package/dist/esm/releasePrepare.js +109 -41
  43. package/dist/esm/releasePrepareMono.js +156 -87
  44. package/dist/esm/releasePrepareProject.d.ts +9 -0
  45. package/dist/esm/releasePrepareProject.js +121 -0
  46. package/dist/esm/renderReleaseNotes.js +2 -1
  47. package/dist/esm/reportPrepare.js +88 -24
  48. package/dist/esm/resolveCommandTags.js +16 -6
  49. package/dist/esm/resolveReleaseTags.d.ts +8 -1
  50. package/dist/esm/resolveReleaseTags.js +11 -7
  51. package/dist/esm/runGitCliff.d.ts +2 -0
  52. package/dist/esm/runGitCliff.js +27 -0
  53. package/dist/esm/stripEmojiPrefix.d.ts +1 -0
  54. package/dist/esm/stripEmojiPrefix.js +7 -0
  55. package/dist/esm/syncWorkTypes.d.ts +10 -0
  56. package/dist/esm/syncWorkTypes.js +90 -0
  57. package/dist/esm/types.d.ts +72 -14
  58. package/dist/esm/validateConfig.js +26 -0
  59. package/dist/esm/validateOnlyExcludesStrandedDependents.d.ts +14 -0
  60. package/dist/esm/validateOnlyExcludesStrandedDependents.js +109 -0
  61. package/dist/esm/work-types.json +127 -0
  62. package/dist/esm/work-types.schema.json +73 -0
  63. package/dist/esm/workTypesData.d.ts +14 -0
  64. package/dist/esm/workTypesData.js +59 -0
  65. package/dist/esm/workTypesUtils.d.ts +5 -0
  66. package/dist/esm/workTypesUtils.js +16 -0
  67. package/package.json +9 -3
  68. package/presets/labels/common.yaml +9 -6
  69. package/schemas/label-map.json +24 -0
  70. package/dist/esm/generateChangelogJson.d.ts +0 -7
  71. package/dist/esm/generateChangelogJson.js +0 -232
  72. package/dist/esm/version.d.ts +0 -1
  73. package/dist/esm/version.js +0 -4
@@ -8,18 +8,21 @@
8
8
  - name: bug
9
9
  color: d73a4a
10
10
  description: "Something isn't working"
11
- - name: documentation
12
- color: a2eeef
13
- description: Improvements or additions to documentation
14
11
  - name: deprecation
15
12
  color: fbca04
16
13
  description: Marks functionality for future removal
14
+ - name: documentation
15
+ color: a2eeef
16
+ description: Improvements or additions to documentation
17
17
  - name: feature
18
18
  color: '0075ca'
19
19
  description: Added or improved external functionality
20
20
  - name: fix
21
21
  color: d73a4a
22
22
  description: Fixes a bug
23
+ - name: operational
24
+ color: '000000'
25
+ description: Actions outside the codebase
23
26
  - name: performance
24
27
  color: '0075ca'
25
28
  description: Improves performance without changing behavior
@@ -48,6 +51,9 @@
48
51
  - name: dependencies
49
52
  color: edc287
50
53
  description: Change to dependencies
54
+ - name: internal
55
+ color: 1d76db
56
+ description: Internal change without external impact
51
57
  - name: refactoring
52
58
  color: edc287
53
59
  description: Improvement to code without change in functionality
@@ -57,9 +63,6 @@
57
63
  - name: tooling
58
64
  color: edc287
59
65
  description: Development tools
60
- - name: utility
61
- color: 1d76db
62
- description: Changed internal functionality
63
66
 
64
67
  # Priority
65
68
  - name: 'priority:critical'
@@ -0,0 +1,24 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "label-map",
4
+ "description": "Maps commit-prefix scopes and types to GitHub label names. Consumed by agent skills, CI tooling, and any script that needs to translate commit conventions into label operations.",
5
+ "type": "object",
6
+ "required": ["types", "scopes"],
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "$schema": {
10
+ "type": "string",
11
+ "description": "JSON Schema reference for editor support."
12
+ },
13
+ "types": {
14
+ "type": "object",
15
+ "description": "Maps commit-type prefix (e.g., `feat`) to GitHub label name (e.g., `feature`).",
16
+ "additionalProperties": { "type": "string" }
17
+ },
18
+ "scopes": {
19
+ "type": "object",
20
+ "description": "Maps commit-scope prefix (e.g., `audit`) to GitHub label name (e.g., `scope:audit`).",
21
+ "additionalProperties": { "type": "string" }
22
+ }
23
+ }
24
+ }
@@ -1,7 +0,0 @@
1
- import type { GenerateChangelogOptions } from './generateChangelogs.ts';
2
- import type { ReleaseConfig } from './types.ts';
3
- export declare function generateChangelogJson(config: Pick<ReleaseConfig, 'cliffConfigPath' | 'changelogJson'>, changelogPath: string, tag: string, dryRun: boolean, options?: GenerateChangelogOptions): string[];
4
- export declare function generateSyntheticChangelogJson(config: Pick<ReleaseConfig, 'changelogJson'>, changelogPath: string, newVersion: string, date: string, propagatedFrom: Array<{
5
- packageName: string;
6
- newVersion: string;
7
- }>, dryRun: boolean): string[];
@@ -1,232 +0,0 @@
1
- import { execFileSync } from "node:child_process";
2
- import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import { dirname, join } from "node:path";
5
- import stringify from "json-stringify-pretty-compact";
6
- import { extractVersion, isChangelogEntry } from "./changelogJsonUtils.js";
7
- import { resolveCliffConfigPath } from "./resolveCliffConfigPath.js";
8
- import { isRecord, isUnknownArray } from "./typeGuards.js";
9
- function generateChangelogJson(config, changelogPath, tag, dryRun, options) {
10
- const outputFile = join(changelogPath, config.changelogJson.outputPath);
11
- if (dryRun) {
12
- return [outputFile];
13
- }
14
- const resolvedConfigPath = resolveCliffConfigPath(config.cliffConfigPath, import.meta.url);
15
- let cliffConfigPath = resolvedConfigPath;
16
- let tempDir;
17
- if (resolvedConfigPath.endsWith(".template")) {
18
- tempDir = mkdtempSync(join(tmpdir(), "cliff-"));
19
- cliffConfigPath = join(tempDir, "cliff.toml");
20
- copyFileSync(resolvedConfigPath, cliffConfigPath);
21
- }
22
- const args = ["--config", cliffConfigPath, "--context", "--tag", tag];
23
- if (options?.tagPattern !== void 0) {
24
- args.push("--tag-pattern", options.tagPattern);
25
- }
26
- for (const includePath of options?.includePaths ?? []) {
27
- args.push("--include-path", includePath);
28
- }
29
- try {
30
- const contextJson = execFileSync("npx", ["--yes", "git-cliff", ...args], {
31
- encoding: "utf8",
32
- stdio: ["pipe", "pipe", "inherit"]
33
- });
34
- const releases = parseCliffContext(contextJson);
35
- const devOnlySections = new Set(config.changelogJson.devOnlySections);
36
- const entries = transformReleases(releases, devOnlySections);
37
- const existingEntries = readExistingEntries(outputFile);
38
- const merged = mergeEntries(entries, existingEntries);
39
- mkdirSync(dirname(outputFile), { recursive: true });
40
- writeFileSync(outputFile, stringify(merged, { maxLength: 100 }) + "\n", "utf8");
41
- return [outputFile];
42
- } catch (error) {
43
- throw new Error(
44
- `Failed to generate changelog JSON for ${outputFile}: ${error instanceof Error ? error.message : String(error)}`
45
- );
46
- } finally {
47
- if (tempDir !== void 0) {
48
- rmSync(tempDir, { recursive: true, force: true });
49
- }
50
- }
51
- }
52
- function generateSyntheticChangelogJson(config, changelogPath, newVersion, date, propagatedFrom, dryRun) {
53
- const outputFile = join(changelogPath, config.changelogJson.outputPath);
54
- if (dryRun) {
55
- return [outputFile];
56
- }
57
- const items = propagatedFrom.map((dep) => ({
58
- description: `Bumped \`${dep.packageName}\` to ${dep.newVersion}`
59
- }));
60
- const entry = {
61
- version: newVersion,
62
- date,
63
- sections: [{ title: "Dependency updates", audience: "dev", items }]
64
- };
65
- const existingEntries = readExistingEntries(outputFile);
66
- const merged = mergeEntries([entry], existingEntries);
67
- mkdirSync(dirname(outputFile), { recursive: true });
68
- writeFileSync(outputFile, stringify(merged, { maxLength: 100 }) + "\n", "utf8");
69
- return [outputFile];
70
- }
71
- function parseCliffContext(json) {
72
- const parsed = JSON.parse(json);
73
- if (!isUnknownArray(parsed)) {
74
- throw new TypeError("Expected git-cliff --context output to be an array");
75
- }
76
- return parsed.map(toCliffContextRelease);
77
- }
78
- function toCliffContextRelease(value) {
79
- if (!isRecord(value)) {
80
- return {};
81
- }
82
- const release = {};
83
- if (typeof value.version === "string") {
84
- release.version = value.version;
85
- }
86
- if (typeof value.timestamp === "number") {
87
- release.timestamp = value.timestamp;
88
- }
89
- if (isUnknownArray(value.commits)) {
90
- release.commits = value.commits.map(toCliffContextCommit);
91
- }
92
- return release;
93
- }
94
- function toCliffContextCommit(value) {
95
- if (!isRecord(value)) {
96
- return { message: "" };
97
- }
98
- const commit = {
99
- message: typeof value.message === "string" ? value.message : ""
100
- };
101
- if (typeof value.group === "string") {
102
- commit.group = value.group;
103
- }
104
- return commit;
105
- }
106
- function transformReleases(releases, devOnlySections) {
107
- const entries = [];
108
- for (const release of releases) {
109
- if (release.version === void 0) {
110
- continue;
111
- }
112
- const version = extractVersion(release.version);
113
- const date = release.timestamp !== void 0 ? new Date(release.timestamp * 1e3).toISOString().slice(0, 10) : "unreleased";
114
- const sectionMap = /* @__PURE__ */ new Map();
115
- for (const commit of release.commits ?? []) {
116
- const group = commit.group ?? "Other";
117
- const description = extractDescription(commit.message);
118
- const body = extractBody(commit.message);
119
- let items = sectionMap.get(group);
120
- if (items === void 0) {
121
- items = [];
122
- sectionMap.set(group, items);
123
- }
124
- const item = { description };
125
- if (body !== void 0) {
126
- item.body = body;
127
- }
128
- items.push(item);
129
- }
130
- const sections = [];
131
- for (const [title, items] of sectionMap) {
132
- if (items.length === 0) {
133
- continue;
134
- }
135
- sections.push({
136
- title,
137
- audience: devOnlySections.has(title) ? "dev" : "all",
138
- items
139
- });
140
- }
141
- if (sections.length > 0) {
142
- entries.push({ version, date, sections });
143
- }
144
- }
145
- return entries;
146
- }
147
- function extractDescription(message) {
148
- const firstLine = message.split("\n")[0] ?? message;
149
- const afterColon = firstLine.split(": ").slice(1).join(": ");
150
- if (afterColon.length > 0) {
151
- return afterColon.charAt(0).toUpperCase() + afterColon.slice(1);
152
- }
153
- return firstLine;
154
- }
155
- const TRAILER_PATTERNS = [
156
- /^Signed-off-by:/i,
157
- /^Co-authored-by:/i,
158
- /^(Closes|Fixes|Resolves)\s+#\d+\s*$/i,
159
- /^https?:\/\/\S+\/pull\/\d+\/?\s*$/
160
- ];
161
- function extractBody(message) {
162
- const lines = message.split("\n").slice(1);
163
- let start = 0;
164
- while (start < lines.length && (lines[start] ?? "").trim() === "") {
165
- start += 1;
166
- }
167
- let end = lines.length;
168
- while (end > start) {
169
- const line = lines[end - 1] ?? "";
170
- const trimmed = line.trim();
171
- if (trimmed === "") {
172
- end -= 1;
173
- continue;
174
- }
175
- if (TRAILER_PATTERNS.some((pattern) => pattern.test(trimmed))) {
176
- end -= 1;
177
- continue;
178
- }
179
- break;
180
- }
181
- if (end <= start) {
182
- return void 0;
183
- }
184
- return lines.slice(start, end).join("\n").trim();
185
- }
186
- function readExistingEntries(filePath) {
187
- if (!existsSync(filePath)) {
188
- return [];
189
- }
190
- try {
191
- const content = readFileSync(filePath, "utf8");
192
- const parsed = JSON.parse(content);
193
- if (!isUnknownArray(parsed)) {
194
- return [];
195
- }
196
- return parsed.filter(isChangelogEntry);
197
- } catch (error) {
198
- console.warn(
199
- `Warning: could not parse existing ${filePath}: ${error instanceof Error ? error.message : String(error)}; treating as empty`
200
- );
201
- return [];
202
- }
203
- }
204
- function mergeEntries(newEntries, existingEntries) {
205
- const versionMap = /* @__PURE__ */ new Map();
206
- for (const entry of existingEntries) {
207
- versionMap.set(entry.version, entry);
208
- }
209
- for (const entry of newEntries) {
210
- versionMap.set(entry.version, entry);
211
- }
212
- return [...versionMap.values()].sort((a, b) => compareVersionsDescending(a.version, b.version));
213
- }
214
- function parseVersionParts(version) {
215
- return version.split(".").map((s) => {
216
- const n = Number(s);
217
- return Number.isNaN(n) ? 0 : n;
218
- });
219
- }
220
- function compareVersionsDescending(a, b) {
221
- const partsA = parseVersionParts(a);
222
- const partsB = parseVersionParts(b);
223
- for (let i = 0; i < 3; i++) {
224
- const diff = (partsB[i] ?? 0) - (partsA[i] ?? 0);
225
- if (diff !== 0) return diff;
226
- }
227
- return 0;
228
- }
229
- export {
230
- generateChangelogJson,
231
- generateSyntheticChangelogJson
232
- };
@@ -1 +0,0 @@
1
- export declare const VERSION = "5.0.0";
@@ -1,4 +0,0 @@
1
- const VERSION = "5.0.0";
2
- export {
3
- VERSION
4
- };