@williamthorsen/release-kit 4.7.0 → 5.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 (87) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +310 -40
  3. package/cliff.toml.template +2 -1
  4. package/dist/esm/.cache +1 -1
  5. package/dist/esm/bin/release-kit.js +67 -12
  6. package/dist/esm/buildDependencyGraph.d.ts +3 -3
  7. package/dist/esm/buildDependencyGraph.js +10 -10
  8. package/dist/esm/buildReleaseSummary.js +4 -4
  9. package/dist/esm/bumpAllVersions.d.ts +1 -0
  10. package/dist/esm/bumpAllVersions.js +16 -2
  11. package/dist/esm/bumpVersion.js +3 -0
  12. package/dist/esm/commitCommand.js +1 -1
  13. package/dist/esm/compareVersions.d.ts +1 -0
  14. package/dist/esm/compareVersions.js +27 -0
  15. package/dist/esm/createGithubRelease.d.ts +6 -2
  16. package/dist/esm/createGithubRelease.js +17 -17
  17. package/dist/esm/createGithubReleaseCommand.d.ts +1 -0
  18. package/dist/esm/createGithubReleaseCommand.js +41 -0
  19. package/dist/esm/defaults.js +5 -3
  20. package/dist/esm/deriveWorkspaceConfig.d.ts +2 -0
  21. package/dist/esm/deriveWorkspaceConfig.js +37 -0
  22. package/dist/esm/detectUndeclaredTagPrefixes.d.ts +7 -0
  23. package/dist/esm/detectUndeclaredTagPrefixes.js +46 -0
  24. package/dist/esm/generateChangelogJson.js +37 -1
  25. package/dist/esm/generateChangelogs.d.ts +1 -1
  26. package/dist/esm/generateChangelogs.js +14 -3
  27. package/dist/esm/getCommitsSinceTarget.d.ts +1 -1
  28. package/dist/esm/getCommitsSinceTarget.js +8 -4
  29. package/dist/esm/index.d.ts +9 -3
  30. package/dist/esm/index.js +12 -3
  31. package/dist/esm/init/detectRepoType.js +1 -2
  32. package/dist/esm/init/initCommand.js +1 -1
  33. package/dist/esm/init/scaffold.d.ts +1 -1
  34. package/dist/esm/init/scaffold.js +8 -5
  35. package/dist/esm/init/templates.d.ts +1 -0
  36. package/dist/esm/init/templates.js +40 -10
  37. package/dist/esm/injectReleaseNotesIntoReadme.d.ts +6 -1
  38. package/dist/esm/injectReleaseNotesIntoReadme.js +20 -7
  39. package/dist/esm/loadConfig.d.ts +2 -1
  40. package/dist/esm/loadConfig.js +65 -12
  41. package/dist/esm/parseRequestedTags.d.ts +1 -0
  42. package/dist/esm/parseRequestedTags.js +10 -0
  43. package/dist/esm/prepareCommand.d.ts +3 -1
  44. package/dist/esm/prepareCommand.js +75 -27
  45. package/dist/esm/previewTagPrefixes.d.ts +30 -0
  46. package/dist/esm/previewTagPrefixes.js +120 -0
  47. package/dist/esm/propagateBumps.d.ts +1 -0
  48. package/dist/esm/propagateBumps.js +1 -1
  49. package/dist/esm/publishCommand.js +8 -13
  50. package/dist/esm/pushCommand.d.ts +1 -0
  51. package/dist/esm/pushCommand.js +47 -0
  52. package/dist/esm/pushRelease.d.ts +11 -0
  53. package/dist/esm/pushRelease.js +26 -0
  54. package/dist/esm/readCurrentVersion.d.ts +1 -0
  55. package/dist/esm/readCurrentVersion.js +21 -0
  56. package/dist/esm/releasePrepare.d.ts +2 -0
  57. package/dist/esm/releasePrepare.js +72 -30
  58. package/dist/esm/releasePrepareMono.js +235 -112
  59. package/dist/esm/renderReleaseNotes.d.ts +1 -0
  60. package/dist/esm/renderReleaseNotes.js +29 -2
  61. package/dist/esm/reportPrepare.js +100 -73
  62. package/dist/esm/resolveCliffConfigPath.js +1 -1
  63. package/dist/esm/resolveCommandTags.d.ts +1 -1
  64. package/dist/esm/resolveCommandTags.js +17 -13
  65. package/dist/esm/resolveReleaseNotesConfig.d.ts +8 -1
  66. package/dist/esm/resolveReleaseNotesConfig.js +17 -7
  67. package/dist/esm/resolveReleaseTags.d.ts +2 -1
  68. package/dist/esm/resolveReleaseTags.js +19 -14
  69. package/dist/esm/showTagPrefixesCommand.d.ts +1 -0
  70. package/dist/esm/showTagPrefixesCommand.js +84 -0
  71. package/dist/esm/sync-labels/initCommand.js +1 -1
  72. package/dist/esm/sync-labels/presets.js +1 -1
  73. package/dist/esm/sync-labels/templates.js +1 -1
  74. package/dist/esm/tagCommand.js +1 -1
  75. package/dist/esm/types.d.ts +22 -7
  76. package/dist/esm/validateConfig.js +179 -36
  77. package/dist/esm/version.d.ts +1 -1
  78. package/dist/esm/version.js +1 -1
  79. package/dist/esm/writeReleaseNotesPreviews.d.ts +18 -0
  80. package/dist/esm/writeReleaseNotesPreviews.js +65 -0
  81. package/package.json +2 -2
  82. package/dist/esm/component.d.ts +0 -2
  83. package/dist/esm/component.js +0 -14
  84. package/dist/esm/findPackageRoot.d.ts +0 -1
  85. package/dist/esm/findPackageRoot.js +0 -17
  86. package/dist/esm/githubReleaseCommand.d.ts +0 -1
  87. package/dist/esm/githubReleaseCommand.js +0 -35
@@ -6,9 +6,13 @@ function isNoTagError(err) {
6
6
  function errorMessage(err) {
7
7
  return err instanceof Error ? err.message : String(err);
8
8
  }
9
- function findLatestTag(tagPrefix) {
9
+ function findLatestTag(tagPrefixes) {
10
+ if (tagPrefixes.length === 0) {
11
+ throw new Error("findLatestTag: tagPrefixes must contain at least one entry");
12
+ }
13
+ const matchArgs = tagPrefixes.map((prefix) => `--match=${prefix}*`);
10
14
  try {
11
- const tagResult = execFileSync("git", ["describe", "--tags", "--abbrev=0", `--match=${tagPrefix}*`], {
15
+ const tagResult = execFileSync("git", ["describe", "--tags", "--abbrev=0", ...matchArgs], {
12
16
  encoding: "utf8",
13
17
  stdio: ["pipe", "pipe", "pipe"]
14
18
  }).trim();
@@ -35,8 +39,8 @@ function parseLogOutput(logOutput) {
35
39
  }
36
40
  return commits;
37
41
  }
38
- function getCommitsSinceTarget(tagPrefix, paths) {
39
- const tag = findLatestTag(tagPrefix);
42
+ function getCommitsSinceTarget(tagPrefixes, paths) {
43
+ const tag = findLatestTag(tagPrefixes);
40
44
  const range = tag === void 0 ? "HEAD" : `${tag}..HEAD`;
41
45
  const format = `%s${FIELD_SEPARATOR}%H`;
42
46
  const args = ["log", range, `--pretty=format:${format}`];
@@ -1,32 +1,36 @@
1
1
  export type { CreateTagsOptions } from './createTags.ts';
2
2
  export type { PackageManager } from './detectPackageManager.ts';
3
3
  export type { GenerateChangelogOptions } from './generateChangelogs.ts';
4
+ export type { RetiredPackagePreviewEntry } from './previewTagPrefixes.ts';
4
5
  export type { PublishOptions } from './publish.ts';
5
6
  export type { ReleasePrepareOptions } from './releasePrepare.ts';
6
7
  export type { ResolvedTag } from './resolveReleaseTags.ts';
7
8
  export type { LabelDefinition, SyncLabelsConfig } from './sync-labels/types.ts';
8
- export type { BumpResult, ChangelogAudience, ChangelogEntry, ChangelogItem, ChangelogJsonConfig, ChangelogSection, Commit, ComponentConfig, ComponentOverride, ComponentPrepareResult, MonorepoReleaseConfig, ParsedCommit, PrepareResult, ReleaseConfig, ReleaseKitConfig, ReleaseNotesConfig, ReleaseType, VersionPatterns, WorkTypeConfig, } from './types.ts';
9
+ export type { BumpResult, ChangelogAudience, ChangelogEntry, ChangelogItem, ChangelogJsonConfig, ChangelogSection, Commit, LegacyIdentity, MonorepoReleaseConfig, ParsedCommit, PrepareResult, ReleaseConfig, ReleaseKitConfig, ReleaseNotesConfig, ReleaseType, RetiredPackage, VersionPatterns, WorkspaceConfig, WorkspaceOverride, WorkspacePrepareResult, WorkTypeConfig, } from './types.ts';
9
10
  export { DEFAULT_CHANGELOG_JSON_CONFIG, DEFAULT_RELEASE_NOTES_CONFIG, DEFAULT_VERSION_PATTERNS, DEFAULT_WORK_TYPES, } from './defaults.ts';
10
11
  export { buildReleaseSummary } from './buildReleaseSummary.ts';
11
12
  export { bumpAllVersions } from './bumpAllVersions.ts';
12
13
  export { bumpVersion } from './bumpVersion.ts';
13
14
  export { commitCommand } from './commitCommand.ts';
14
- export { component } from './component.ts';
15
15
  export type { CreateGithubReleaseOptions } from './createGithubRelease.ts';
16
16
  export { createGithubRelease, createGithubReleases } from './createGithubRelease.ts';
17
17
  export { createTags } from './createTags.ts';
18
18
  export { deleteFileIfExists } from './deleteFileIfExists.ts';
19
+ export { deriveWorkspaceConfig } from './deriveWorkspaceConfig.ts';
19
20
  export { detectPackageManager } from './detectPackageManager.ts';
20
21
  export { determineBumpType } from './determineBumpType.ts';
21
22
  export { discoverWorkspaces } from './discoverWorkspaces.ts';
22
23
  export { generateChangelogJson, generateSyntheticChangelogJson } from './generateChangelogJson.ts';
23
24
  export { generateChangelog, generateChangelogs } from './generateChangelogs.ts';
24
25
  export { getCommitsSinceTarget } from './getCommitsSinceTarget.ts';
25
- export { injectReleaseNotesIntoReadme, resolveReadmePath } from './injectReleaseNotesIntoReadme.ts';
26
+ export type { RenderedInjectedReadme } from './injectReleaseNotesIntoReadme.ts';
27
+ export { injectReleaseNotesIntoReadme, renderInjectedReadme, resolveReadmePath, } from './injectReleaseNotesIntoReadme.ts';
26
28
  export { injectSection } from './injectSection.ts';
27
29
  export { COMMIT_PREPROCESSOR_PATTERNS, parseCommitMessage } from './parseCommitMessage.ts';
28
30
  export { RELEASE_SUMMARY_FILE, RELEASE_TAGS_FILE, writeReleaseTags } from './prepareCommand.ts';
29
31
  export { publishPackage } from './publish.ts';
32
+ export type { PushReleaseOptions } from './pushRelease.ts';
33
+ export { pushRelease } from './pushRelease.ts';
30
34
  export { releasePrepare } from './releasePrepare.ts';
31
35
  export { releasePrepareMono } from './releasePrepareMono.ts';
32
36
  export type { RenderOptions } from './renderReleaseNotes.ts';
@@ -35,3 +39,5 @@ export { reportPrepare } from './reportPrepare.ts';
35
39
  export { resolveCommandTags } from './resolveCommandTags.ts';
36
40
  export { resolveReleaseTags } from './resolveReleaseTags.ts';
37
41
  export { stripScope } from './stripScope.ts';
42
+ export type { PreviewFileResult, WriteReleaseNotesPreviewsOptions, WriteReleaseNotesPreviewsResult, } from './writeReleaseNotesPreviews.ts';
43
+ export { writeReleaseNotesPreviews } from './writeReleaseNotesPreviews.ts';
package/dist/esm/index.js CHANGED
@@ -8,21 +8,26 @@ import { buildReleaseSummary } from "./buildReleaseSummary.js";
8
8
  import { bumpAllVersions } from "./bumpAllVersions.js";
9
9
  import { bumpVersion } from "./bumpVersion.js";
10
10
  import { commitCommand } from "./commitCommand.js";
11
- import { component } from "./component.js";
12
11
  import { createGithubRelease, createGithubReleases } from "./createGithubRelease.js";
13
12
  import { createTags } from "./createTags.js";
14
13
  import { deleteFileIfExists } from "./deleteFileIfExists.js";
14
+ import { deriveWorkspaceConfig } from "./deriveWorkspaceConfig.js";
15
15
  import { detectPackageManager } from "./detectPackageManager.js";
16
16
  import { determineBumpType } from "./determineBumpType.js";
17
17
  import { discoverWorkspaces } from "./discoverWorkspaces.js";
18
18
  import { generateChangelogJson, generateSyntheticChangelogJson } from "./generateChangelogJson.js";
19
19
  import { generateChangelog, generateChangelogs } from "./generateChangelogs.js";
20
20
  import { getCommitsSinceTarget } from "./getCommitsSinceTarget.js";
21
- import { injectReleaseNotesIntoReadme, resolveReadmePath } from "./injectReleaseNotesIntoReadme.js";
21
+ import {
22
+ injectReleaseNotesIntoReadme,
23
+ renderInjectedReadme,
24
+ resolveReadmePath
25
+ } from "./injectReleaseNotesIntoReadme.js";
22
26
  import { injectSection } from "./injectSection.js";
23
27
  import { COMMIT_PREPROCESSOR_PATTERNS, parseCommitMessage } from "./parseCommitMessage.js";
24
28
  import { RELEASE_SUMMARY_FILE, RELEASE_TAGS_FILE, writeReleaseTags } from "./prepareCommand.js";
25
29
  import { publishPackage } from "./publish.js";
30
+ import { pushRelease } from "./pushRelease.js";
26
31
  import { releasePrepare } from "./releasePrepare.js";
27
32
  import { releasePrepareMono } from "./releasePrepareMono.js";
28
33
  import { matchesAudience, renderReleaseNotesMulti, renderReleaseNotesSingle } from "./renderReleaseNotes.js";
@@ -30,6 +35,7 @@ import { reportPrepare } from "./reportPrepare.js";
30
35
  import { resolveCommandTags } from "./resolveCommandTags.js";
31
36
  import { resolveReleaseTags } from "./resolveReleaseTags.js";
32
37
  import { stripScope } from "./stripScope.js";
38
+ import { writeReleaseNotesPreviews } from "./writeReleaseNotesPreviews.js";
33
39
  export {
34
40
  COMMIT_PREPROCESSOR_PATTERNS,
35
41
  DEFAULT_CHANGELOG_JSON_CONFIG,
@@ -42,11 +48,11 @@ export {
42
48
  bumpAllVersions,
43
49
  bumpVersion,
44
50
  commitCommand,
45
- component,
46
51
  createGithubRelease,
47
52
  createGithubReleases,
48
53
  createTags,
49
54
  deleteFileIfExists,
55
+ deriveWorkspaceConfig,
50
56
  detectPackageManager,
51
57
  determineBumpType,
52
58
  discoverWorkspaces,
@@ -60,8 +66,10 @@ export {
60
66
  matchesAudience,
61
67
  parseCommitMessage,
62
68
  publishPackage,
69
+ pushRelease,
63
70
  releasePrepare,
64
71
  releasePrepareMono,
72
+ renderInjectedReadme,
65
73
  renderReleaseNotesMulti,
66
74
  renderReleaseNotesSingle,
67
75
  reportPrepare,
@@ -69,5 +77,6 @@ export {
69
77
  resolveReadmePath,
70
78
  resolveReleaseTags,
71
79
  stripScope,
80
+ writeReleaseNotesPreviews,
72
81
  writeReleaseTags
73
82
  };
@@ -4,13 +4,12 @@ function detectRepoType() {
4
4
  if (existsSync("pnpm-workspace.yaml")) {
5
5
  return "monorepo";
6
6
  }
7
- try {
7
+ if (existsSync("package.json")) {
8
8
  const raw = readFileSync("package.json", "utf8");
9
9
  const pkg = parseJsonRecord(raw);
10
10
  if (pkg !== void 0 && Array.isArray(pkg.workspaces)) {
11
11
  return "monorepo";
12
12
  }
13
- } catch {
14
13
  }
15
14
  return "single-package";
16
15
  }
@@ -1,4 +1,4 @@
1
- import { printError, printStep, printSuccess, reportWriteResult } from "@williamthorsen/node-monorepo-core";
1
+ import { printError, printStep, printSuccess, reportWriteResult } from "@williamthorsen/nmr-core";
2
2
  import { hasPackageJson, isGitRepo, usesPnpm } from "./checks.js";
3
3
  import { detectRepoType } from "./detectRepoType.js";
4
4
  import { scaffoldFiles } from "./scaffold.js";
@@ -1,4 +1,4 @@
1
- import type { WriteResult } from '@williamthorsen/node-monorepo-core';
1
+ import type { WriteResult } from '@williamthorsen/nmr-core';
2
2
  import type { RepoType } from './detectRepoType.ts';
3
3
  interface ScaffoldOptions {
4
4
  repoType: RepoType;
@@ -1,8 +1,7 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
- import { writeFileWithCheck } from "@williamthorsen/node-monorepo-core";
4
- import { findPackageRoot } from "../findPackageRoot.js";
5
- import { publishWorkflow, releaseConfigScript, releaseWorkflow } from "./templates.js";
3
+ import { findPackageRoot, writeFileWithCheck } from "@williamthorsen/nmr-core";
4
+ import { createGithubReleaseWorkflow, publishWorkflow, releaseConfigScript, releaseWorkflow } from "./templates.js";
6
5
  function copyCliffTemplate(dryRun, overwrite) {
7
6
  const destPath = ".config/git-cliff.toml";
8
7
  const root = findPackageRoot(import.meta.url);
@@ -21,8 +20,12 @@ function copyCliffTemplate(dryRun, overwrite) {
21
20
  }
22
21
  function scaffoldFiles({ repoType, dryRun, overwrite, withConfig }) {
23
22
  const results = [
24
- writeFileWithCheck(".github/workflows/release.yaml", releaseWorkflow(repoType), { dryRun, overwrite }),
25
- writeFileWithCheck(".github/workflows/publish.yaml", publishWorkflow(repoType), { dryRun, overwrite })
23
+ writeFileWithCheck(".github/workflows/create-github-release.yaml", createGithubReleaseWorkflow(repoType), {
24
+ dryRun,
25
+ overwrite
26
+ }),
27
+ writeFileWithCheck(".github/workflows/publish.yaml", publishWorkflow(repoType), { dryRun, overwrite }),
28
+ writeFileWithCheck(".github/workflows/release.yaml", releaseWorkflow(repoType), { dryRun, overwrite })
26
29
  ];
27
30
  if (withConfig) {
28
31
  results.push(
@@ -1,4 +1,5 @@
1
1
  import type { RepoType } from './detectRepoType.ts';
2
2
  export declare function releaseConfigScript(repoType: RepoType): string;
3
3
  export declare function publishWorkflow(repoType: RepoType): string;
4
+ export declare function createGithubReleaseWorkflow(repoType: RepoType): string;
4
5
  export declare function releaseWorkflow(repoType: RepoType): string;
@@ -3,8 +3,12 @@ function releaseConfigScript(repoType) {
3
3
  return `import type { ReleaseKitConfig } from '@williamthorsen/release-kit';
4
4
 
5
5
  const config: ReleaseKitConfig = {
6
- // Uncomment to exclude components from release processing:
7
- // components: [
6
+ releaseNotes: {
7
+ shouldInjectIntoReadme: true,
8
+ },
9
+
10
+ // Uncomment to exclude workspaces from release processing:
11
+ // workspaces: [
8
12
  // { dir: 'my-package', shouldExclude: true },
9
13
  // ],
10
14
 
@@ -23,6 +27,10 @@ export default config;
23
27
  return `import type { ReleaseKitConfig } from '@williamthorsen/release-kit';
24
28
 
25
29
  const config: ReleaseKitConfig = {
30
+ releaseNotes: {
31
+ shouldInjectIntoReadme: true,
32
+ },
33
+
26
34
  // Formatting: prettier is auto-detected. Set formatCommand to override.
27
35
 
28
36
  // Uncomment to override the default version patterns:
@@ -36,7 +44,7 @@ export default config;
36
44
  `;
37
45
  }
38
46
  function publishWorkflow(repoType) {
39
- const tagPattern = repoType === "monorepo" ? "'*-v[0-9]*'" : "'v[0-9]*'";
47
+ const tagPattern = repoType === "monorepo" ? "'*-v[0-9]*.[0-9]*.[0-9]*'" : "'v[0-9]*.[0-9]*.[0-9]*'";
40
48
  return `# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
41
49
  name: Publish
42
50
 
@@ -51,9 +59,30 @@ permissions:
51
59
 
52
60
  jobs:
53
61
  publish:
54
- uses: williamthorsen/node-monorepo-tools/.github/workflows/publish.reusable.yaml@publish-workflow-v1
62
+ uses: williamthorsen/node-monorepo-tools/.github/workflows/publish.reusable.yaml@workflow/publish-v1
63
+ with:
64
+ provenance: true
65
+ tags: \${{ github.ref_name }}
66
+ `;
67
+ }
68
+ function createGithubReleaseWorkflow(repoType) {
69
+ const tagPattern = repoType === "monorepo" ? "'*-v[0-9]*.[0-9]*.[0-9]*'" : "'v[0-9]*.[0-9]*.[0-9]*'";
70
+ return `# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
71
+ name: Create GitHub Release
72
+
73
+ on:
74
+ push:
75
+ tags:
76
+ - ${tagPattern}
77
+
78
+ permissions:
79
+ contents: write
80
+
81
+ jobs:
82
+ create-github-release:
83
+ uses: williamthorsen/node-monorepo-tools/.github/workflows/create-github-release.reusable.yaml@workflow/create-github-release-v1
55
84
  with:
56
- provenance: false # Set to true for public repos to generate npm provenance attestations
85
+ tag: \${{ github.ref_name }}
57
86
  `;
58
87
  }
59
88
  function releaseWorkflow(repoType) {
@@ -65,7 +94,7 @@ on:
65
94
  workflow_dispatch:
66
95
  inputs:
67
96
  only:
68
- description: 'Components to release (comma-separated, leave empty for all)'
97
+ description: 'Workspaces to release (comma-separated, leave empty for all)'
69
98
  required: false
70
99
  type: string
71
100
  bump:
@@ -78,7 +107,7 @@ on:
78
107
  - minor
79
108
  - major
80
109
  force:
81
- description: 'Force a version bump even when there are no release-worthy changes'
110
+ description: 'Force a release even when there are no commits since the last tag (requires --bump)'
82
111
  required: false
83
112
  type: boolean
84
113
  default: false
@@ -89,7 +118,7 @@ permissions:
89
118
 
90
119
  jobs:
91
120
  release:
92
- uses: williamthorsen/node-monorepo-tools/.github/workflows/release.reusable.yaml@release-workflow-v1
121
+ uses: williamthorsen/node-monorepo-tools/.github/workflows/release.reusable.yaml@workflow/release-v1
93
122
  with:
94
123
  only: \${{ inputs.only }}
95
124
  bump: \${{ inputs.bump }}
@@ -112,7 +141,7 @@ on:
112
141
  - minor
113
142
  - major
114
143
  force:
115
- description: 'Force a version bump even when there are no release-worthy changes'
144
+ description: 'Force a release even when there are no commits since the last tag (requires --bump)'
116
145
  required: false
117
146
  type: boolean
118
147
  default: false
@@ -123,13 +152,14 @@ permissions:
123
152
 
124
153
  jobs:
125
154
  release:
126
- uses: williamthorsen/node-monorepo-tools/.github/workflows/release.reusable.yaml@release-workflow-v1
155
+ uses: williamthorsen/node-monorepo-tools/.github/workflows/release.reusable.yaml@workflow/release-v1
127
156
  with:
128
157
  bump: \${{ inputs.bump }}
129
158
  force: \${{ inputs.force }}
130
159
  `;
131
160
  }
132
161
  export {
162
+ createGithubReleaseWorkflow,
133
163
  publishWorkflow,
134
164
  releaseConfigScript,
135
165
  releaseWorkflow
@@ -1,2 +1,7 @@
1
- export declare function injectReleaseNotesIntoReadme(readmePath: string, changelogJsonPath: string, tag: string): string | undefined;
1
+ export interface RenderedInjectedReadme {
2
+ injectedReadme: string;
3
+ releaseNotesMarkdown: string;
4
+ }
5
+ export declare function renderInjectedReadme(readme: string, changelogJsonPath: string, tag: string, sectionOrder?: string[]): RenderedInjectedReadme | undefined;
6
+ export declare function injectReleaseNotesIntoReadme(readmePath: string, changelogJsonPath: string, tag: string, sectionOrder?: string[]): string | undefined;
2
7
  export declare function resolveReadmePath(workspacePath: string): string | undefined;
@@ -3,12 +3,11 @@ import { join } from "node:path";
3
3
  import { extractVersion, readChangelogEntries } from "./changelogJsonUtils.js";
4
4
  import { injectSection } from "./injectSection.js";
5
5
  import { matchesAudience, renderReleaseNotesSingle } from "./renderReleaseNotes.js";
6
- function injectReleaseNotesIntoReadme(readmePath, changelogJsonPath, tag) {
6
+ function renderInjectedReadme(readme, changelogJsonPath, tag, sectionOrder) {
7
7
  if (!existsSync(changelogJsonPath)) {
8
8
  console.warn(`Warning: ${changelogJsonPath} not found; skipping README injection`);
9
9
  return void 0;
10
10
  }
11
- const originalReadme = readFileSync(readmePath, "utf8");
12
11
  const version = extractVersion(tag);
13
12
  const entries = readChangelogEntries(changelogJsonPath);
14
13
  if (entries === void 0) {
@@ -20,16 +19,29 @@ function injectReleaseNotesIntoReadme(readmePath, changelogJsonPath, tag) {
20
19
  console.warn(`Warning: no changelog entry for version ${version}; skipping README injection`);
21
20
  return void 0;
22
21
  }
23
- const releaseNotesMarkdown = renderReleaseNotesSingle(entry, {
22
+ const renderedSections = renderReleaseNotesSingle(entry, {
24
23
  filter: matchesAudience("all"),
25
- includeHeading: false
24
+ includeHeading: false,
25
+ ...sectionOrder === void 0 ? {} : { sectionOrder }
26
26
  });
27
- if (releaseNotesMarkdown.trimEnd().length === 0) {
27
+ if (renderedSections.trimEnd().length === 0) {
28
28
  console.warn(`Warning: no user-facing release notes for version ${version}; skipping README injection`);
29
29
  return void 0;
30
30
  }
31
- const injected = injectSection(originalReadme, "release-notes", releaseNotesMarkdown.trimEnd());
32
- writeFileSync(readmePath, injected, "utf8");
31
+ const labeledHeading = `## Release notes \u2014 v${version} (${entry.date})`;
32
+ const releaseNotesMarkdown = `${labeledHeading}
33
+
34
+ ${renderedSections.trimEnd()}`;
35
+ const injectedReadme = injectSection(readme, "release-notes", releaseNotesMarkdown);
36
+ return { injectedReadme, releaseNotesMarkdown };
37
+ }
38
+ function injectReleaseNotesIntoReadme(readmePath, changelogJsonPath, tag, sectionOrder) {
39
+ const originalReadme = readFileSync(readmePath, "utf8");
40
+ const rendered = renderInjectedReadme(originalReadme, changelogJsonPath, tag, sectionOrder);
41
+ if (rendered === void 0) {
42
+ return void 0;
43
+ }
44
+ writeFileSync(readmePath, rendered.injectedReadme, "utf8");
33
45
  return originalReadme;
34
46
  }
35
47
  function resolveReadmePath(workspacePath) {
@@ -38,5 +50,6 @@ function resolveReadmePath(workspacePath) {
38
50
  }
39
51
  export {
40
52
  injectReleaseNotesIntoReadme,
53
+ renderInjectedReadme,
41
54
  resolveReadmePath
42
55
  };
@@ -1,5 +1,6 @@
1
- import type { MonorepoReleaseConfig, ReleaseConfig, ReleaseKitConfig } from './types.ts';
1
+ import type { MonorepoReleaseConfig, ReleaseConfig, ReleaseKitConfig, WorkTypeConfig } from './types.ts';
2
2
  export declare const CONFIG_FILE_PATH = ".config/release-kit.config.ts";
3
3
  export declare function loadConfig(): Promise<unknown>;
4
4
  export declare function mergeMonorepoConfig(discoveredPaths: string[], userConfig: ReleaseKitConfig | undefined): MonorepoReleaseConfig;
5
5
  export declare function mergeSinglePackageConfig(userConfig: ReleaseKitConfig | undefined): ReleaseConfig;
6
+ export declare function resolveWorkTypes(userWorkTypes?: Record<string, WorkTypeConfig>): Record<string, WorkTypeConfig>;
@@ -1,12 +1,12 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import path from "node:path";
3
- import { component } from "./component.js";
4
3
  import {
5
4
  DEFAULT_CHANGELOG_JSON_CONFIG,
6
5
  DEFAULT_RELEASE_NOTES_CONFIG,
7
6
  DEFAULT_VERSION_PATTERNS,
8
7
  DEFAULT_WORK_TYPES
9
8
  } from "./defaults.js";
9
+ import { deriveWorkspaceConfig } from "./deriveWorkspaceConfig.js";
10
10
  import { isRecord } from "./typeGuards.js";
11
11
  const CONFIG_FILE_PATH = ".config/release-kit.config.ts";
12
12
  async function loadConfig() {
@@ -29,20 +29,31 @@ async function loadConfig() {
29
29
  return resolved;
30
30
  }
31
31
  function mergeMonorepoConfig(discoveredPaths, userConfig) {
32
- let components = discoveredPaths.map((workspacePath) => component(workspacePath));
33
- if (userConfig?.components !== void 0) {
34
- const overrides = new Map(userConfig.components.map((c) => [c.dir, c]));
35
- components = components.filter((c) => {
36
- const override = overrides.get(c.dir);
32
+ let workspaces = discoveredPaths.map((workspacePath) => deriveWorkspaceConfig(workspacePath));
33
+ assertUniqueTagPrefixes(workspaces);
34
+ if (userConfig?.workspaces !== void 0) {
35
+ const overrides = new Map(userConfig.workspaces.map((w) => [w.dir, w]));
36
+ workspaces = workspaces.filter((w) => {
37
+ const override = overrides.get(w.dir);
37
38
  return override?.shouldExclude !== true;
39
+ }).map((w) => {
40
+ const override = overrides.get(w.dir);
41
+ if (override?.legacyIdentities === void 0) {
42
+ return w;
43
+ }
44
+ assertLegacyIdentityDoesNotMatchCurrent(w.dir, w.name, w.tagPrefix, override.legacyIdentities);
45
+ return { ...w, legacyIdentities: override.legacyIdentities.map((identity) => ({ ...identity })) };
38
46
  });
39
47
  }
40
- const workTypes = userConfig?.workTypes === void 0 ? { ...DEFAULT_WORK_TYPES } : { ...DEFAULT_WORK_TYPES, ...userConfig.workTypes };
48
+ if (userConfig?.retiredPackages !== void 0) {
49
+ assertRetiredPackagesDoNotCollideWithActive(workspaces, userConfig.retiredPackages);
50
+ }
51
+ const workTypes = resolveWorkTypes(userConfig?.workTypes);
41
52
  const versionPatterns = userConfig?.versionPatterns === void 0 ? { ...DEFAULT_VERSION_PATTERNS } : { ...userConfig.versionPatterns };
42
53
  const changelogJson = mergeChangelogJsonConfig(userConfig?.changelogJson);
43
54
  const releaseNotes = mergeReleaseNotesConfig(userConfig?.releaseNotes);
44
55
  const result = {
45
- components,
56
+ workspaces,
46
57
  workTypes,
47
58
  versionPatterns,
48
59
  changelogJson,
@@ -63,7 +74,7 @@ function mergeMonorepoConfig(discoveredPaths, userConfig) {
63
74
  return result;
64
75
  }
65
76
  function mergeSinglePackageConfig(userConfig) {
66
- const workTypes = userConfig?.workTypes === void 0 ? { ...DEFAULT_WORK_TYPES } : { ...DEFAULT_WORK_TYPES, ...userConfig.workTypes };
77
+ const workTypes = resolveWorkTypes(userConfig?.workTypes);
67
78
  const versionPatterns = userConfig?.versionPatterns === void 0 ? { ...DEFAULT_VERSION_PATTERNS } : { ...userConfig.versionPatterns };
68
79
  const changelogJson = mergeChangelogJsonConfig(userConfig?.changelogJson);
69
80
  const releaseNotes = mergeReleaseNotesConfig(userConfig?.releaseNotes);
@@ -90,6 +101,9 @@ function mergeSinglePackageConfig(userConfig) {
90
101
  }
91
102
  return result;
92
103
  }
104
+ function resolveWorkTypes(userWorkTypes) {
105
+ return userWorkTypes === void 0 ? { ...DEFAULT_WORK_TYPES } : { ...DEFAULT_WORK_TYPES, ...userWorkTypes };
106
+ }
93
107
  function mergeChangelogJsonConfig(partial) {
94
108
  if (partial === void 0) {
95
109
  return { ...DEFAULT_CHANGELOG_JSON_CONFIG };
@@ -100,18 +114,57 @@ function mergeChangelogJsonConfig(partial) {
100
114
  devOnlySections: partial.devOnlySections ?? [...DEFAULT_CHANGELOG_JSON_CONFIG.devOnlySections]
101
115
  };
102
116
  }
117
+ function assertLegacyIdentityDoesNotMatchCurrent(dir, currentName, currentTagPrefix, legacyIdentities) {
118
+ for (const identity of legacyIdentities) {
119
+ if (identity.name === currentName && identity.tagPrefix === currentTagPrefix) {
120
+ throw new Error(
121
+ `Workspace '${dir}': legacyIdentities must not match the current identity (name='${currentName}', tagPrefix='${currentTagPrefix}'). The current identity is always searched; listing it again is a no-op.`
122
+ );
123
+ }
124
+ }
125
+ }
126
+ function assertRetiredPackagesDoNotCollideWithActive(workspaces, retiredPackages) {
127
+ const workspaceByDerivedPrefix = /* @__PURE__ */ new Map();
128
+ for (const workspace of workspaces) {
129
+ workspaceByDerivedPrefix.set(workspace.tagPrefix, workspace);
130
+ }
131
+ for (const retired of retiredPackages) {
132
+ const active = workspaceByDerivedPrefix.get(retired.tagPrefix);
133
+ if (active !== void 0) {
134
+ throw new Error(
135
+ `retiredPackages: tagPrefix '${retired.tagPrefix}' collides with active workspace '${active.dir}' (derived prefix '${active.tagPrefix}'). A retired package's tagPrefix cannot belong to an active workspace.`
136
+ );
137
+ }
138
+ }
139
+ }
140
+ function assertUniqueTagPrefixes(workspaces) {
141
+ const pathsByPrefix = /* @__PURE__ */ new Map();
142
+ for (const workspace of workspaces) {
143
+ const existing = pathsByPrefix.get(workspace.tagPrefix);
144
+ if (existing === void 0) {
145
+ pathsByPrefix.set(workspace.tagPrefix, [workspace.workspacePath]);
146
+ } else {
147
+ existing.push(workspace.workspacePath);
148
+ }
149
+ }
150
+ for (const [prefix, paths] of pathsByPrefix) {
151
+ if (paths.length > 1) {
152
+ throw new Error(`Duplicate tag prefix '${prefix}' for workspaces: ${paths.join(", ")}`);
153
+ }
154
+ }
155
+ }
103
156
  function mergeReleaseNotesConfig(partial) {
104
157
  if (partial === void 0) {
105
158
  return { ...DEFAULT_RELEASE_NOTES_CONFIG };
106
159
  }
107
160
  return {
108
- shouldInjectIntoReadme: partial.shouldInjectIntoReadme ?? DEFAULT_RELEASE_NOTES_CONFIG.shouldInjectIntoReadme,
109
- shouldCreateGithubRelease: partial.shouldCreateGithubRelease ?? DEFAULT_RELEASE_NOTES_CONFIG.shouldCreateGithubRelease
161
+ shouldInjectIntoReadme: partial.shouldInjectIntoReadme ?? DEFAULT_RELEASE_NOTES_CONFIG.shouldInjectIntoReadme
110
162
  };
111
163
  }
112
164
  export {
113
165
  CONFIG_FILE_PATH,
114
166
  loadConfig,
115
167
  mergeMonorepoConfig,
116
- mergeSinglePackageConfig
168
+ mergeSinglePackageConfig,
169
+ resolveWorkTypes
117
170
  };
@@ -0,0 +1 @@
1
+ export declare function parseRequestedTags(flagValue: string | undefined): string[] | undefined;
@@ -0,0 +1,10 @@
1
+ function parseRequestedTags(flagValue) {
2
+ if (flagValue === void 0) {
3
+ return void 0;
4
+ }
5
+ const segments = flagValue.split(",").filter(Boolean);
6
+ return segments.length === 0 ? void 0 : segments;
7
+ }
8
+ export {
9
+ parseRequestedTags
10
+ };
@@ -1,4 +1,4 @@
1
- import type { WriteResult } from '@williamthorsen/node-monorepo-core';
1
+ import type { WriteResult } from '@williamthorsen/nmr-core';
2
2
  import type { ReleaseType } from './types.ts';
3
3
  export declare const RELEASE_TAGS_FILE = "tmp/.release-tags";
4
4
  export declare const RELEASE_SUMMARY_FILE = "tmp/.release-summary";
@@ -8,6 +8,8 @@ export declare function parseArgs(argv: string[]): {
8
8
  noGitChecks: boolean;
9
9
  bumpOverride: ReleaseType | undefined;
10
10
  only: string[] | undefined;
11
+ setVersion: string | undefined;
12
+ withReleaseNotes: boolean;
11
13
  };
12
14
  export declare function writeReleaseTags(tags: string[], dryRun: boolean): WriteResult | undefined;
13
15
  export declare function prepareCommand(argv: string[]): Promise<void>;