@williamthorsen/release-kit 5.2.1 → 5.3.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 (46) hide show
  1. package/CHANGELOG.md +62 -26
  2. package/README.md +251 -31
  3. package/cliff.toml.template +4 -39
  4. package/dist/esm/.cache +1 -1
  5. package/dist/esm/bin/release-kit.js +59 -0
  6. package/dist/esm/buildChangelogEntries.js +6 -0
  7. package/dist/esm/buildEmptyReleaseEntry.d.ts +2 -0
  8. package/dist/esm/buildEmptyReleaseEntry.js +16 -0
  9. package/dist/esm/changelogJsonFile.d.ts +2 -0
  10. package/dist/esm/changelogJsonFile.js +11 -1
  11. package/dist/esm/changelogJsonUtils.d.ts +2 -1
  12. package/dist/esm/changelogJsonUtils.js +9 -0
  13. package/dist/esm/changelogOverrides.d.ts +53 -0
  14. package/dist/esm/changelogOverrides.js +424 -0
  15. package/dist/esm/checkWorkTypesDrift.js +3 -2
  16. package/dist/esm/defaults.js +1 -1
  17. package/dist/esm/generateChangelogs.d.ts +0 -3
  18. package/dist/esm/generateChangelogs.js +1 -35
  19. package/dist/esm/index.d.ts +2 -0
  20. package/dist/esm/index.js +8 -0
  21. package/dist/esm/loadConfig.d.ts +1 -1
  22. package/dist/esm/releasePrepare.js +68 -11
  23. package/dist/esm/releasePrepareMono.js +103 -56
  24. package/dist/esm/releasePrepareProject.d.ts +4 -1
  25. package/dist/esm/releasePrepareProject.js +74 -18
  26. package/dist/esm/renderChangelogMarkdown.d.ts +12 -0
  27. package/dist/esm/renderChangelogMarkdown.js +32 -0
  28. package/dist/esm/renderReleaseNotes.js +6 -1
  29. package/dist/esm/resolveReleaseNotesConfig.js +3 -1
  30. package/dist/esm/runGitCliff.d.ts +1 -0
  31. package/dist/esm/runGitCliff.js +7 -0
  32. package/dist/esm/syncWorkTypes.js +3 -2
  33. package/dist/esm/types.d.ts +98 -31
  34. package/dist/esm/types.js +60 -0
  35. package/dist/esm/validateConfig.js +84 -345
  36. package/dist/esm/validateOverridesCommand.d.ts +13 -0
  37. package/dist/esm/validateOverridesCommand.js +119 -0
  38. package/dist/esm/work-types.json +23 -17
  39. package/dist/esm/work-types.schema.json +28 -1
  40. package/dist/esm/workTypesData.d.ts +8 -0
  41. package/dist/esm/workTypesData.js +20 -17
  42. package/dist/esm/workTypesUtils.d.ts +1 -0
  43. package/dist/esm/workTypesUtils.js +8 -0
  44. package/package.json +4 -3
  45. package/dist/esm/writeSyntheticChangelog.d.ts +0 -9
  46. package/dist/esm/writeSyntheticChangelog.js +0 -27
@@ -1,30 +1,42 @@
1
1
  import { execSync } from "node:child_process";
2
2
  import { buildChangelogEntries } from "./buildChangelogEntries.js";
3
3
  import { buildDependencyGraph } from "./buildDependencyGraph.js";
4
+ import { buildEmptyReleaseEntry } from "./buildEmptyReleaseEntry.js";
4
5
  import { buildSyntheticChangelogEntry } from "./buildSyntheticChangelogEntry.js";
5
6
  import { bumpAllVersions, setAllVersions } from "./bumpAllVersions.js";
6
- import { resolveChangelogJsonPath, upsertChangelogJson } from "./changelogJsonFile.js";
7
+ import {
8
+ mergeChangelogEntriesWithDisk,
9
+ resolveChangelogJsonPath,
10
+ upsertChangelogJsonAndReturn
11
+ } from "./changelogJsonFile.js";
12
+ import {
13
+ applyWorkspaceOverrides,
14
+ createOverrideContext,
15
+ formatStaleOverrideKeyWarning
16
+ } from "./changelogOverrides.js";
7
17
  import { createPolicyViolationCollector } from "./collectPolicyViolations.js";
8
18
  import { isForwardVersion } from "./compareVersions.js";
9
19
  import { decideRelease } from "./decideRelease.js";
10
20
  import { DEFAULT_BREAKING_POLICIES, DEFAULT_VERSION_PATTERNS, DEFAULT_WORK_TYPES } from "./defaults.js";
11
21
  import { detectUndeclaredTagPrefixes } from "./detectUndeclaredTagPrefixes.js";
12
- import { buildTagPattern, generateChangelog } from "./generateChangelogs.js";
22
+ import { buildTagPattern } from "./generateChangelogs.js";
13
23
  import { getCommitsSinceTarget } from "./getCommitsSinceTarget.js";
14
24
  import { hasPrettierConfig } from "./hasPrettierConfig.js";
15
25
  import { resolveWorkTypes } from "./loadConfig.js";
16
26
  import { propagateBumps } from "./propagateBumps.js";
17
27
  import { readCurrentVersion } from "./readCurrentVersion.js";
18
28
  import { releasePrepareProject } from "./releasePrepareProject.js";
29
+ import { writeChangelogMarkdown } from "./renderChangelogMarkdown.js";
19
30
  import { deriveSectionOrder } from "./resolveReleaseNotesConfig.js";
31
+ import { refreshGitCliffCache } from "./runGitCliff.js";
20
32
  import { writeReleaseNotesPreviews } from "./writeReleaseNotesPreviews.js";
21
- import { writeSyntheticChangelog } from "./writeSyntheticChangelog.js";
22
33
  function releasePrepareMono(config, options) {
23
34
  const { dryRun, withReleaseNotes } = options;
24
35
  if (withReleaseNotes === true && !config.changelogJson.enabled) {
25
36
  console.warn("Warning: --with-release-notes requires changelogJson.enabled; skipping preview generation");
26
37
  }
27
38
  const sectionOrder = deriveSectionOrder(resolveWorkTypes(config.workTypes));
39
+ const overrideContext = createOverrideContext(config.workspaces);
28
40
  const { directBumps, directResults, skippedResults, currentVersions } = determineDirectBumps(config, options);
29
41
  const previousTags = /* @__PURE__ */ new Map();
30
42
  for (const result of directResults.values()) {
@@ -47,7 +59,10 @@ function releasePrepareMono(config, options) {
47
59
  enabled: withReleaseNotes === true && config.changelogJson.enabled,
48
60
  sectionOrder
49
61
  };
50
- const { tags, modifiedFiles } = executeReleaseSet(
62
+ if (fullReleaseSet.size > 0) {
63
+ refreshGitCliffCache();
64
+ }
65
+ const { tags, modifiedFiles } = executeReleaseSet({
51
66
  sortedDirs,
52
67
  fullReleaseSet,
53
68
  config,
@@ -55,8 +70,10 @@ function releasePrepareMono(config, options) {
55
70
  previousTags,
56
71
  dryRun,
57
72
  workspaces,
58
- previewOptions
59
- );
73
+ previewOptions,
74
+ overrideContext,
75
+ sectionOrder
76
+ });
60
77
  const configOrder = new Map(config.workspaces.map((w, i) => [w.dir, i]));
61
78
  workspaces.sort((a, b) => {
62
79
  const orderA = configOrder.get(a.name ?? "") ?? 0;
@@ -65,15 +82,32 @@ function releasePrepareMono(config, options) {
65
82
  });
66
83
  let project;
67
84
  if (config.project !== void 0) {
68
- project = tryStage("project release stage", () => releasePrepareProject({ config, options, modifiedFiles, tags }));
85
+ project = tryStage(
86
+ "project release stage",
87
+ () => releasePrepareProject({
88
+ config,
89
+ options,
90
+ modifiedFiles,
91
+ tags,
92
+ rootOverrides: overrideContext.project,
93
+ overrideWarnings: overrideContext.overrideWarnings,
94
+ globalMatchedRootKeys: overrideContext.globalMatchedRootKeys
95
+ })
96
+ );
69
97
  }
70
98
  const formatCommand = runFormatCommand(config, tags, modifiedFiles, dryRun);
99
+ for (const overrideKey of overrideContext.project.keys()) {
100
+ if (!overrideContext.globalMatchedRootKeys.has(overrideKey)) {
101
+ overrideContext.overrideWarnings.push(formatStaleOverrideKeyWarning(overrideKey));
102
+ }
103
+ }
104
+ const allWarnings = [...warnings, ...overrideContext.overrideWarnings];
71
105
  return {
72
106
  workspaces,
73
107
  tags,
74
108
  formatCommand,
75
109
  dryRun,
76
- ...warnings.length > 0 ? { warnings } : {},
110
+ ...allWarnings.length > 0 ? { warnings: allWarnings } : {},
77
111
  ...project === void 0 ? {} : { project }
78
112
  };
79
113
  }
@@ -206,7 +240,19 @@ function collectSkippedWorkspaces(skippedResults, fullReleaseSet) {
206
240
  }
207
241
  return workspaces;
208
242
  }
209
- function executeReleaseSet(sortedDirs, fullReleaseSet, config, directResults, previousTags, dryRun, workspaces, previewOptions) {
243
+ function executeReleaseSet(args) {
244
+ const {
245
+ sortedDirs,
246
+ fullReleaseSet,
247
+ config,
248
+ directResults,
249
+ previousTags,
250
+ dryRun,
251
+ workspaces,
252
+ previewOptions,
253
+ overrideContext,
254
+ sectionOrder
255
+ } = args;
210
256
  const tags = [];
211
257
  const modifiedFiles = [];
212
258
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -233,7 +279,9 @@ function executeReleaseSet(sortedDirs, fullReleaseSet, config, directResults, pr
233
279
  tags,
234
280
  modifiedFiles,
235
281
  workspaces,
236
- previewOptions
282
+ previewOptions,
283
+ overrideContext,
284
+ sectionOrder
237
285
  })
238
286
  );
239
287
  }
@@ -252,7 +300,9 @@ function executeWorkspaceRelease(args) {
252
300
  tags,
253
301
  modifiedFiles,
254
302
  workspaces,
255
- previewOptions
303
+ previewOptions,
304
+ overrideContext,
305
+ sectionOrder
256
306
  } = args;
257
307
  const setVersionTarget = directResult?.setVersion;
258
308
  const bump = setVersionTarget === void 0 ? bumpAllVersions(workspace.packageFiles, releaseEntry.releaseType, dryRun) : setAllVersions(workspace.packageFiles, setVersionTarget, dryRun);
@@ -260,17 +310,21 @@ function executeWorkspaceRelease(args) {
260
310
  tags.push(newTag);
261
311
  modifiedFiles.push(...workspace.packageFiles, ...workspace.changelogPaths.map((p) => `${p}/CHANGELOG.md`));
262
312
  const isPropagationOnly = directResult === void 0;
313
+ const isEmptyRange = directResult !== void 0 && directResult.commits.length === 0;
263
314
  const changelogFiles = generateWorkspaceChangelogs({
264
315
  workspace,
265
316
  releaseEntry,
266
317
  newTag,
267
318
  newVersion: bump.newVersion,
268
319
  isPropagationOnly,
320
+ isEmptyRange,
269
321
  config,
270
322
  dryRun,
271
323
  today,
272
324
  modifiedFiles,
273
- previewOptions
325
+ previewOptions,
326
+ overrideContext,
327
+ sectionOrder
274
328
  });
275
329
  const released = {
276
330
  name: dir,
@@ -327,66 +381,59 @@ function generateWorkspaceChangelogs(args) {
327
381
  newTag,
328
382
  newVersion,
329
383
  isPropagationOnly,
384
+ isEmptyRange,
330
385
  config,
331
386
  dryRun,
332
387
  today,
333
388
  modifiedFiles,
334
- previewOptions
389
+ previewOptions,
390
+ overrideContext,
391
+ sectionOrder
335
392
  } = args;
393
+ const newEntries = buildWorkspaceEntries({
394
+ workspace,
395
+ releaseEntry,
396
+ newTag,
397
+ newVersion,
398
+ isPropagationOnly,
399
+ isEmptyRange,
400
+ config,
401
+ today
402
+ });
403
+ const applied = applyWorkspaceOverrides(newEntries, workspace.workspacePath, overrideContext);
336
404
  const changelogFiles = [];
337
405
  let firstChangelogJsonPath;
338
- if (isPropagationOnly && releaseEntry.propagatedFrom !== void 0) {
339
- for (const changelogPath of workspace.changelogPaths) {
340
- changelogFiles.push(
341
- writeSyntheticChangelog({
342
- changelogPath,
343
- newVersion,
344
- date: today,
345
- propagatedFrom: releaseEntry.propagatedFrom,
346
- dryRun
347
- })
348
- );
349
- }
406
+ for (const changelogPath of workspace.changelogPaths) {
407
+ const jsonPath = resolveChangelogJsonPath(config, changelogPath);
408
+ const shouldWriteJson = config.changelogJson.enabled && !dryRun;
409
+ const mergedEntries = shouldWriteJson ? upsertChangelogJsonAndReturn(jsonPath, applied.entries) : mergeChangelogEntriesWithDisk(jsonPath, applied.entries);
350
410
  if (config.changelogJson.enabled) {
351
- const syntheticEntry = buildSyntheticChangelogEntry(releaseEntry.propagatedFrom, newVersion, today);
352
- for (const changelogPath of workspace.changelogPaths) {
353
- const jsonPath = resolveChangelogJsonPath(config, changelogPath);
354
- if (!dryRun) {
355
- upsertChangelogJson(jsonPath, [syntheticEntry]);
356
- }
357
- modifiedFiles.push(jsonPath);
358
- firstChangelogJsonPath ??= jsonPath;
359
- }
411
+ modifiedFiles.push(jsonPath);
412
+ firstChangelogJsonPath ??= jsonPath;
360
413
  }
361
- maybeWritePreviews(workspace, newTag, firstChangelogJsonPath, previewOptions, dryRun);
362
- return changelogFiles;
363
- }
364
- const tagPattern = buildTagPattern(getAllTagPrefixes(workspace));
365
- for (const changelogPath of workspace.changelogPaths) {
366
414
  changelogFiles.push(
367
- ...generateChangelog(config, changelogPath, newTag, dryRun, {
368
- tagPattern,
369
- includePaths: workspace.paths
415
+ writeChangelogMarkdown({
416
+ changelogPath,
417
+ entries: mergedEntries,
418
+ sectionOrder,
419
+ dryRun
370
420
  })
371
421
  );
372
422
  }
373
- if (config.changelogJson.enabled) {
374
- const entries = buildChangelogEntries(config, newTag, {
375
- tagPattern,
376
- includePaths: workspace.paths
377
- });
378
- for (const changelogPath of workspace.changelogPaths) {
379
- const jsonPath = resolveChangelogJsonPath(config, changelogPath);
380
- if (!dryRun) {
381
- upsertChangelogJson(jsonPath, entries);
382
- }
383
- modifiedFiles.push(jsonPath);
384
- firstChangelogJsonPath ??= jsonPath;
385
- }
386
- }
387
423
  maybeWritePreviews(workspace, newTag, firstChangelogJsonPath, previewOptions, dryRun);
388
424
  return changelogFiles;
389
425
  }
426
+ function buildWorkspaceEntries(args) {
427
+ const { workspace, releaseEntry, newTag, newVersion, isPropagationOnly, isEmptyRange, config, today } = args;
428
+ if (isPropagationOnly && releaseEntry.propagatedFrom !== void 0) {
429
+ return [buildSyntheticChangelogEntry(releaseEntry.propagatedFrom, newVersion, today)];
430
+ }
431
+ if (isEmptyRange) {
432
+ return [buildEmptyReleaseEntry(newVersion, today)];
433
+ }
434
+ const tagPattern = buildTagPattern(getAllTagPrefixes(workspace));
435
+ return buildChangelogEntries(config, newTag, { tagPattern, includePaths: workspace.paths });
436
+ }
390
437
  function maybeWritePreviews(workspace, newTag, changelogJsonPath, previewOptions, dryRun) {
391
438
  if (!previewOptions.enabled || changelogJsonPath === void 0) {
392
439
  return;
@@ -1,9 +1,12 @@
1
1
  import type { ReleasePrepareOptions } from './releasePrepare.ts';
2
- import type { MonorepoReleaseConfig, ProjectPrepareResult } from './types.ts';
2
+ import type { ChangelogOverride, MonorepoReleaseConfig, ProjectPrepareResult } from './types.ts';
3
3
  export interface ReleasePrepareProjectArgs {
4
4
  config: MonorepoReleaseConfig;
5
5
  options: ReleasePrepareOptions;
6
6
  modifiedFiles: string[];
7
7
  tags: string[];
8
+ rootOverrides?: Map<string, ChangelogOverride>;
9
+ overrideWarnings?: string[];
10
+ globalMatchedRootKeys?: Set<string>;
8
11
  }
9
12
  export declare function releasePrepareProject(args: ReleasePrepareProjectArgs): ProjectPrepareResult;
@@ -1,17 +1,21 @@
1
1
  import { buildChangelogEntries } from "./buildChangelogEntries.js";
2
+ import { buildEmptyReleaseEntry } from "./buildEmptyReleaseEntry.js";
2
3
  import { bumpAllVersions } from "./bumpAllVersions.js";
3
- import { resolveChangelogJsonPath, writeChangelogJson } from "./changelogJsonFile.js";
4
+ import { mergeChangelogEntriesWithDisk, resolveChangelogJsonPath, writeChangelogJson } from "./changelogJsonFile.js";
5
+ import { applyChangelogOverrides } from "./changelogOverrides.js";
4
6
  import { createPolicyViolationCollector } from "./collectPolicyViolations.js";
5
7
  import { decideRelease } from "./decideRelease.js";
6
8
  import { DEFAULT_BREAKING_POLICIES, DEFAULT_VERSION_PATTERNS, DEFAULT_WORK_TYPES } from "./defaults.js";
7
- import { buildTagPattern, generateChangelog } from "./generateChangelogs.js";
9
+ import { buildTagPattern } from "./generateChangelogs.js";
8
10
  import { getCommitsSinceTarget } from "./getCommitsSinceTarget.js";
11
+ import { writeChangelogMarkdown } from "./renderChangelogMarkdown.js";
9
12
  import { deriveSectionOrder } from "./resolveReleaseNotesConfig.js";
10
13
  import { writeReleaseNotesPreviews } from "./writeReleaseNotesPreviews.js";
11
14
  const ROOT_PACKAGE_FILE = "./package.json";
12
15
  const ROOT_CHANGELOG_PATH = ".";
13
16
  function releasePrepareProject(args) {
14
17
  const { config, options, modifiedFiles, tags } = args;
18
+ const { rootOverrides, overrideWarnings, globalMatchedRootKeys } = resolveOptionalOverrideArgs(args);
15
19
  const { dryRun, bumpOverride, withReleaseNotes, force } = options;
16
20
  const project = config.project;
17
21
  if (project === void 0) {
@@ -60,23 +64,18 @@ function releasePrepareProject(args) {
60
64
  const { releaseType, parsedCommitCount, unparseableCommits } = decision;
61
65
  const bump = bumpAllVersions([ROOT_PACKAGE_FILE], releaseType, dryRun);
62
66
  const newTag = `${project.tagPrefix}${bump.newVersion}`;
63
- const tagPattern = buildTagPattern([project.tagPrefix]);
64
- const changelogFiles = generateChangelog(config, ROOT_CHANGELOG_PATH, newTag, dryRun, {
65
- tagPattern,
66
- includePaths: contributingPaths
67
+ const { changelogFiles, changelogJsonFiles } = writeProjectChangelogs({
68
+ config,
69
+ project,
70
+ commits,
71
+ contributingPaths,
72
+ newTag,
73
+ newVersion: bump.newVersion,
74
+ dryRun,
75
+ rootOverrides,
76
+ overrideWarnings,
77
+ globalMatchedRootKeys
67
78
  });
68
- const changelogJsonFiles = [];
69
- if (config.changelogJson.enabled) {
70
- const changelogJsonPath = resolveChangelogJsonPath(config, ROOT_CHANGELOG_PATH);
71
- const entries = buildChangelogEntries(config, newTag, {
72
- tagPattern,
73
- includePaths: contributingPaths
74
- });
75
- if (!dryRun) {
76
- writeChangelogJson(changelogJsonPath, entries);
77
- }
78
- changelogJsonFiles.push(changelogJsonPath);
79
- }
80
79
  const firstChangelogJsonPath = changelogJsonFiles[0];
81
80
  if (withReleaseNotes === true && config.changelogJson.enabled && firstChangelogJsonPath !== void 0) {
82
81
  const sectionOrder = deriveSectionOrder(workTypes);
@@ -116,6 +115,63 @@ function releasePrepareProject(args) {
116
115
  }
117
116
  return result;
118
117
  }
118
+ function resolveOptionalOverrideArgs(args) {
119
+ return {
120
+ rootOverrides: args.rootOverrides ?? /* @__PURE__ */ new Map(),
121
+ overrideWarnings: args.overrideWarnings ?? [],
122
+ globalMatchedRootKeys: args.globalMatchedRootKeys ?? /* @__PURE__ */ new Set()
123
+ };
124
+ }
125
+ function writeProjectChangelogs(args) {
126
+ const {
127
+ config,
128
+ project,
129
+ commits,
130
+ contributingPaths,
131
+ newTag,
132
+ newVersion,
133
+ dryRun,
134
+ rootOverrides,
135
+ overrideWarnings,
136
+ globalMatchedRootKeys
137
+ } = args;
138
+ const isEmptyRange = commits.length === 0;
139
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
140
+ const tagPattern = buildTagPattern([project.tagPrefix]);
141
+ const newEntries = isEmptyRange ? [buildEmptyReleaseEntry(newVersion, today)] : buildChangelogEntries(config, newTag, { tagPattern, includePaths: contributingPaths });
142
+ const applied = applyChangelogOverrides(newEntries, rootOverrides);
143
+ if (applied.errors.length > 0) {
144
+ throw new Error(`Changelog override application failed:
145
+ - ${applied.errors.join("\n - ")}`);
146
+ }
147
+ overrideWarnings.push(...applied.warnings);
148
+ for (const matched of applied.matchedKeys) {
149
+ globalMatchedRootKeys.add(matched);
150
+ }
151
+ const changelogJsonPath = resolveChangelogJsonPath(config, ROOT_CHANGELOG_PATH);
152
+ const sectionOrder = deriveSectionOrder(config.workTypes ?? { ...DEFAULT_WORK_TYPES });
153
+ const renderEntries = isEmptyRange ? mergeChangelogEntriesWithDisk(changelogJsonPath, applied.entries) : applied.entries;
154
+ if (config.changelogJson.enabled && !dryRun) {
155
+ if (isEmptyRange) {
156
+ writeChangelogJson(changelogJsonPath, renderEntries);
157
+ } else {
158
+ writeChangelogJson(changelogJsonPath, applied.entries);
159
+ }
160
+ }
161
+ const changelogFiles = [
162
+ writeChangelogMarkdown({
163
+ changelogPath: ROOT_CHANGELOG_PATH,
164
+ entries: renderEntries,
165
+ sectionOrder,
166
+ dryRun
167
+ })
168
+ ];
169
+ const changelogJsonFiles = [];
170
+ if (config.changelogJson.enabled) {
171
+ changelogJsonFiles.push(changelogJsonPath);
172
+ }
173
+ return { changelogFiles, changelogJsonFiles };
174
+ }
119
175
  export {
120
176
  releasePrepareProject
121
177
  };
@@ -0,0 +1,12 @@
1
+ import type { ChangelogEntry } from './types.ts';
2
+ export interface RenderChangelogMarkdownOptions {
3
+ sectionOrder?: string[];
4
+ }
5
+ export declare function renderChangelogMarkdown(entries: ChangelogEntry[], options?: RenderChangelogMarkdownOptions): string;
6
+ export interface WriteChangelogMarkdownParams {
7
+ changelogPath: string;
8
+ entries: ChangelogEntry[];
9
+ sectionOrder?: string[];
10
+ dryRun?: boolean;
11
+ }
12
+ export declare function writeChangelogMarkdown(params: WriteChangelogMarkdownParams): string;
@@ -0,0 +1,32 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { dirname, join as joinPath } from "node:path";
3
+ import { renderReleaseNotesMulti } from "./renderReleaseNotes.js";
4
+ const CHANGELOG_HEADER = `# Changelog
5
+
6
+ All notable changes to this project will be documented in this file.`;
7
+ const CHANGELOG_FOOTER = `<!-- Generated by release-kit. Do not edit this file. Use .meta/changelog-overrides.json to override entries. -->`;
8
+ function renderChangelogMarkdown(entries, options) {
9
+ const body = renderReleaseNotesMulti(entries, options);
10
+ const trimmedBody = body.trimEnd();
11
+ const parts = [CHANGELOG_HEADER];
12
+ if (trimmedBody.length > 0) {
13
+ parts.push(trimmedBody);
14
+ }
15
+ parts.push(CHANGELOG_FOOTER);
16
+ return parts.join("\n\n") + "\n";
17
+ }
18
+ function writeChangelogMarkdown(params) {
19
+ const { changelogPath, entries, sectionOrder, dryRun = false } = params;
20
+ const filePath = joinPath(changelogPath, "CHANGELOG.md");
21
+ if (dryRun) {
22
+ return filePath;
23
+ }
24
+ const rendered = renderChangelogMarkdown(entries, sectionOrder !== void 0 ? { sectionOrder } : void 0);
25
+ mkdirSync(dirname(filePath), { recursive: true });
26
+ writeFileSync(filePath, rendered, "utf8");
27
+ return filePath;
28
+ }
29
+ export {
30
+ renderChangelogMarkdown,
31
+ writeChangelogMarkdown
32
+ };
@@ -1,3 +1,8 @@
1
+ import { WORK_TYPES_DATA } from "./workTypesData.js";
2
+ function getBreakingPrefix() {
3
+ const { emoji, label } = WORK_TYPES_DATA.markers.breaking;
4
+ return `${emoji} **${label}:** `;
5
+ }
1
6
  function allSections() {
2
7
  return true;
3
8
  }
@@ -26,7 +31,7 @@ function renderReleaseNotesSingle(entry, options) {
26
31
  }
27
32
  lines.push(`### ${section.title}`, "");
28
33
  for (const [index, item] of section.items.entries()) {
29
- const prefix = item.breaking === true ? "\u{1F6A8} **Breaking:** " : "";
34
+ const prefix = item.breaking === true ? getBreakingPrefix() : "";
30
35
  lines.push(`- ${prefix}${item.description}`);
31
36
  if (item.body !== void 0 && item.body.length > 0) {
32
37
  lines.push("", ...indentBodyLines(item.body));
@@ -33,7 +33,9 @@ async function resolveReleaseNotesConfig(options = {}) {
33
33
  console.warn(` \u26A0\uFE0F ${warning}`);
34
34
  }
35
35
  return {
36
- releaseNotes: { ...DEFAULT_RELEASE_NOTES_CONFIG, ...config.releaseNotes },
36
+ releaseNotes: {
37
+ shouldInjectIntoReadme: config.releaseNotes?.shouldInjectIntoReadme ?? DEFAULT_RELEASE_NOTES_CONFIG.shouldInjectIntoReadme
38
+ },
37
39
  changelogJsonOutputPath: config.changelogJson?.outputPath ?? DEFAULT_CHANGELOG_JSON_CONFIG.outputPath,
38
40
  sectionOrder: deriveSectionOrder(resolveWorkTypes(config.workTypes))
39
41
  };
@@ -1,2 +1,3 @@
1
1
  import { type StdioOptions } from 'node:child_process';
2
2
  export declare function runGitCliff(cliffConfigPath: string, cliffArgs: readonly string[], stdio: StdioOptions): string;
3
+ export declare function refreshGitCliffCache(): void;
@@ -22,6 +22,13 @@ function runGitCliff(cliffConfigPath, cliffArgs, stdio) {
22
22
  }
23
23
  }
24
24
  }
25
+ function refreshGitCliffCache() {
26
+ execFileSync("npx", ["--yes", "git-cliff", "--version"], {
27
+ stdio: ["ignore", "pipe", "inherit"],
28
+ env: { ...process.env, npm_config_progress: "false" }
29
+ });
30
+ }
25
31
  export {
32
+ refreshGitCliffCache,
26
33
  runGitCliff
27
34
  };
@@ -3,7 +3,7 @@ import { dirname, resolve } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { UPSTREAM_WORK_TYPES_URL } from "./checkWorkTypesDrift.js";
5
5
  import { isRecord } from "./typeGuards.js";
6
- import { errorMessage, hasExpectedTopLevelShape } from "./workTypesUtils.js";
6
+ import { buildFetchInit, errorMessage, hasExpectedTopLevelShape } from "./workTypesUtils.js";
7
7
  function resolveDefaultLocalPath() {
8
8
  const moduleDir = dirname(fileURLToPath(import.meta.url));
9
9
  return resolve(moduleDir, "work-types.json");
@@ -25,9 +25,10 @@ async function syncWorkTypes(dependencies = {}) {
25
25
  const localPath = dependencies.localPath ?? resolveDefaultLocalPath();
26
26
  const fetcher = dependencies.fetch ?? globalThis.fetch;
27
27
  const url = dependencies.upstreamUrl ?? UPSTREAM_WORK_TYPES_URL;
28
+ const fetchInit = buildFetchInit();
28
29
  let response;
29
30
  try {
30
- response = await fetcher(url);
31
+ response = fetchInit === void 0 ? await fetcher(url) : await fetcher(url, fetchInit);
31
32
  } catch (error) {
32
33
  return {
33
34
  exitCode: 2,