@williamthorsen/release-kit 10.2.1 → 10.2.2

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 (39) hide show
  1. package/.readyup/kits/default.js +1 -1
  2. package/.readyup/kits/npm-auto-publish.js +135 -23
  3. package/.readyup/manifest.json +3 -3
  4. package/CHANGELOG.md +22 -0
  5. package/README.md +13 -3
  6. package/dist/esm/buildChangelogEntries.js +1 -1
  7. package/dist/esm/buildReleaseSummary.d.ts +1 -1
  8. package/dist/esm/changelogJsonFile.d.ts +1 -3
  9. package/dist/esm/changelogJsonFile.js +4 -18
  10. package/dist/esm/commitCommand.js +3 -13
  11. package/dist/esm/createTags.js +2 -13
  12. package/dist/esm/injectReleaseNotesIntoReadme.d.ts +2 -0
  13. package/dist/esm/injectReleaseNotesIntoReadme.js +13 -10
  14. package/dist/esm/planReleaseNotesPreviews.d.ts +13 -0
  15. package/dist/esm/planReleaseNotesPreviews.js +43 -0
  16. package/dist/esm/planVersionBump.d.ts +9 -0
  17. package/dist/esm/{bumpAllVersions.js → planVersionBump.js} +15 -26
  18. package/dist/esm/prepareCommand.d.ts +0 -4
  19. package/dist/esm/prepareCommand.js +51 -45
  20. package/dist/esm/releaseFiles.d.ts +4 -0
  21. package/dist/esm/releaseFiles.js +34 -0
  22. package/dist/esm/releasePlan.d.ts +10 -0
  23. package/dist/esm/releasePlan.js +53 -0
  24. package/dist/esm/releasePrepare.d.ts +3 -3
  25. package/dist/esm/releasePrepare.js +53 -54
  26. package/dist/esm/releasePrepareMono.d.ts +3 -2
  27. package/dist/esm/releasePrepareMono.js +48 -52
  28. package/dist/esm/releasePrepareProject.d.ts +3 -0
  29. package/dist/esm/releasePrepareProject.js +33 -37
  30. package/dist/esm/renderChangelogMarkdown.d.ts +0 -7
  31. package/dist/esm/renderChangelogMarkdown.js +0 -13
  32. package/dist/esm/reportPrepare.d.ts +5 -1
  33. package/dist/esm/reportPrepare.js +36 -17
  34. package/dist/esm/types.d.ts +4 -9
  35. package/dist/esm/workTypesData.d.ts +1 -1
  36. package/package.json +2 -2
  37. package/dist/esm/bumpAllVersions.d.ts +0 -3
  38. package/dist/esm/writeReleaseNotesPreviews.d.ts +0 -18
  39. package/dist/esm/writeReleaseNotesPreviews.js +0 -63
@@ -1,10 +1,10 @@
1
- import { execSync } from 'node:child_process';
1
+ import { join as joinPath } from 'node:path';
2
2
  import { buildChangelogEntries } from "./buildChangelogEntries.js";
3
3
  import { buildDependencyGraph } from "./buildDependencyGraph.js";
4
4
  import { buildEmptyReleaseEntry } from "./buildEmptyReleaseEntry.js";
5
+ import { buildReleaseSummary } from "./buildReleaseSummary.js";
5
6
  import { buildSyntheticChangelogEntry } from "./buildSyntheticChangelogEntry.js";
6
- import { bumpAllVersions, setAllVersions } from "./bumpAllVersions.js";
7
- import { mergeChangelogEntriesWithDisk, resolveChangelogJsonPath, upsertChangelogJsonAndReturn, } from "./changelogJsonFile.js";
7
+ import { mergeChangelogEntriesWithDisk, renderChangelogJson, resolveChangelogJsonPath } from "./changelogJsonFile.js";
8
8
  import { applyWorkspaceOverrides, createOverrideContext, formatStaleOverrideKeyWarning, } from "./changelogOverrides.js";
9
9
  import { createPolicyViolationCollector } from "./collectPolicyViolations.js";
10
10
  import { isForwardVersion } from "./compareVersions.js";
@@ -15,15 +15,17 @@ import { buildTagPattern, getAllTagPrefixes } from "./generateChangelogs.js";
15
15
  import { getCommitsSinceTarget } from "./getCommitsSinceTarget.js";
16
16
  import { hasPrettierConfig } from "./hasPrettierConfig.js";
17
17
  import { resolveWorkTypes } from "./loadConfig.js";
18
+ import { planReleaseNotesPreviews } from "./planReleaseNotesPreviews.js";
19
+ import { planVersionBump, planVersionSet } from "./planVersionBump.js";
18
20
  import { propagateBumps } from "./propagateBumps.js";
19
21
  import { readCurrentVersion } from "./readCurrentVersion.js";
20
22
  import { releasePrepareProject } from "./releasePrepareProject.js";
21
- import { writeChangelogMarkdown } from "./renderChangelogMarkdown.js";
23
+ import { renderChangelogMarkdown } from "./renderChangelogMarkdown.js";
22
24
  import { deriveSectionOrder } from "./resolveReleaseNotesConfig.js";
23
25
  import { refreshGitCliffCache } from "./runGitCliff.js";
24
- import { writeReleaseNotesPreviews } from "./writeReleaseNotesPreviews.js";
25
26
  export function releasePrepareMono(config, options) {
26
- const { dryRun, withReleaseNotes } = options;
27
+ const { withReleaseNotes } = options;
28
+ const writes = [];
27
29
  if (withReleaseNotes === true && !config.changelogJson.enabled) {
28
30
  console.warn('Warning: --with-release-notes requires changelogJson.enabled; skipping preview generation');
29
31
  }
@@ -59,7 +61,8 @@ export function releasePrepareMono(config, options) {
59
61
  config,
60
62
  directResults,
61
63
  previousTags,
62
- dryRun,
64
+ writes,
65
+ warnings,
63
66
  workspaces,
64
67
  previewOptions,
65
68
  overrideContext,
@@ -77,13 +80,15 @@ export function releasePrepareMono(config, options) {
77
80
  config,
78
81
  options,
79
82
  modifiedFiles,
83
+ writes,
80
84
  tags,
85
+ warnings,
81
86
  rootOverrides: overrideContext.project,
82
87
  overrideWarnings: overrideContext.overrideWarnings,
83
88
  globalMatchedRootKeys: overrideContext.globalMatchedRootKeys,
84
89
  }));
85
90
  }
86
- const formatCommand = runFormatCommand(config, tags, modifiedFiles, dryRun);
91
+ const formatCommand = planFormatCommand(config, tags, modifiedFiles);
87
92
  for (const overrideKey of overrideContext.project.keys()) {
88
93
  if (!overrideContext.globalMatchedRootKeys.has(overrideKey)) {
89
94
  overrideContext.overrideWarnings.push(formatStaleOverrideKeyWarning(overrideKey));
@@ -93,8 +98,9 @@ export function releasePrepareMono(config, options) {
93
98
  return {
94
99
  workspaces,
95
100
  tags,
101
+ writes,
102
+ summary: buildReleaseSummary({ workspaces, ...(project !== undefined && { project }) }),
96
103
  formatCommand,
97
- dryRun,
98
104
  ...(allWarnings.length > 0 && { warnings: allWarnings }),
99
105
  ...(project !== undefined && { project }),
100
106
  };
@@ -221,7 +227,7 @@ function collectSkippedWorkspaces(skippedResults, fullReleaseSet) {
221
227
  return workspaces;
222
228
  }
223
229
  function executeReleaseSet(args) {
224
- const { sortedDirs, fullReleaseSet, config, directResults, previousTags, dryRun, workspaces, previewOptions, overrideContext, sectionOrder, } = args;
230
+ const { sortedDirs, fullReleaseSet, config, directResults, previousTags, writes, warnings, workspaces, previewOptions, overrideContext, sectionOrder, } = args;
225
231
  const tags = [];
226
232
  const modifiedFiles = [];
227
233
  const today = new Date().toISOString().slice(0, 10);
@@ -241,10 +247,11 @@ function executeReleaseSet(args) {
241
247
  directResult: directResults.get(dir),
242
248
  previousTags,
243
249
  config,
244
- dryRun,
245
250
  today,
246
251
  tags,
247
252
  modifiedFiles,
253
+ writes,
254
+ warnings,
248
255
  workspaces,
249
256
  previewOptions,
250
257
  overrideContext,
@@ -254,17 +261,18 @@ function executeReleaseSet(args) {
254
261
  return { tags, modifiedFiles };
255
262
  }
256
263
  function executeWorkspaceRelease(args) {
257
- const { dir, workspace, releaseEntry, directResult, previousTags, config, dryRun, today, tags, modifiedFiles, workspaces, previewOptions, overrideContext, sectionOrder, } = args;
264
+ const { dir, workspace, releaseEntry, directResult, previousTags, config, today, tags, modifiedFiles, writes, warnings, workspaces, previewOptions, overrideContext, sectionOrder, } = args;
258
265
  const setVersionTarget = directResult?.setVersion;
259
266
  const bump = setVersionTarget === undefined
260
- ? bumpAllVersions(workspace.packageFiles, releaseEntry.releaseType, dryRun)
261
- : setAllVersions(workspace.packageFiles, setVersionTarget, dryRun);
267
+ ? planVersionBump(workspace.packageFiles, releaseEntry.releaseType)
268
+ : planVersionSet(workspace.packageFiles, setVersionTarget);
262
269
  const newTag = `${workspace.tagPrefix}${bump.newVersion}`;
263
270
  tags.push(newTag);
264
- modifiedFiles.push(...workspace.packageFiles, ...workspace.changelogPaths.map((p) => `${p}/CHANGELOG.md`));
271
+ writes.push(...bump.writes);
272
+ modifiedFiles.push(...workspace.packageFiles, ...workspace.changelogPaths.map((changelogPath) => joinPath(changelogPath, 'CHANGELOG.md')));
265
273
  const isPropagationOnly = directResult === undefined;
266
274
  const isEmptyRange = directResult !== undefined && directResult.commits.length === 0;
267
- const changelogFiles = generateWorkspaceChangelogs({
275
+ const { changelogFiles, previewFiles } = generateWorkspaceChangelogs({
268
276
  workspace,
269
277
  releaseEntry,
270
278
  newTag,
@@ -272,9 +280,10 @@ function executeWorkspaceRelease(args) {
272
280
  isPropagationOnly,
273
281
  isEmptyRange,
274
282
  config,
275
- dryRun,
276
283
  today,
277
284
  modifiedFiles,
285
+ writes,
286
+ warnings,
278
287
  previewOptions,
279
288
  overrideContext,
280
289
  sectionOrder,
@@ -286,8 +295,9 @@ function executeWorkspaceRelease(args) {
286
295
  currentVersion: bump.currentVersion,
287
296
  newVersion: bump.newVersion,
288
297
  tag: newTag,
289
- bumpedFiles: bump.files,
298
+ bumpedFiles: bump.writes.map((write) => write.path),
290
299
  changelogFiles,
300
+ ...(previewFiles.length > 0 && { previewFiles }),
291
301
  };
292
302
  attachReleasedWorkspaceOptionals(released, {
293
303
  previousTag: directResult?.tag ?? previousTags.get(dir),
@@ -328,7 +338,7 @@ function attachReleasedWorkspaceOptionals(released, args) {
328
338
  }
329
339
  }
330
340
  function generateWorkspaceChangelogs(args) {
331
- const { workspace, releaseEntry, newTag, newVersion, isPropagationOnly, isEmptyRange, config, dryRun, today, modifiedFiles, previewOptions, overrideContext, sectionOrder, } = args;
341
+ const { workspace, releaseEntry, newTag, newVersion, isPropagationOnly, isEmptyRange, config, today, modifiedFiles, writes, warnings, previewOptions, overrideContext, sectionOrder, } = args;
332
342
  const newEntries = buildWorkspaceEntries({
333
343
  workspace,
334
344
  releaseEntry,
@@ -341,26 +351,22 @@ function generateWorkspaceChangelogs(args) {
341
351
  });
342
352
  const applied = applyWorkspaceOverrides(newEntries, workspace.workspacePath, overrideContext);
343
353
  const changelogFiles = [];
344
- let firstChangelogJsonPath;
354
+ let firstMergedEntries;
345
355
  for (const changelogPath of workspace.changelogPaths) {
346
356
  const jsonPath = resolveChangelogJsonPath(config, changelogPath);
347
- const shouldWriteJson = config.changelogJson.enabled && !dryRun;
348
- const mergedEntries = shouldWriteJson
349
- ? upsertChangelogJsonAndReturn(jsonPath, applied.entries)
350
- : mergeChangelogEntriesWithDisk(jsonPath, applied.entries);
357
+ const mergedEntries = mergeChangelogEntriesWithDisk(jsonPath, applied.entries);
351
358
  if (config.changelogJson.enabled) {
359
+ writes.push({ path: jsonPath, content: renderChangelogJson(mergedEntries) });
352
360
  modifiedFiles.push(jsonPath);
353
- firstChangelogJsonPath ??= jsonPath;
361
+ firstMergedEntries ??= mergedEntries;
354
362
  }
355
- changelogFiles.push(writeChangelogMarkdown({
356
- changelogPath,
357
- entries: mergedEntries,
358
- sectionOrder,
359
- dryRun,
360
- }));
363
+ const changelogFile = joinPath(changelogPath, 'CHANGELOG.md');
364
+ writes.push({ path: changelogFile, content: renderChangelogMarkdown(mergedEntries, { sectionOrder }) });
365
+ changelogFiles.push(changelogFile);
361
366
  }
362
- maybeWritePreviews(workspace, newTag, firstChangelogJsonPath, previewOptions, dryRun);
363
- return changelogFiles;
367
+ const previews = planPreviews(workspace, newTag, firstMergedEntries, previewOptions, warnings);
368
+ writes.push(...previews);
369
+ return { changelogFiles, previewFiles: previews.map((write) => write.path) };
364
370
  }
365
371
  function buildWorkspaceEntries(args) {
366
372
  const { workspace, releaseEntry, newTag, newVersion, isPropagationOnly, isEmptyRange, config, today } = args;
@@ -373,35 +379,25 @@ function buildWorkspaceEntries(args) {
373
379
  const tagPattern = buildTagPattern(getAllTagPrefixes(workspace));
374
380
  return buildChangelogEntries(config, newTag, { tagPattern, includePaths: workspace.paths });
375
381
  }
376
- function maybeWritePreviews(workspace, newTag, changelogJsonPath, previewOptions, dryRun) {
377
- if (!previewOptions.enabled || changelogJsonPath === undefined) {
378
- return;
382
+ function planPreviews(workspace, newTag, entries, previewOptions, warnings) {
383
+ if (!previewOptions.enabled || entries === undefined) {
384
+ return [];
379
385
  }
380
- writeReleaseNotesPreviews({
386
+ const previews = planReleaseNotesPreviews({
381
387
  workspacePath: workspace.workspacePath,
382
388
  tag: newTag,
383
- changelogJsonPath,
389
+ entries,
384
390
  sectionOrder: previewOptions.sectionOrder,
385
- dryRun,
386
391
  });
392
+ warnings.push(...previews.warnings);
393
+ return previews.writes;
387
394
  }
388
- function runFormatCommand(config, tags, modifiedFiles, dryRun) {
395
+ function planFormatCommand(config, tags, modifiedFiles) {
389
396
  const formatCommandStr = config.formatCommand ?? (hasPrettierConfig() ? 'npx prettier --write' : undefined);
390
397
  if (tags.length === 0 || formatCommandStr === undefined) {
391
398
  return undefined;
392
399
  }
393
- const fullCommand = `${formatCommandStr} ${modifiedFiles.join(' ')}`;
394
- if (dryRun) {
395
- return { command: fullCommand, executed: false, files: modifiedFiles };
396
- }
397
- try {
398
- execSync(fullCommand, { stdio: 'inherit' });
399
- }
400
- catch (error) {
401
- const baseMessage = error instanceof Error ? error.message : String(error);
402
- throw new Error(`format stage: ${baseMessage} (command: '${fullCommand}')`, { cause: error });
403
- }
404
- return { command: fullCommand, executed: true, files: modifiedFiles };
400
+ return { command: `${formatCommandStr} ${modifiedFiles.join(' ')}`, files: modifiedFiles };
405
401
  }
406
402
  function findWorkspace(workspaces, dir) {
407
403
  return workspaces.find((w) => w.dir === dir);
@@ -1,10 +1,13 @@
1
+ import type { PlannedWrite } from './releasePlan.js';
1
2
  import type { ReleasePrepareOptions } from './releasePrepare.js';
2
3
  import type { ChangelogOverride, MonorepoReleaseConfig, ProjectPrepareResult } from './types.js';
3
4
  export interface ReleasePrepareProjectArgs {
4
5
  config: MonorepoReleaseConfig;
5
6
  options: ReleasePrepareOptions;
6
7
  modifiedFiles: string[];
8
+ writes: PlannedWrite[];
7
9
  tags: string[];
10
+ warnings?: string[];
8
11
  rootOverrides?: Map<string, ChangelogOverride>;
9
12
  overrideWarnings?: string[];
10
13
  globalMatchedRootKeys?: Set<string>;
@@ -1,22 +1,23 @@
1
+ import { join as joinPath } from 'node:path';
1
2
  import { buildChangelogEntries } from "./buildChangelogEntries.js";
2
3
  import { buildEmptyReleaseEntry } from "./buildEmptyReleaseEntry.js";
3
- import { bumpAllVersions } from "./bumpAllVersions.js";
4
- import { mergeChangelogEntriesWithDisk, resolveChangelogJsonPath, writeChangelogJson } from "./changelogJsonFile.js";
4
+ import { mergeChangelogEntriesWithDisk, renderChangelogJson, resolveChangelogJsonPath } from "./changelogJsonFile.js";
5
5
  import { applyChangelogOverrides } from "./changelogOverrides.js";
6
6
  import { createPolicyViolationCollector } from "./collectPolicyViolations.js";
7
7
  import { decideRelease } from "./decideRelease.js";
8
8
  import { DEFAULT_BREAKING_POLICIES, DEFAULT_VERSION_PATTERNS, DEFAULT_WORK_TYPES } from "./defaults.js";
9
9
  import { buildTagPattern } from "./generateChangelogs.js";
10
10
  import { getCommitsSinceTarget } from "./getCommitsSinceTarget.js";
11
- import { writeChangelogMarkdown } from "./renderChangelogMarkdown.js";
11
+ import { planReleaseNotesPreviews } from "./planReleaseNotesPreviews.js";
12
+ import { planVersionBump } from "./planVersionBump.js";
13
+ import { renderChangelogMarkdown } from "./renderChangelogMarkdown.js";
12
14
  import { deriveSectionOrder } from "./resolveReleaseNotesConfig.js";
13
- import { writeReleaseNotesPreviews } from "./writeReleaseNotesPreviews.js";
14
15
  const ROOT_PACKAGE_FILE = './package.json';
15
16
  const ROOT_CHANGELOG_PATH = '.';
16
17
  export function releasePrepareProject(args) {
17
- const { config, options, modifiedFiles, tags } = args;
18
- const { rootOverrides, overrideWarnings, globalMatchedRootKeys } = resolveOptionalOverrideArgs(args);
19
- const { dryRun, bumpOverride, withReleaseNotes, force } = options;
18
+ const { config, options, modifiedFiles, writes, tags } = args;
19
+ const { rootOverrides, overrideWarnings, globalMatchedRootKeys, warnings } = resolveOptionalOverrideArgs(args);
20
+ const { bumpOverride, withReleaseNotes, force } = options;
20
21
  const project = config.project;
21
22
  if (project === undefined) {
22
23
  throw new Error('releasePrepareProject called without a configured project block');
@@ -62,30 +63,33 @@ export function releasePrepareProject(args) {
62
63
  return skipped;
63
64
  }
64
65
  const { releaseType, parsedCommitCount, unparseableCommits } = decision;
65
- const bump = bumpAllVersions([ROOT_PACKAGE_FILE], releaseType, dryRun);
66
+ const bump = planVersionBump([ROOT_PACKAGE_FILE], releaseType);
67
+ writes.push(...bump.writes);
66
68
  const newTag = `${project.tagPrefix}${bump.newVersion}`;
67
- const { changelogFiles, changelogJsonFiles } = writeProjectChangelogs({
69
+ const changelogs = planProjectChangelogs({
68
70
  config,
69
71
  project,
70
72
  commits,
71
73
  contributingPaths,
72
74
  newTag,
73
75
  newVersion: bump.newVersion,
74
- dryRun,
75
76
  rootOverrides,
76
77
  overrideWarnings,
77
78
  globalMatchedRootKeys,
78
79
  });
79
- const firstChangelogJsonPath = changelogJsonFiles[0];
80
- if (withReleaseNotes === true && config.changelogJson.enabled && firstChangelogJsonPath !== undefined) {
81
- const sectionOrder = deriveSectionOrder(workTypes);
82
- writeReleaseNotesPreviews({
80
+ const { changelogFiles, changelogJsonFiles } = changelogs;
81
+ writes.push(...changelogs.writes);
82
+ const previewFiles = [];
83
+ if (withReleaseNotes === true && config.changelogJson.enabled && changelogJsonFiles.length > 0) {
84
+ const previews = planReleaseNotesPreviews({
83
85
  workspacePath: ROOT_CHANGELOG_PATH,
84
86
  tag: newTag,
85
- changelogJsonPath: firstChangelogJsonPath,
86
- sectionOrder,
87
- dryRun,
87
+ entries: changelogs.entries,
88
+ sectionOrder: deriveSectionOrder(workTypes),
88
89
  });
90
+ writes.push(...previews.writes);
91
+ warnings.push(...previews.warnings);
92
+ previewFiles.push(...previews.writes.map((write) => write.path));
89
93
  }
90
94
  tags.push(newTag);
91
95
  modifiedFiles.push(ROOT_PACKAGE_FILE, ...changelogFiles, ...changelogJsonFiles);
@@ -97,10 +101,13 @@ export function releasePrepareProject(args) {
97
101
  currentVersion: bump.currentVersion,
98
102
  newVersion: bump.newVersion,
99
103
  tag: newTag,
100
- bumpedFiles: bump.files,
104
+ bumpedFiles: bump.writes.map((write) => write.path),
101
105
  changelogFiles,
102
106
  commits,
103
107
  };
108
+ if (previewFiles.length > 0) {
109
+ result.previewFiles = previewFiles;
110
+ }
104
111
  if (tag !== undefined) {
105
112
  result.previousTag = tag;
106
113
  }
@@ -120,10 +127,11 @@ function resolveOptionalOverrideArgs(args) {
120
127
  rootOverrides: args.rootOverrides ?? new Map(),
121
128
  overrideWarnings: args.overrideWarnings ?? [],
122
129
  globalMatchedRootKeys: args.globalMatchedRootKeys ?? new Set(),
130
+ warnings: args.warnings ?? [],
123
131
  };
124
132
  }
125
- function writeProjectChangelogs(args) {
126
- const { config, project, commits, contributingPaths, newTag, newVersion, dryRun, rootOverrides, overrideWarnings, globalMatchedRootKeys, } = args;
133
+ function planProjectChangelogs(args) {
134
+ const { config, project, commits, contributingPaths, newTag, newVersion, rootOverrides, overrideWarnings, globalMatchedRootKeys, } = args;
127
135
  const isEmptyRange = commits.length === 0;
128
136
  const today = new Date().toISOString().slice(0, 10);
129
137
  const tagPattern = buildTagPattern([project.tagPrefix]);
@@ -143,25 +151,13 @@ function writeProjectChangelogs(args) {
143
151
  const renderEntries = isEmptyRange
144
152
  ? mergeChangelogEntriesWithDisk(changelogJsonPath, applied.entries)
145
153
  : applied.entries;
146
- if (config.changelogJson.enabled && !dryRun) {
147
- if (isEmptyRange) {
148
- writeChangelogJson(changelogJsonPath, renderEntries);
149
- }
150
- else {
151
- writeChangelogJson(changelogJsonPath, applied.entries);
152
- }
153
- }
154
- const changelogFiles = [
155
- writeChangelogMarkdown({
156
- changelogPath: ROOT_CHANGELOG_PATH,
157
- entries: renderEntries,
158
- sectionOrder,
159
- dryRun,
160
- }),
161
- ];
154
+ const writes = [];
162
155
  const changelogJsonFiles = [];
163
156
  if (config.changelogJson.enabled) {
157
+ writes.push({ path: changelogJsonPath, content: renderChangelogJson(renderEntries) });
164
158
  changelogJsonFiles.push(changelogJsonPath);
165
159
  }
166
- return { changelogFiles, changelogJsonFiles };
160
+ const changelogFile = joinPath(ROOT_CHANGELOG_PATH, 'CHANGELOG.md');
161
+ writes.push({ path: changelogFile, content: renderChangelogMarkdown(renderEntries, { sectionOrder }) });
162
+ return { changelogFiles: [changelogFile], changelogJsonFiles, entries: renderEntries, writes };
167
163
  }
@@ -3,10 +3,3 @@ export interface RenderChangelogMarkdownOptions {
3
3
  sectionOrder?: string[];
4
4
  }
5
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;
@@ -1,5 +1,3 @@
1
- import { mkdirSync, writeFileSync } from 'node:fs';
2
- import { dirname, join as joinPath } from 'node:path';
3
1
  import { renderReleaseNotesMulti } from "./renderReleaseNotes.js";
4
2
  const CHANGELOG_HEADER = `# Changelog
5
3
 
@@ -15,14 +13,3 @@ export function renderChangelogMarkdown(entries, options) {
15
13
  parts.push(CHANGELOG_FOOTER);
16
14
  return parts.join('\n\n') + '\n';
17
15
  }
18
- export 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 !== undefined ? { sectionOrder } : undefined);
25
- mkdirSync(dirname(filePath), { recursive: true });
26
- writeFileSync(filePath, rendered, 'utf8');
27
- return filePath;
28
- }
@@ -1,2 +1,6 @@
1
1
  import type { PrepareResult } from './types.js';
2
- export declare function reportPrepare(result: PrepareResult): string;
2
+ export interface ReportPrepareOptions {
3
+ applied: boolean;
4
+ formatError?: string;
5
+ }
6
+ export declare function reportPrepare(plan: PrepareResult, options: ReportPrepareOptions): string;
@@ -1,12 +1,13 @@
1
1
  import { bold, dim, sectionHeader } from "./format.js";
2
- export function reportPrepare(result) {
3
- const isMultiWorkspace = result.workspaces.some((w) => w.name !== undefined) || result.project !== undefined;
2
+ export function reportPrepare(plan, options) {
3
+ const isMultiWorkspace = plan.workspaces.some((w) => w.name !== undefined) || plan.project !== undefined;
4
4
  if (isMultiWorkspace) {
5
- return formatMultiWorkspace(result);
5
+ return formatMultiWorkspace(plan, options);
6
6
  }
7
- return formatSingleWorkspace(result);
7
+ return formatSingleWorkspace(plan, options);
8
8
  }
9
- function formatSingleWorkspace(result) {
9
+ function formatSingleWorkspace(result, options) {
10
+ const dryRun = !options.applied;
10
11
  const lines = [];
11
12
  const workspace = result.workspaces[0];
12
13
  if (workspace === undefined) {
@@ -41,22 +42,25 @@ function formatSingleWorkspace(result) {
41
42
  else if (workspace.releaseType !== undefined) {
42
43
  lines.push(`📦 ${workspace.currentVersion} → ${bold(workspace.newVersion)} (${workspace.releaseType})`);
43
44
  }
44
- formatBumpFiles(lines, workspace, result.dryRun);
45
+ formatBumpFiles(lines, workspace, dryRun);
45
46
  lines.push(dim('Generating changelogs...'));
46
- formatChangelogFiles(lines, workspace, result.dryRun);
47
- formatFormatCommand(lines, result);
47
+ formatChangelogFiles(lines, workspace, dryRun);
48
+ formatPreviewFiles(lines, workspace, dryRun);
49
+ formatFormatCommand(lines, result, options);
50
+ formatWarnings(lines, result);
48
51
  lines.push(`✅ Release preparation complete.`, ` 🏷️ ${bold(workspace.tag)}`);
49
52
  return lines.join('\n');
50
53
  }
51
- function formatMultiWorkspace(result) {
54
+ function formatMultiWorkspace(result, options) {
55
+ const dryRun = !options.applied;
52
56
  const lines = [];
53
57
  for (const workspace of result.workspaces) {
54
- formatWorkspaceSection(lines, workspace, result.dryRun);
58
+ formatWorkspaceSection(lines, workspace, dryRun);
55
59
  }
56
60
  if (result.project !== undefined) {
57
- formatProjectSection(lines, result.project, result.dryRun);
61
+ formatProjectSection(lines, result.project, dryRun);
58
62
  }
59
- formatFormatCommand(lines, result);
63
+ formatFormatCommand(lines, result, options);
60
64
  formatWarnings(lines, result);
61
65
  if (result.tags.length > 0) {
62
66
  lines.push(`\n✅ Release preparation complete.`);
@@ -104,6 +108,7 @@ function formatProjectSection(lines, project, dryRun) {
104
108
  lines.push(dim(` Generating changelog: ${file}`));
105
109
  }
106
110
  }
111
+ formatPreviewFiles(lines, project, dryRun, ' ');
107
112
  lines.push(` 🏷️ ${bold(tag)}`);
108
113
  }
109
114
  function formatProjectUnparseable(lines, project) {
@@ -141,6 +146,7 @@ function formatWorkspaceSection(lines, workspace, dryRun) {
141
146
  formatBumpFiles(lines, workspace, dryRun, ' ');
142
147
  lines.push(dim(' Generating changelogs...'));
143
148
  formatChangelogFiles(lines, workspace, dryRun, ' ');
149
+ formatPreviewFiles(lines, workspace, dryRun, ' ');
144
150
  lines.push(` 🏷️ ${bold(workspace.tag)}`);
145
151
  }
146
152
  function formatCommitSummary(lines, workspace, propagatedFrom, isPropagatedOnly) {
@@ -195,6 +201,16 @@ function formatChangelogFiles(lines, workspace, dryRun, indent = '') {
195
201
  }
196
202
  }
197
203
  }
204
+ function formatPreviewFiles(lines, release, dryRun, indent = '') {
205
+ for (const file of release.previewFiles ?? []) {
206
+ if (dryRun) {
207
+ lines.push(dim(`${indent} [dry-run] Would write ${file}`));
208
+ }
209
+ else {
210
+ lines.push(dim(`${indent} Wrote ${file}`));
211
+ }
212
+ }
213
+ }
198
214
  function formatUnparseableWarning(lines, workspace, indent = '') {
199
215
  const unparseable = workspace.unparseableCommits;
200
216
  if (unparseable === undefined || unparseable.length === 0) {
@@ -240,14 +256,17 @@ function formatWarnings(lines, result) {
240
256
  lines.push(`⚠️ ${warning}`);
241
257
  }
242
258
  }
243
- function formatFormatCommand(lines, result) {
259
+ function formatFormatCommand(lines, result, options) {
244
260
  if (result.formatCommand === undefined) {
245
261
  return;
246
262
  }
247
- if (result.formatCommand.executed) {
248
- lines.push(dim(`\n Running format command: ${result.formatCommand.command}`));
249
- }
250
- else {
263
+ if (!options.applied) {
251
264
  lines.push(dim(`\n [dry-run] Would run format command: ${result.formatCommand.command}`));
265
+ return;
266
+ }
267
+ if (options.formatError === undefined) {
268
+ lines.push(dim(`\n Running format command: ${result.formatCommand.command}`));
269
+ return;
252
270
  }
271
+ lines.push(`\n ⚠️ Format command failed: ${result.formatCommand.command}`, ` ${options.formatError}`);
253
272
  }
@@ -39,11 +39,6 @@ export interface PropagationSource {
39
39
  packageName: string;
40
40
  newVersion: string;
41
41
  }
42
- export interface BumpResult {
43
- currentVersion: string;
44
- newVersion: string;
45
- files: string[];
46
- }
47
42
  export interface PolicyViolation {
48
43
  commitHash: string;
49
44
  commitSubject: string;
@@ -64,6 +59,7 @@ export interface ReleasedWorkspaceResult {
64
59
  tag: string;
65
60
  bumpedFiles: string[];
66
61
  changelogFiles: string[];
62
+ previewFiles?: string[];
67
63
  commits?: Commit[];
68
64
  bumpOverride?: ReleaseType;
69
65
  propagatedFrom?: PropagationSource[];
@@ -93,6 +89,7 @@ export interface ReleasedProjectResult {
93
89
  tag: string;
94
90
  bumpedFiles: string[];
95
91
  changelogFiles: string[];
92
+ previewFiles?: string[];
96
93
  commits: Commit[];
97
94
  bumpOverride?: ReleaseType;
98
95
  }
@@ -111,10 +108,8 @@ export interface PrepareResult {
111
108
  tags: string[];
112
109
  formatCommand?: {
113
110
  command: string;
114
- executed: boolean;
115
111
  files: string[];
116
112
  } | undefined;
117
- dryRun: boolean;
118
113
  warnings?: string[] | undefined;
119
114
  project?: ProjectPrepareResult | undefined;
120
115
  }
@@ -167,8 +162,8 @@ export declare const versionPatternsSchema: z.ZodObject<{
167
162
  minor: z.ZodArray<z.ZodString>;
168
163
  }, z.core.$strict>;
169
164
  export declare const breakingPolicyValueSchema: z.ZodEnum<{
170
- optional: "optional";
171
165
  forbidden: "forbidden";
166
+ optional: "optional";
172
167
  required: "required";
173
168
  }>;
174
169
  export declare const labelSpecSchema: z.ZodObject<{
@@ -186,8 +181,8 @@ export declare const repoLabelsSchema: z.ZodObject<{
186
181
  export type RepoLabelsConfig = z.infer<typeof repoLabelsSchema>;
187
182
  export declare const releaseKitConfigSchema: z.ZodObject<{
188
183
  breakingPolicies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
189
- optional: "optional";
190
184
  forbidden: "forbidden";
185
+ optional: "optional";
191
186
  required: "required";
192
187
  }>>>;
193
188
  changelogJson: z.ZodOptional<z.ZodObject<{
@@ -15,8 +15,8 @@ export interface WorkTypesData {
15
15
  tiers: string[];
16
16
  types: WorkTypeEntry[];
17
17
  markers: {
18
- breaking: MarkerEntry;
19
18
  [key: string]: MarkerEntry;
19
+ breaking: MarkerEntry;
20
20
  };
21
21
  }
22
22
  export declare const WORK_TYPES_DATA: WorkTypesData;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@williamthorsen/release-kit",
3
- "version": "10.2.1",
3
+ "version": "10.2.2",
4
4
  "description": "Version-bumping and changelog-generation toolkit for release workflows",
5
5
  "keywords": [],
6
6
  "homepage": "https://github.com/williamthorsen/node-monorepo-tools/tree/main/packages/release-kit#readme",
@@ -44,7 +44,7 @@
44
44
  "semver": "7.8.5",
45
45
  "yaml": "2.9.0",
46
46
  "zod": "4.4.3",
47
- "@williamthorsen/nmr-core": "0.9.1"
47
+ "@williamthorsen/nmr-core": "0.9.2"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@types/semver": "7.7.1",
@@ -1,3 +0,0 @@
1
- import type { BumpResult, ReleaseType } from './types.js';
2
- export declare function bumpAllVersions(packageFiles: readonly string[], releaseType: ReleaseType, dryRun: boolean): BumpResult;
3
- export declare function setAllVersions(packageFiles: readonly string[], newVersion: string, dryRun: boolean): BumpResult;
@@ -1,18 +0,0 @@
1
- export interface WriteReleaseNotesPreviewsOptions {
2
- workspacePath: string;
3
- tag: string;
4
- changelogJsonPath: string;
5
- sectionOrder: string[];
6
- dryRun: boolean;
7
- }
8
- export interface PreviewFileResult {
9
- filePath: string;
10
- outcome: 'created' | 'overwritten' | 'skipped-no-readme' | 'failed' | 'dry-run';
11
- error?: string;
12
- }
13
- export interface WriteReleaseNotesPreviewsResult {
14
- injectedReadme?: PreviewFileResult;
15
- releaseNotes?: PreviewFileResult;
16
- renderSkipped: boolean;
17
- }
18
- export declare function writeReleaseNotesPreviews(options: WriteReleaseNotesPreviewsOptions): WriteReleaseNotesPreviewsResult;