@williamthorsen/release-kit 5.4.0 → 7.0.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 (135) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +12 -12
  3. package/dist/esm/.cache +1 -1
  4. package/dist/esm/assertCleanWorkingTree.js +9 -14
  5. package/dist/esm/bin/release-kit.js +202 -229
  6. package/dist/esm/buildChangelogEntries.d.ts +2 -2
  7. package/dist/esm/buildChangelogEntries.js +142 -149
  8. package/dist/esm/buildDependencyGraph.d.ts +1 -1
  9. package/dist/esm/buildDependencyGraph.js +60 -59
  10. package/dist/esm/buildEmptyReleaseEntry.d.ts +1 -1
  11. package/dist/esm/buildEmptyReleaseEntry.js +12 -15
  12. package/dist/esm/buildReleaseSummary.d.ts +1 -1
  13. package/dist/esm/buildReleaseSummary.js +23 -26
  14. package/dist/esm/buildSyntheticChangelogEntry.d.ts +1 -1
  15. package/dist/esm/buildSyntheticChangelogEntry.js +9 -12
  16. package/dist/esm/bumpAllVersions.d.ts +1 -1
  17. package/dist/esm/bumpAllVersions.js +51 -52
  18. package/dist/esm/bumpVersion.d.ts +1 -1
  19. package/dist/esm/bumpVersion.js +25 -28
  20. package/dist/esm/changelogJsonFile.d.ts +1 -1
  21. package/dist/esm/changelogJsonFile.js +59 -62
  22. package/dist/esm/changelogJsonUtils.d.ts +1 -1
  23. package/dist/esm/changelogJsonUtils.js +35 -32
  24. package/dist/esm/changelogOverrides.d.ts +1 -1
  25. package/dist/esm/changelogOverrides.js +374 -377
  26. package/dist/esm/checkWorkTypesDrift.js +104 -99
  27. package/dist/esm/collectPolicyViolations.d.ts +2 -2
  28. package/dist/esm/collectPolicyViolations.js +11 -14
  29. package/dist/esm/commitCommand.js +48 -53
  30. package/dist/esm/compareVersions.js +20 -23
  31. package/dist/esm/createGithubRelease.js +56 -59
  32. package/dist/esm/createGithubReleaseCommand.js +21 -29
  33. package/dist/esm/createTags.js +57 -56
  34. package/dist/esm/decideRelease.d.ts +2 -2
  35. package/dist/esm/decideRelease.js +27 -41
  36. package/dist/esm/defaults.d.ts +3 -3
  37. package/dist/esm/defaults.js +36 -48
  38. package/dist/esm/deleteFileIfExists.js +10 -12
  39. package/dist/esm/deriveWorkspaceConfig.d.ts +1 -1
  40. package/dist/esm/deriveWorkspaceConfig.js +34 -36
  41. package/dist/esm/detectPackageManager.js +35 -37
  42. package/dist/esm/detectUndeclaredTagPrefixes.js +41 -40
  43. package/dist/esm/determineBumpFromCommits.d.ts +2 -2
  44. package/dist/esm/determineBumpFromCommits.js +25 -29
  45. package/dist/esm/determineBumpType.d.ts +1 -1
  46. package/dist/esm/determineBumpType.js +31 -32
  47. package/dist/esm/discoverWorkspaces.js +38 -40
  48. package/dist/esm/format.js +6 -11
  49. package/dist/esm/generateChangelogs.d.ts +1 -1
  50. package/dist/esm/generateChangelogs.js +13 -17
  51. package/dist/esm/getCommitsSinceTarget.d.ts +1 -1
  52. package/dist/esm/getCommitsSinceTarget.js +54 -55
  53. package/dist/esm/hasPrettierConfig.js +33 -35
  54. package/dist/esm/help/prepareHelp.d.ts +2 -0
  55. package/dist/esm/help/prepareHelp.js +26 -0
  56. package/dist/esm/index.d.ts +4 -4
  57. package/dist/esm/index.js +2 -8
  58. package/dist/esm/init/checks.js +28 -32
  59. package/dist/esm/init/detectRepoType.js +12 -15
  60. package/dist/esm/init/initCommand.js +60 -54
  61. package/dist/esm/init/parseJsonRecord.js +9 -11
  62. package/dist/esm/init/scaffold.d.ts +1 -1
  63. package/dist/esm/init/scaffold.js +32 -38
  64. package/dist/esm/init/templates.d.ts +1 -1
  65. package/dist/esm/init/templates.js +16 -22
  66. package/dist/esm/injectReleaseNotesIntoReadme.js +42 -49
  67. package/dist/esm/injectSection.js +17 -27
  68. package/dist/esm/loadConfig.d.ts +1 -1
  69. package/dist/esm/loadConfig.js +206 -225
  70. package/dist/esm/parseCommitMessage.d.ts +1 -1
  71. package/dist/esm/parseCommitMessage.js +72 -76
  72. package/dist/esm/parseRequestedTags.js +6 -9
  73. package/dist/esm/prepareCommand.d.ts +32 -1
  74. package/dist/esm/prepareCommand.js +225 -271
  75. package/dist/esm/previewTagPrefixes.d.ts +1 -1
  76. package/dist/esm/previewTagPrefixes.js +101 -96
  77. package/dist/esm/propagateBumps.d.ts +2 -2
  78. package/dist/esm/propagateBumps.js +48 -50
  79. package/dist/esm/publish.d.ts +2 -2
  80. package/dist/esm/publish.js +22 -28
  81. package/dist/esm/publishCommand.js +75 -86
  82. package/dist/esm/pushCommand.js +33 -40
  83. package/dist/esm/pushRelease.d.ts +1 -1
  84. package/dist/esm/pushRelease.js +21 -24
  85. package/dist/esm/readCurrentVersion.js +13 -17
  86. package/dist/esm/releasePrepare.d.ts +1 -1
  87. package/dist/esm/releasePrepare.js +213 -231
  88. package/dist/esm/releasePrepareMono.d.ts +2 -2
  89. package/dist/esm/releasePrepareMono.js +434 -493
  90. package/dist/esm/releasePrepareProject.d.ts +2 -2
  91. package/dist/esm/releasePrepareProject.js +143 -153
  92. package/dist/esm/renderChangelogMarkdown.d.ts +1 -1
  93. package/dist/esm/renderChangelogMarkdown.js +20 -24
  94. package/dist/esm/renderReleaseNotes.d.ts +1 -1
  95. package/dist/esm/renderReleaseNotes.js +50 -55
  96. package/dist/esm/reportPrepare.d.ts +1 -1
  97. package/dist/esm/reportPrepare.js +230 -231
  98. package/dist/esm/resolveCliffConfigPath.js +18 -23
  99. package/dist/esm/resolveCommandTags.d.ts +1 -1
  100. package/dist/esm/resolveCommandTags.js +47 -44
  101. package/dist/esm/resolveReleaseNotesConfig.d.ts +1 -1
  102. package/dist/esm/resolveReleaseNotesConfig.js +39 -41
  103. package/dist/esm/resolveReleaseTags.d.ts +1 -1
  104. package/dist/esm/resolveReleaseTags.js +39 -40
  105. package/dist/esm/runGitCliff.js +27 -30
  106. package/dist/esm/showTagPrefixesCommand.js +48 -70
  107. package/dist/esm/stripEmojiPrefix.js +2 -5
  108. package/dist/esm/stripScope.js +18 -21
  109. package/dist/esm/sync-labels/generateCommand.d.ts +1 -1
  110. package/dist/esm/sync-labels/generateCommand.js +51 -52
  111. package/dist/esm/sync-labels/initCommand.js +46 -47
  112. package/dist/esm/sync-labels/loadSyncLabelsConfig.d.ts +1 -1
  113. package/dist/esm/sync-labels/loadSyncLabelsConfig.js +46 -52
  114. package/dist/esm/sync-labels/presets.d.ts +1 -1
  115. package/dist/esm/sync-labels/presets.js +40 -43
  116. package/dist/esm/sync-labels/resolveLabels.d.ts +1 -1
  117. package/dist/esm/sync-labels/resolveLabels.js +28 -35
  118. package/dist/esm/sync-labels/syncCommand.js +30 -30
  119. package/dist/esm/sync-labels/templates.d.ts +1 -1
  120. package/dist/esm/sync-labels/templates.js +23 -26
  121. package/dist/esm/sync-labels/types.js +1 -0
  122. package/dist/esm/syncWorkTypes.js +83 -81
  123. package/dist/esm/tagCommand.js +12 -21
  124. package/dist/esm/typeGuards.js +4 -8
  125. package/dist/esm/types.js +66 -60
  126. package/dist/esm/validateConfig.d.ts +1 -1
  127. package/dist/esm/validateConfig.js +109 -115
  128. package/dist/esm/validateOnlyExcludesStrandedDependents.d.ts +2 -2
  129. package/dist/esm/validateOnlyExcludesStrandedDependents.js +97 -91
  130. package/dist/esm/validateOverridesCommand.d.ts +2 -2
  131. package/dist/esm/validateOverridesCommand.js +111 -111
  132. package/dist/esm/workTypesData.js +57 -60
  133. package/dist/esm/workTypesUtils.js +16 -21
  134. package/dist/esm/writeReleaseNotesPreviews.js +55 -57
  135. package/package.json +2 -6
@@ -1,136 +1,136 @@
1
+ import { formatErrorLine } from '@williamthorsen/nmr-core';
1
2
  import { buildChangelogEntries } from "./buildChangelogEntries.js";
2
- import {
3
- resolveOverridePath,
4
- validateAllChangelogOverrides
5
- } from "./changelogOverrides.js";
3
+ import { resolveOverridePath, validateAllChangelogOverrides, } from "./changelogOverrides.js";
6
4
  import { discoverWorkspaces } from "./discoverWorkspaces.js";
7
5
  import { buildTagPattern, getAllTagPrefixes } from "./generateChangelogs.js";
8
6
  import { loadConfig, mergeMonorepoConfig, mergeSinglePackageConfig, readRootPackageVersion } from "./loadConfig.js";
9
7
  import { validateConfig } from "./validateConfig.js";
10
- const SYNTHETIC_VALIDATE_TAG = "validate-only";
11
- async function validateOverridesCommand(dependencies = {}) {
12
- const discover = dependencies.discoverWorkspaces ?? discoverWorkspaces;
13
- const load = dependencies.loadConfig ?? loadConfig;
14
- const buildEntries = dependencies.buildEntries ?? defaultBuildEntries;
15
- const validate = dependencies.validate ?? validateAllChangelogOverrides;
16
- let userConfig;
17
- try {
18
- userConfig = await loadAndValidateConfig(load);
19
- } catch (error) {
20
- return { exitCode: 2, message: errorMessage(error) };
21
- }
22
- let discoveredPaths;
23
- try {
24
- discoveredPaths = await discover();
25
- } catch (error) {
26
- return { exitCode: 2, message: `Error discovering workspaces: ${errorMessage(error)}` };
27
- }
28
- let inputs;
29
- try {
30
- inputs = discoveredPaths === void 0 ? buildSinglePackageInputs(userConfig, buildEntries) : buildMonorepoInputs(discoveredPaths, userConfig, buildEntries);
31
- } catch (error) {
32
- return { exitCode: 2, message: `Error resolving overrides scope: ${errorMessage(error)}` };
33
- }
34
- const result = validate(inputs);
35
- return formatValidateOverridesResult(result);
8
+ const SYNTHETIC_VALIDATE_TAG = 'validate-only';
9
+ export async function validateOverridesCommand(dependencies = {}) {
10
+ const discover = dependencies.discoverWorkspaces ?? discoverWorkspaces;
11
+ const load = dependencies.loadConfig ?? loadConfig;
12
+ const buildEntries = dependencies.buildEntries ?? defaultBuildEntries;
13
+ const validate = dependencies.validate ?? validateAllChangelogOverrides;
14
+ let rawConfig;
15
+ try {
16
+ rawConfig = await load();
17
+ }
18
+ catch (error) {
19
+ return { exitCode: 2, message: formatErrorLine(`Failed to load config: ${errorMessage(error)}`) };
20
+ }
21
+ let userConfig;
22
+ try {
23
+ userConfig = validateLoadedConfig(rawConfig);
24
+ }
25
+ catch (error) {
26
+ return { exitCode: 2, message: errorMessage(error) };
27
+ }
28
+ let discoveredPaths;
29
+ try {
30
+ discoveredPaths = await discover();
31
+ }
32
+ catch (error) {
33
+ return { exitCode: 2, message: formatErrorLine(`Failed to discover workspaces: ${errorMessage(error)}`) };
34
+ }
35
+ let inputs;
36
+ try {
37
+ inputs =
38
+ discoveredPaths === undefined
39
+ ? buildSinglePackageInputs(userConfig, buildEntries)
40
+ : buildMonorepoInputs(discoveredPaths, userConfig, buildEntries);
41
+ }
42
+ catch (error) {
43
+ return { exitCode: 2, message: formatErrorLine(`Failed to resolve overrides scope: ${errorMessage(error)}`) };
44
+ }
45
+ const result = validate(inputs);
46
+ return formatValidateOverridesResult(result);
36
47
  }
37
- function formatValidateOverridesResult(result) {
38
- const { errors, warnings } = result;
39
- if (errors.length === 0 && warnings.length === 0) {
40
- return { exitCode: 0, message: "All override files are valid (no errors, no stale keys)." };
41
- }
42
- const exitCode = errors.length > 0 ? 2 : 1;
43
- const summary = formatSummaryLine(errors.length, warnings.length);
44
- const errorLines = errors.map((message2) => ` \u274C ${message2}`);
45
- const warningLines = warnings.map((message2) => ` \u26A0\uFE0F ${message2}`);
46
- const message = [summary, "", ...errorLines, ...warningLines].join("\n");
47
- return { exitCode, message };
48
+ export function formatValidateOverridesResult(result) {
49
+ const { errors, warnings } = result;
50
+ if (errors.length === 0 && warnings.length === 0) {
51
+ return { exitCode: 0, message: 'All override files are valid (no errors, no stale keys).' };
52
+ }
53
+ const exitCode = errors.length > 0 ? 2 : 1;
54
+ const summary = formatSummaryLine(errors.length, warnings.length);
55
+ const errorLines = errors.map((message) => ` ❌ ${message}`);
56
+ const warningLines = warnings.map((message) => ` ⚠️ ${message}`);
57
+ const message = [summary, '', ...errorLines, ...warningLines].join('\n');
58
+ return { exitCode, message };
48
59
  }
49
60
  function formatSummaryLine(errorCount, warningCount) {
50
- const parts = [];
51
- if (errorCount > 0) {
52
- parts.push(pluralize(errorCount, "error"));
53
- }
54
- if (warningCount > 0) {
55
- parts.push(pluralize(warningCount, "warning"));
56
- }
57
- return `Found ${parts.join(" and ")}:`;
61
+ const parts = [];
62
+ if (errorCount > 0) {
63
+ parts.push(pluralize(errorCount, 'error'));
64
+ }
65
+ if (warningCount > 0) {
66
+ parts.push(pluralize(warningCount, 'warning'));
67
+ }
68
+ return `Found ${parts.join(' and ')}:`;
58
69
  }
59
70
  function pluralize(count, noun) {
60
- return count === 1 ? `${count} ${noun}` : `${count} ${noun}s`;
71
+ return count === 1 ? `${count} ${noun}` : `${count} ${noun}s`;
61
72
  }
62
73
  function errorMessage(error) {
63
- return error instanceof Error ? error.message : String(error);
74
+ return error instanceof Error ? error.message : String(error);
64
75
  }
65
76
  function defaultBuildEntries(config, tagPattern, includePaths) {
66
- const options = {};
67
- if (tagPattern !== void 0) {
68
- options.tagPattern = tagPattern;
69
- }
70
- if (includePaths !== void 0) {
71
- options.includePaths = includePaths;
72
- }
73
- return buildChangelogEntries(config, SYNTHETIC_VALIDATE_TAG, options);
77
+ const options = {};
78
+ if (tagPattern !== undefined) {
79
+ options.tagPattern = tagPattern;
80
+ }
81
+ if (includePaths !== undefined) {
82
+ options.includePaths = includePaths;
83
+ }
84
+ return buildChangelogEntries(config, SYNTHETIC_VALIDATE_TAG, options);
74
85
  }
75
86
  function flattenEntriesToHashes(entries) {
76
- const hashes = [];
77
- for (const entry of entries) {
78
- for (const section of entry.sections) {
79
- for (const item of section.items) {
80
- if (item.hash !== void 0) {
81
- hashes.push(item.hash);
87
+ const hashes = [];
88
+ for (const entry of entries) {
89
+ for (const section of entry.sections) {
90
+ for (const item of section.items) {
91
+ if (item.hash !== undefined) {
92
+ hashes.push(item.hash);
93
+ }
94
+ }
82
95
  }
83
- }
84
96
  }
85
- }
86
- return hashes;
97
+ return hashes;
87
98
  }
88
- async function loadAndValidateConfig(load) {
89
- let rawConfig;
90
- try {
91
- rawConfig = await load();
92
- } catch (error) {
93
- throw new Error(`Error loading config: ${errorMessage(error)}`);
94
- }
95
- if (rawConfig === void 0) {
96
- return void 0;
97
- }
98
- const { config, errors } = validateConfig(rawConfig);
99
- if (errors.length > 0) {
100
- throw new Error(`Invalid config:
101
- - ${errors.join("\n - ")}`);
102
- }
103
- return config;
99
+ function validateLoadedConfig(rawConfig) {
100
+ if (rawConfig === undefined) {
101
+ return undefined;
102
+ }
103
+ const { config, errors } = validateConfig(rawConfig);
104
+ if (errors.length > 0) {
105
+ throw new Error(`Invalid config:\n - ${errors.join('\n - ')}`);
106
+ }
107
+ return config;
104
108
  }
105
109
  function buildSinglePackageInputs(userConfig, buildEntries) {
106
- const config = mergeSinglePackageConfig(userConfig);
107
- const hashes = flattenEntriesToHashes(buildEntries(config));
108
- return {
109
- project: { filePath: resolveOverridePath("."), hashes }
110
- };
110
+ const config = mergeSinglePackageConfig(userConfig);
111
+ const hashes = flattenEntriesToHashes(buildEntries(config));
112
+ return {
113
+ project: { filePath: resolveOverridePath('.'), hashes },
114
+ };
111
115
  }
112
116
  function buildMonorepoInputs(discoveredPaths, userConfig, buildEntries) {
113
- const rootPackage = readRootPackageVersion();
114
- const config = mergeMonorepoConfig(discoveredPaths, userConfig, rootPackage);
115
- const workspaces = config.workspaces.map((workspace) => {
116
- const tagPattern = buildTagPattern(getAllTagPrefixes(workspace));
117
- return {
118
- filePath: resolveOverridePath(workspace.workspacePath),
119
- hashes: flattenEntriesToHashes(buildEntries(config, tagPattern, workspace.paths))
117
+ const rootPackage = readRootPackageVersion();
118
+ const config = mergeMonorepoConfig(discoveredPaths, userConfig, rootPackage);
119
+ const workspaces = config.workspaces.map((workspace) => {
120
+ const tagPattern = buildTagPattern(getAllTagPrefixes(workspace));
121
+ return {
122
+ filePath: resolveOverridePath(workspace.workspacePath),
123
+ hashes: flattenEntriesToHashes(buildEntries(config, tagPattern, workspace.paths)),
124
+ };
125
+ });
126
+ const project = config.project;
127
+ const projectScope = {
128
+ filePath: resolveOverridePath('.'),
120
129
  };
121
- });
122
- const project = config.project;
123
- const projectScope = {
124
- filePath: resolveOverridePath(".")
125
- };
126
- if (project !== void 0) {
127
- const contributingPaths = config.workspaces.flatMap((workspace) => workspace.paths);
128
- const projectTagPattern = buildTagPattern([project.tagPrefix]);
129
- projectScope.hashes = flattenEntriesToHashes(buildEntries(config, projectTagPattern, contributingPaths));
130
- }
131
- return { project: projectScope, workspaces };
130
+ if (project !== undefined) {
131
+ const contributingPaths = config.workspaces.flatMap((workspace) => workspace.paths);
132
+ const projectTagPattern = buildTagPattern([project.tagPrefix]);
133
+ projectScope.hashes = flattenEntriesToHashes(buildEntries(config, projectTagPattern, contributingPaths));
134
+ }
135
+ return { project: projectScope, workspaces };
132
136
  }
133
- export {
134
- formatValidateOverridesResult,
135
- validateOverridesCommand
136
- };
@@ -1,62 +1,59 @@
1
- const WORK_TYPES_DATA = {
2
- tiers: ["public", "internal", "process"],
3
- types: [
4
- { tier: "public", key: "feat", aliases: ["feature"], emoji: "\u{1F389}", label: "Features", breakingPolicy: "optional" },
5
- { tier: "public", key: "drop", aliases: [], emoji: "\u{1FAA6}", label: "Removed", breakingPolicy: "required" },
6
- { tier: "public", key: "deprecate", aliases: [], emoji: "\u{1F5D1}\uFE0F", label: "Deprecated", breakingPolicy: "forbidden" },
7
- { tier: "public", key: "fix", aliases: ["bugfix"], emoji: "\u{1F41B}", label: "Bug fixes", breakingPolicy: "forbidden" },
8
- { tier: "public", key: "sec", aliases: ["security"], emoji: "\u{1F512}", label: "Security", breakingPolicy: "optional" },
9
- {
10
- tier: "public",
11
- key: "perf",
12
- aliases: ["performance"],
13
- emoji: "\u26A1",
14
- label: "Performance",
15
- breakingPolicy: "forbidden"
1
+ export const WORK_TYPES_DATA = {
2
+ tiers: ['public', 'internal', 'process'],
3
+ types: [
4
+ { tier: 'public', key: 'feat', aliases: ['feature'], emoji: '🎉', label: 'Features', breakingPolicy: 'optional' },
5
+ { tier: 'public', key: 'drop', aliases: [], emoji: '🪦', label: 'Removed', breakingPolicy: 'required' },
6
+ { tier: 'public', key: 'deprecate', aliases: [], emoji: '🗑️', label: 'Deprecated', breakingPolicy: 'forbidden' },
7
+ { tier: 'public', key: 'fix', aliases: ['bugfix'], emoji: '🐛', label: 'Bug fixes', breakingPolicy: 'forbidden' },
8
+ { tier: 'public', key: 'sec', aliases: ['security'], emoji: '🔒', label: 'Security', breakingPolicy: 'optional' },
9
+ {
10
+ tier: 'public',
11
+ key: 'perf',
12
+ aliases: ['performance'],
13
+ emoji: '⚡',
14
+ label: 'Performance',
15
+ breakingPolicy: 'forbidden',
16
+ },
17
+ {
18
+ tier: 'internal',
19
+ key: 'internal',
20
+ aliases: ['utility'],
21
+ emoji: '🏗️',
22
+ label: 'Internal features',
23
+ breakingPolicy: 'forbidden',
24
+ },
25
+ {
26
+ tier: 'internal',
27
+ key: 'refactor',
28
+ aliases: [],
29
+ emoji: '♻️',
30
+ label: 'Refactoring',
31
+ breakingPolicy: 'forbidden',
32
+ },
33
+ { tier: 'internal', key: 'tests', aliases: ['test'], emoji: '🧪', label: 'Tests', breakingPolicy: 'forbidden' },
34
+ { tier: 'process', key: 'tooling', aliases: [], emoji: '⚙️', label: 'Tooling', breakingPolicy: 'forbidden' },
35
+ { tier: 'process', key: 'ci', aliases: [], emoji: '👷', label: 'CI', breakingPolicy: 'forbidden' },
36
+ { tier: 'process', key: 'deps', aliases: ['dep'], emoji: '📦', label: 'Dependencies', breakingPolicy: 'forbidden' },
37
+ { tier: 'process', key: 'ai', aliases: [], emoji: '🤖', label: 'Agentic support', breakingPolicy: 'forbidden' },
38
+ {
39
+ tier: 'process',
40
+ key: 'docs',
41
+ aliases: ['doc'],
42
+ emoji: '📚',
43
+ label: 'Documentation',
44
+ breakingPolicy: 'forbidden',
45
+ },
46
+ {
47
+ tier: 'process',
48
+ key: 'fmt',
49
+ aliases: [],
50
+ emoji: '🎨',
51
+ label: 'Formatting',
52
+ breakingPolicy: 'forbidden',
53
+ excludedFromChangelog: true,
54
+ },
55
+ ],
56
+ markers: {
57
+ breaking: { emoji: '🚨', label: 'Breaking' },
16
58
  },
17
- {
18
- tier: "internal",
19
- key: "internal",
20
- aliases: ["utility"],
21
- emoji: "\u{1F3D7}\uFE0F",
22
- label: "Internal features",
23
- breakingPolicy: "forbidden"
24
- },
25
- {
26
- tier: "internal",
27
- key: "refactor",
28
- aliases: [],
29
- emoji: "\u267B\uFE0F",
30
- label: "Refactoring",
31
- breakingPolicy: "forbidden"
32
- },
33
- { tier: "internal", key: "tests", aliases: ["test"], emoji: "\u{1F9EA}", label: "Tests", breakingPolicy: "forbidden" },
34
- { tier: "process", key: "tooling", aliases: [], emoji: "\u2699\uFE0F", label: "Tooling", breakingPolicy: "forbidden" },
35
- { tier: "process", key: "ci", aliases: [], emoji: "\u{1F477}", label: "CI", breakingPolicy: "forbidden" },
36
- { tier: "process", key: "deps", aliases: ["dep"], emoji: "\u{1F4E6}", label: "Dependencies", breakingPolicy: "forbidden" },
37
- { tier: "process", key: "ai", aliases: [], emoji: "\u{1F916}", label: "Agentic support", breakingPolicy: "forbidden" },
38
- {
39
- tier: "process",
40
- key: "docs",
41
- aliases: ["doc"],
42
- emoji: "\u{1F4DA}",
43
- label: "Documentation",
44
- breakingPolicy: "forbidden"
45
- },
46
- {
47
- tier: "process",
48
- key: "fmt",
49
- aliases: [],
50
- emoji: "\u{1F3A8}",
51
- label: "Formatting",
52
- breakingPolicy: "forbidden",
53
- excludedFromChangelog: true
54
- }
55
- ],
56
- markers: {
57
- breaking: { emoji: "\u{1F6A8}", label: "Breaking" }
58
- }
59
- };
60
- export {
61
- WORK_TYPES_DATA
62
59
  };
@@ -1,24 +1,19 @@
1
- function hasExpectedTopLevelShape(value) {
2
- if (typeof value !== "object" || value === null) {
3
- return false;
4
- }
5
- if (!("tiers" in value) || !("types" in value)) {
6
- return false;
7
- }
8
- return Array.isArray(value.tiers) && Array.isArray(value.types);
1
+ export function hasExpectedTopLevelShape(value) {
2
+ if (typeof value !== 'object' || value === null) {
3
+ return false;
4
+ }
5
+ if (!('tiers' in value) || !('types' in value)) {
6
+ return false;
7
+ }
8
+ return Array.isArray(value.tiers) && Array.isArray(value.types);
9
9
  }
10
- function errorMessage(error) {
11
- return error instanceof Error ? error.message : String(error);
10
+ export function errorMessage(error) {
11
+ return error instanceof Error ? error.message : String(error);
12
12
  }
13
- function buildFetchInit() {
14
- const token = process.env.GITHUB_TOKEN;
15
- if (token === void 0 || token === "") {
16
- return void 0;
17
- }
18
- return { headers: { Authorization: `Bearer ${token}` } };
13
+ export function buildFetchInit() {
14
+ const token = process.env.GITHUB_TOKEN;
15
+ if (token === undefined || token === '') {
16
+ return undefined;
17
+ }
18
+ return { headers: { Authorization: `Bearer ${token}` } };
19
19
  }
20
- export {
21
- buildFetchInit,
22
- errorMessage,
23
- hasExpectedTopLevelShape
24
- };
@@ -1,65 +1,63 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import path from "node:path";
3
- import { writeFileWithCheck } from "@williamthorsen/nmr-core";
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { reportError, writeFileWithCheck } from '@williamthorsen/nmr-core';
4
4
  import { extractVersion } from "./changelogJsonUtils.js";
5
5
  import { dim } from "./format.js";
6
6
  import { renderInjectedReadme } from "./injectReleaseNotesIntoReadme.js";
7
- function writeReleaseNotesPreviews(options) {
8
- const { workspacePath, tag, changelogJsonPath, sectionOrder, dryRun } = options;
9
- const version = extractVersion(tag);
10
- const readmePath = path.join(workspacePath, "README.md");
11
- let readmeExists = existsSync(readmePath);
12
- let readmeUnreadable = false;
13
- let readmeContent = "";
14
- if (readmeExists) {
15
- try {
16
- readmeContent = readFileSync(readmePath, "utf8");
17
- } catch (error) {
18
- const message = error instanceof Error ? error.message : String(error);
19
- console.warn(`Warning: failed to read ${readmePath}: ${message}; skipping injected-README preview`);
20
- readmeExists = false;
21
- readmeUnreadable = true;
7
+ export function writeReleaseNotesPreviews(options) {
8
+ const { workspacePath, tag, changelogJsonPath, sectionOrder, dryRun } = options;
9
+ const version = extractVersion(tag);
10
+ const readmePath = path.join(workspacePath, 'README.md');
11
+ let readmeExists = existsSync(readmePath);
12
+ let readmeUnreadable = false;
13
+ let readmeContent = '';
14
+ if (readmeExists) {
15
+ try {
16
+ readmeContent = readFileSync(readmePath, 'utf8');
17
+ }
18
+ catch (error) {
19
+ const message = error instanceof Error ? error.message : String(error);
20
+ console.warn(`Warning: failed to read ${readmePath}: ${message}; skipping injected-README preview`);
21
+ readmeExists = false;
22
+ readmeUnreadable = true;
23
+ }
22
24
  }
23
- }
24
- const rendered = renderInjectedReadme(readmeContent, changelogJsonPath, tag, sectionOrder);
25
- if (rendered === void 0) {
26
- return { renderSkipped: true };
27
- }
28
- const docsDir = path.join(workspacePath, "docs");
29
- const readmePreviewPath = path.join(docsDir, `README.v${version}.md`);
30
- const releaseNotesPreviewPath = path.join(docsDir, `RELEASE_NOTES.v${version}.md`);
31
- let injectedReadme;
32
- if (readmeExists) {
33
- injectedReadme = writePreviewFile(readmePreviewPath, rendered.injectedReadme, dryRun);
34
- } else {
35
- if (!readmeUnreadable) {
36
- console.warn(
37
- `Warning: ${readmePath} not found; skipping injected-README preview but still writing standalone release notes`
38
- );
25
+ const rendered = renderInjectedReadme(readmeContent, changelogJsonPath, tag, sectionOrder);
26
+ if (rendered === undefined) {
27
+ return { renderSkipped: true };
39
28
  }
40
- injectedReadme = { filePath: readmePreviewPath, outcome: "skipped-no-readme" };
41
- }
42
- const releaseNotesContent = rendered.releaseNotesMarkdown.endsWith("\n") ? rendered.releaseNotesMarkdown : `${rendered.releaseNotesMarkdown}
43
- `;
44
- const releaseNotes = writePreviewFile(releaseNotesPreviewPath, releaseNotesContent, dryRun);
45
- return { injectedReadme, releaseNotes, renderSkipped: false };
29
+ const docsDir = path.join(workspacePath, 'docs');
30
+ const readmePreviewPath = path.join(docsDir, `README.v${version}.md`);
31
+ const releaseNotesPreviewPath = path.join(docsDir, `RELEASE_NOTES.v${version}.md`);
32
+ let injectedReadme;
33
+ if (readmeExists) {
34
+ injectedReadme = writePreviewFile(readmePreviewPath, rendered.injectedReadme, dryRun);
35
+ }
36
+ else {
37
+ if (!readmeUnreadable) {
38
+ console.warn(`Warning: ${readmePath} not found; skipping injected-README preview but still writing standalone release notes`);
39
+ }
40
+ injectedReadme = { filePath: readmePreviewPath, outcome: 'skipped-no-readme' };
41
+ }
42
+ const releaseNotesContent = rendered.releaseNotesMarkdown.endsWith('\n')
43
+ ? rendered.releaseNotesMarkdown
44
+ : `${rendered.releaseNotesMarkdown}\n`;
45
+ const releaseNotes = writePreviewFile(releaseNotesPreviewPath, releaseNotesContent, dryRun);
46
+ return { injectedReadme, releaseNotes, renderSkipped: false };
46
47
  }
47
48
  function writePreviewFile(filePath, content, dryRun) {
48
- if (dryRun) {
49
- console.info(dim(` [dry-run] Would write ${filePath}`));
50
- return { filePath, outcome: "dry-run" };
51
- }
52
- const result = writeFileWithCheck(filePath, content, { dryRun: false, overwrite: true });
53
- if (result.outcome === "failed") {
54
- console.error(`Error writing ${filePath}: ${result.error ?? "unknown error"}`);
55
- return { filePath, outcome: "failed", ...result.error === void 0 ? {} : { error: result.error } };
56
- }
57
- if (result.outcome === "created" || result.outcome === "overwritten") {
58
- console.info(dim(` Wrote ${filePath}`));
59
- return { filePath, outcome: result.outcome };
60
- }
61
- return { filePath, outcome: "failed", error: `unexpected outcome: ${result.outcome}` };
49
+ if (dryRun) {
50
+ console.info(dim(` [dry-run] Would write ${filePath}`));
51
+ return { filePath, outcome: 'dry-run' };
52
+ }
53
+ const result = writeFileWithCheck(filePath, content, { dryRun: false, overwrite: true });
54
+ if (result.outcome === 'failed') {
55
+ reportError(`Failed to write ${filePath}: ${result.error ?? 'unknown error'}`);
56
+ return { filePath, outcome: 'failed', ...(result.error === undefined ? {} : { error: result.error }) };
57
+ }
58
+ if (result.outcome === 'created' || result.outcome === 'overwritten') {
59
+ console.info(dim(` Wrote ${filePath}`));
60
+ return { filePath, outcome: result.outcome };
61
+ }
62
+ return { filePath, outcome: 'failed', error: `unexpected outcome: ${result.outcome}` };
62
63
  }
63
- export {
64
- writeReleaseNotesPreviews
65
- };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@williamthorsen/release-kit",
3
- "version": "5.4.0",
3
+ "version": "7.0.0",
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",
@@ -38,7 +38,7 @@
38
38
  "semver": "7.8.5",
39
39
  "yaml": "2.9.0",
40
40
  "zod": "4.4.3",
41
- "@williamthorsen/nmr-core": "0.4.0"
41
+ "@williamthorsen/nmr-core": "0.6.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/semver": "7.7.1",
@@ -53,10 +53,6 @@
53
53
  },
54
54
  "scripts": {
55
55
  "build:post": "node scripts/copy-work-types.js",
56
- "test": "pnpm exec vitest --config=vitest.standalone.config.ts",
57
- "test:coverage": "pnpm exec vitest --config=vitest.standalone.config.ts --coverage",
58
- "test:integration": "pnpm exec vitest --config=vitest.integration.config.ts",
59
- "test:watch": "pnpm exec vitest --config=vitest.standalone.config.ts --watch",
60
56
  "work-types:check": "pnpm exec release-kit work-types check",
61
57
  "work-types:sync": "pnpm exec release-kit work-types sync"
62
58
  }