@williamthorsen/release-kit 15.0.2 → 16.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 (138) hide show
  1. package/.meta/changelog.json +88 -0
  2. package/.readyup/kits/default.js +14 -14
  3. package/.readyup/kits/npm-auto-publish.js +5 -5
  4. package/.readyup/manifest.json +14 -14
  5. package/CHANGELOG.md +28 -0
  6. package/README.md +3 -3
  7. package/dist/esm/applyChangelogOverrides.js +6 -6
  8. package/dist/esm/assertCleanWorkingTree.js +2 -2
  9. package/dist/esm/assertReleasesOnNpm.js +11 -11
  10. package/dist/esm/assertTaggedBaseline.js +5 -5
  11. package/dist/esm/bin/release-kit.js +16 -16
  12. package/dist/esm/buildChangelogEntries.d.ts +19 -19
  13. package/dist/esm/buildChangelogEntries.js +40 -36
  14. package/dist/esm/buildChangelogItem.js +24 -24
  15. package/dist/esm/buildDependencyGraph.js +23 -23
  16. package/dist/esm/buildReleasedResult.js +21 -19
  17. package/dist/esm/buildSyntheticChangelogEntry.js +2 -2
  18. package/dist/esm/bumpVersion.js +8 -8
  19. package/dist/esm/changelogArchive.d.ts +1 -1
  20. package/dist/esm/changelogArchive.js +2 -2
  21. package/dist/esm/changelogJsonFile.js +5 -5
  22. package/dist/esm/changelogJsonUtils.js +3 -3
  23. package/dist/esm/changelogOverrides.d.ts +5 -5
  24. package/dist/esm/changelogOverrides.js +23 -23
  25. package/dist/esm/classifyChangelogCommit.js +4 -4
  26. package/dist/esm/commitCommand.js +7 -7
  27. package/dist/esm/compareVersions.js +13 -13
  28. package/dist/esm/configSchema.d.ts +2 -2
  29. package/dist/esm/configSchema.js +1 -1
  30. package/dist/esm/createGithubRelease.d.ts +4 -4
  31. package/dist/esm/createGithubRelease.js +10 -10
  32. package/dist/esm/createGithubReleaseCommand.js +9 -9
  33. package/dist/esm/createTags.d.ts +2 -2
  34. package/dist/esm/createTags.js +12 -12
  35. package/dist/esm/decideDirectReleases.d.ts +5 -5
  36. package/dist/esm/decideDirectReleases.js +25 -25
  37. package/dist/esm/decideRelease.d.ts +1 -1
  38. package/dist/esm/decideRelease.js +2 -2
  39. package/dist/esm/deriveDirectoryConfig.d.ts +1 -1
  40. package/dist/esm/deriveDirectoryConfig.js +18 -18
  41. package/dist/esm/deriveWorkspaceConfig.js +4 -4
  42. package/dist/esm/detectPackageManager.js +5 -5
  43. package/dist/esm/detectUndeclaredTagPrefixes.js +8 -8
  44. package/dist/esm/enumerateReleaseWindows.d.ts +1 -1
  45. package/dist/esm/enumerateReleaseWindows.js +9 -9
  46. package/dist/esm/findTransitiveDependents.js +5 -5
  47. package/dist/esm/findUnroutedEntryScopes.js +11 -11
  48. package/dist/esm/format.d.ts +1 -1
  49. package/dist/esm/format.js +1 -1
  50. package/dist/esm/formatPrepareFiles.d.ts +3 -3
  51. package/dist/esm/formatPrepareFiles.js +10 -10
  52. package/dist/esm/formatPrepareWarnings.js +6 -6
  53. package/dist/esm/hasPrettierConfig.js +2 -2
  54. package/dist/esm/init/checks.js +7 -5
  55. package/dist/esm/init/detectRepoType.js +3 -3
  56. package/dist/esm/init/initCommand.d.ts +4 -4
  57. package/dist/esm/init/initCommand.js +7 -7
  58. package/dist/esm/init/parseJsonRecord.d.ts +1 -1
  59. package/dist/esm/init/parseJsonRecord.js +4 -4
  60. package/dist/esm/init/scaffold.d.ts +4 -4
  61. package/dist/esm/init/scaffold.js +18 -9
  62. package/dist/esm/init/templates.d.ts +10 -10
  63. package/dist/esm/init/templates.js +5 -5
  64. package/dist/esm/init/updateTemplatesCommand.d.ts +2 -2
  65. package/dist/esm/init/updateTemplatesCommand.js +16 -14
  66. package/dist/esm/injectReleaseNotesIntoReadme.d.ts +1 -1
  67. package/dist/esm/injectReleaseNotesIntoReadme.js +6 -6
  68. package/dist/esm/injectSection.js +8 -8
  69. package/dist/esm/loadChangelogOverrides.d.ts +1 -1
  70. package/dist/esm/loadChangelogOverrides.js +9 -9
  71. package/dist/esm/loadConfig.d.ts +3 -3
  72. package/dist/esm/loadConfig.js +10 -10
  73. package/dist/esm/loadValidatedConfig.js +4 -4
  74. package/dist/esm/mergeConfig.d.ts +1 -1
  75. package/dist/esm/mergeConfig.js +27 -27
  76. package/dist/esm/monorepoConfigAssertions.js +15 -15
  77. package/dist/esm/npmRegistry.js +4 -4
  78. package/dist/esm/packsPath.js +3 -3
  79. package/dist/esm/parseChangeRecordBlock.js +33 -33
  80. package/dist/esm/parseCommitMessage.js +5 -5
  81. package/dist/esm/planChangelogFiles.js +8 -8
  82. package/dist/esm/planReleaseNotesPreviews.js +10 -10
  83. package/dist/esm/planVersionBump.js +24 -16
  84. package/dist/esm/prepareArgs.d.ts +9 -9
  85. package/dist/esm/prepareArgs.js +11 -11
  86. package/dist/esm/prepareCommand.js +23 -23
  87. package/dist/esm/prepareComposite.d.ts +4 -4
  88. package/dist/esm/prepareComposite.js +16 -16
  89. package/dist/esm/{releasePrepareTargets.d.ts → prepareReleaseTargets.d.ts} +9 -9
  90. package/dist/esm/{releasePrepareTargets.js → prepareReleaseTargets.js} +40 -40
  91. package/dist/esm/prepareRunContext.d.ts +1 -1
  92. package/dist/esm/prepareRunContext.js +5 -5
  93. package/dist/esm/prepareTarget.d.ts +3 -3
  94. package/dist/esm/prepareTarget.js +41 -39
  95. package/dist/esm/previewTagPrefixes.js +21 -21
  96. package/dist/esm/propagateBumps.js +8 -8
  97. package/dist/esm/publish.d.ts +2 -2
  98. package/dist/esm/publish.js +5 -5
  99. package/dist/esm/publishCommand.js +20 -20
  100. package/dist/esm/pushCommand.js +8 -8
  101. package/dist/esm/pushRelease.d.ts +1 -1
  102. package/dist/esm/pushRelease.js +4 -4
  103. package/dist/esm/readChangelogSections.d.ts +1 -1
  104. package/dist/esm/readChangelogSections.js +16 -16
  105. package/dist/esm/releasePlan.js +26 -26
  106. package/dist/esm/renderChangelogMarkdown.d.ts +4 -4
  107. package/dist/esm/renderChangelogMarkdown.js +18 -15
  108. package/dist/esm/renderReleaseNotes.d.ts +1 -1
  109. package/dist/esm/renderReleaseNotes.js +16 -16
  110. package/dist/esm/reportPrepare.js +34 -34
  111. package/dist/esm/resolveCommandTags.js +9 -9
  112. package/dist/esm/resolveReleaseDeclaration.d.ts +2 -2
  113. package/dist/esm/resolveReleaseDeclaration.js +22 -22
  114. package/dist/esm/resolveReleaseTags.js +19 -17
  115. package/dist/esm/resolveReleaseTargets.js +2 -2
  116. package/dist/esm/showTagPrefixesCommand.js +4 -4
  117. package/dist/esm/sync-labels/generateCommand.d.ts +3 -3
  118. package/dist/esm/sync-labels/generateCommand.js +10 -10
  119. package/dist/esm/sync-labels/initCommand.d.ts +3 -3
  120. package/dist/esm/sync-labels/initCommand.js +23 -15
  121. package/dist/esm/sync-labels/presets.js +3 -3
  122. package/dist/esm/sync-labels/resolveLabels.js +13 -13
  123. package/dist/esm/sync-labels/syncCommand.js +2 -2
  124. package/dist/esm/sync-labels/templates.d.ts +4 -4
  125. package/dist/esm/sync-labels/templates.js +13 -40
  126. package/dist/esm/tagCommand.js +4 -4
  127. package/dist/esm/topologicalSort.d.ts +2 -2
  128. package/dist/esm/topologicalSort.js +7 -7
  129. package/dist/esm/types.d.ts +3 -3
  130. package/dist/esm/validateAllChangelogOverrides.js +9 -9
  131. package/dist/esm/validateConfig.d.ts +1 -1
  132. package/dist/esm/validateConfig.js +60 -50
  133. package/dist/esm/validateOverridesCommand.js +2 -2
  134. package/docs/changelogs.md +5 -5
  135. package/docs/configuration.md +1 -1
  136. package/docs/work-types.md +1 -1
  137. package/package.json +9 -8
  138. package/templates/sync-labels.yaml.template +36 -0
@@ -1,5 +1,5 @@
1
1
  import { execFileSync } from 'node:child_process';
2
- import { GIT_OUTPUT_LIMIT } from '@williamthorsen/nmr-core';
2
+ import { GIT_OUTPUT_LIMIT_BYTES } from '@williamthorsen/nmr-core';
3
3
  import { chainError } from '@williamthorsen/toolbelt.errors/candidate';
4
4
  import { matchesTagPrefix } from "./matchesTagPrefix.js";
5
5
  const FIELD_SEPARATOR = '\u{1F}';
@@ -11,7 +11,7 @@ export function enumerateReleaseWindows(options) {
11
11
  }
12
12
  const unreleasedWindow = {
13
13
  version: unreleasedTag,
14
- timestamp: Math.floor(now() / 1_000),
14
+ timestampSec: Math.floor(now() / 1_000),
15
15
  commits: [],
16
16
  };
17
17
  const ancestry = readAncestry();
@@ -21,7 +21,7 @@ export function enumerateReleaseWindows(options) {
21
21
  const boundaries = readTagBoundaries(tagPrefixes, ancestry.positionByHash);
22
22
  const releasedWindows = boundaries.map((boundary) => ({
23
23
  version: boundary.tag,
24
- timestamp: boundary.timestamp,
24
+ timestampSec: boundary.timestampSec,
25
25
  commits: [],
26
26
  }));
27
27
  const windowIndexByHash = claimAncestors(boundaries, ancestry.parentsByHash);
@@ -35,14 +35,14 @@ export function enumerateReleaseWindows(options) {
35
35
  function claimAncestors(boundaries, parentsByHash) {
36
36
  const windowIndexByHash = new Map();
37
37
  for (const [windowIndex, boundary] of boundaries.entries()) {
38
- const pending = [boundary.hash];
39
- while (pending.length > 0) {
40
- const hash = pending.pop();
38
+ const pendingHashes = [boundary.hash];
39
+ while (pendingHashes.length > 0) {
40
+ const hash = pendingHashes.pop();
41
41
  if (hash === undefined || windowIndexByHash.has(hash)) {
42
42
  continue;
43
43
  }
44
44
  windowIndexByHash.set(hash, windowIndex);
45
- pending.push(...(parentsByHash.get(hash) ?? []));
45
+ pendingHashes.push(...(parentsByHash.get(hash) ?? []));
46
46
  }
47
47
  }
48
48
  return windowIndexByHash;
@@ -103,7 +103,7 @@ function readTagBoundaries(tagPrefixes, positionByHash) {
103
103
  const hash = dereferencedName || objectName;
104
104
  const position = positionByHash.get(hash);
105
105
  if (position !== undefined) {
106
- boundaries.push({ hash, position, tag, timestamp: Number(creatorDate) });
106
+ boundaries.push({ hash, position, tag, timestampSec: Number(creatorDate) });
107
107
  }
108
108
  }
109
109
  return boundaries.toSorted((left, right) => right.position - left.position);
@@ -112,7 +112,7 @@ function runGit(args, description) {
112
112
  try {
113
113
  return execFileSync('git', args, {
114
114
  encoding: 'utf8',
115
- maxBuffer: GIT_OUTPUT_LIMIT,
115
+ maxBuffer: GIT_OUTPUT_LIMIT_BYTES,
116
116
  stdio: ['pipe', 'pipe', 'pipe'],
117
117
  }).trim();
118
118
  }
@@ -1,6 +1,6 @@
1
1
  export function findTransitiveDependents(graph, startDirs) {
2
- const found = new Set(startDirs);
3
- const queue = [...found];
2
+ const foundDirs = new Set(startDirs);
3
+ const queue = [...foundDirs];
4
4
  while (queue.length > 0) {
5
5
  const dir = queue.shift();
6
6
  if (dir === undefined)
@@ -10,11 +10,11 @@ export function findTransitiveDependents(graph, startDirs) {
10
10
  continue;
11
11
  const dependents = graph.dependentsOf.get(packageName) ?? [];
12
12
  for (const dependent of dependents) {
13
- if (found.has(dependent.id))
13
+ if (foundDirs.has(dependent.id))
14
14
  continue;
15
- found.add(dependent.id);
15
+ foundDirs.add(dependent.id);
16
16
  queue.push(dependent.id);
17
17
  }
18
18
  }
19
- return found;
19
+ return foundDirs;
20
20
  }
@@ -28,11 +28,11 @@ function findCommitUnroutedScopes(commit, windowDirs, unreadDirs, isRootReserved
28
28
  for (const [index, entry] of reading.entries.entries()) {
29
29
  const scopes = new Set(entry.scopes);
30
30
  for (const scope of scopes) {
31
- const resolved = scopeAliases[scope] ?? scope;
32
- const isRouted = resolved === '*' ||
33
- windowDirs.has(resolved) ||
34
- unreadDirs.has(resolved) ||
35
- (resolved === 'root' && isRootReserved);
31
+ const resolvedScope = scopeAliases[scope] ?? scope;
32
+ const isRouted = resolvedScope === '*' ||
33
+ windowDirs.has(resolvedScope) ||
34
+ unreadDirs.has(resolvedScope) ||
35
+ (resolvedScope === 'root' && isRootReserved);
36
36
  if (!isRouted) {
37
37
  findings.push({ commitHash: commit.hash, commitSubject: commit.subject, entryPosition: index + 1, scope });
38
38
  }
@@ -41,17 +41,17 @@ function findCommitUnroutedScopes(commit, windowDirs, unreadDirs, isRootReserved
41
41
  return findings;
42
42
  }
43
43
  function indexCommits(windows) {
44
- const index = new Map();
44
+ const commitsByHash = new Map();
45
45
  for (const window of windows) {
46
46
  for (const commit of window.commits) {
47
- const indexed = index.get(commit.hash);
48
- if (indexed === undefined) {
49
- index.set(commit.hash, { commit, windowDirs: new Set([window.dir]) });
47
+ const indexedEntry = commitsByHash.get(commit.hash);
48
+ if (indexedEntry === undefined) {
49
+ commitsByHash.set(commit.hash, { commit, windowDirs: new Set([window.dir]) });
50
50
  }
51
51
  else {
52
- indexed.windowDirs.add(window.dir);
52
+ indexedEntry.windowDirs.add(window.dir);
53
53
  }
54
54
  }
55
55
  }
56
- return index;
56
+ return commitsByHash;
57
57
  }
@@ -3,4 +3,4 @@ export declare function bold(text: string, stream?: NodeJS.WritableStream): stri
3
3
  /** Styles text dim, returning it unstyled for a stream that cannot render color. */
4
4
  export declare function dim(text: string, stream?: NodeJS.WritableStream): string;
5
5
  /** Renders a section header for separating workspaces in CLI output. */
6
- export declare function sectionHeader(name: string): string;
6
+ export declare function renderSectionHeader(name: string): string;
@@ -5,6 +5,6 @@ export function bold(text, stream = process.stdout) {
5
5
  export function dim(text, stream = process.stdout) {
6
6
  return styleText('dim', text, { stream });
7
7
  }
8
- export function sectionHeader(name) {
8
+ export function renderSectionHeader(name) {
9
9
  return `━━━ ${name} ━━━`;
10
10
  }
@@ -1,11 +1,11 @@
1
1
  import { type OutputStyle } from '@williamthorsen/nmr-core';
2
2
  import type { ReleasedPackageResult } from './types.js';
3
3
  /** Appends bump file detail lines. */
4
- export declare function formatBumpFiles(lines: string[], workspace: Pick<ReleasedPackageResult, 'bumpedFiles'>, dryRun: boolean, indent?: string): void;
4
+ export declare function formatBumpFiles(lines: string[], workspace: Pick<ReleasedPackageResult, 'bumpedFiles'>, isDryRun: boolean, indent?: string): void;
5
5
  /**
6
6
  * Appends a line per generated changelog file, each followed by the versions kept from the existing changelog and a
7
7
  * warning naming the sections dropped for lacking a version, then a line per removed changelog archive file.
8
8
  */
9
- export declare function formatChangelogFiles(lines: string[], release: Pick<ReleasedPackageResult, 'changelogFiles' | 'changelogPreservation' | 'removedChangelogFiles'>, dryRun: boolean, style: OutputStyle, indent?: string): void;
9
+ export declare function formatChangelogFiles(lines: string[], release: Pick<ReleasedPackageResult, 'changelogFiles' | 'changelogPreservation' | 'removedChangelogFiles'>, isDryRun: boolean, style: OutputStyle, indent?: string): void;
10
10
  /** Appends release-notes preview file lines, which are present only under `--with-release-notes`. */
11
- export declare function formatPreviewFiles(lines: string[], release: Pick<ReleasedPackageResult, 'previewFiles'>, dryRun: boolean, indent?: string): void;
11
+ export declare function formatPreviewFiles(lines: string[], release: Pick<ReleasedPackageResult, 'previewFiles'>, isDryRun: boolean, indent?: string): void;
@@ -1,8 +1,8 @@
1
1
  import { formatStatusLine } from '@williamthorsen/nmr-core';
2
2
  import { dim } from "./format.js";
3
- export function formatBumpFiles(lines, workspace, dryRun, indent = '') {
3
+ export function formatBumpFiles(lines, workspace, isDryRun, indent = '') {
4
4
  for (const file of workspace.bumpedFiles) {
5
- if (dryRun) {
5
+ if (isDryRun) {
6
6
  lines.push(dim(`${indent} [dry-run] Would bump ${file}`));
7
7
  }
8
8
  else {
@@ -10,9 +10,9 @@ export function formatBumpFiles(lines, workspace, dryRun, indent = '') {
10
10
  }
11
11
  }
12
12
  }
13
- export function formatChangelogFiles(lines, release, dryRun, style, indent = '') {
13
+ export function formatChangelogFiles(lines, release, isDryRun, style, indent = '') {
14
14
  for (const file of release.changelogFiles) {
15
- if (dryRun) {
15
+ if (isDryRun) {
16
16
  lines.push(dim(`${indent} [dry-run] Would generate changelog: ${file}`));
17
17
  }
18
18
  else {
@@ -25,16 +25,16 @@ export function formatChangelogFiles(lines, release, dryRun, style, indent = '')
25
25
  if (preservation.preservedVersions.length > 0) {
26
26
  lines.push(dim(`${indent} Kept from the existing changelog: ${preservation.preservedVersions.join(', ')}`));
27
27
  }
28
- const dropped = preservation.droppedUnversionedHeadings;
29
- if (dropped.length === 0) {
28
+ const droppedHeadings = preservation.droppedUnversionedHeadings;
29
+ if (droppedHeadings.length === 0) {
30
30
  continue;
31
31
  }
32
- const message = `Dropped ${dropped.length} section${dropped.length === 1 ? '' : 's'} without a version: ${dropped.join(', ')}`;
32
+ const message = `Dropped ${droppedHeadings.length} section${droppedHeadings.length === 1 ? '' : 's'} without a version: ${droppedHeadings.join(', ')}`;
33
33
  lines.push(`${indent} ${formatStatusLine(style, 'warning', message)}`);
34
34
  }
35
35
  const removedFiles = release.removedChangelogFiles ?? [];
36
36
  for (const file of removedFiles) {
37
- if (dryRun) {
37
+ if (isDryRun) {
38
38
  lines.push(dim(`${indent} [dry-run] Would remove changelog: ${file}`));
39
39
  }
40
40
  else {
@@ -42,10 +42,10 @@ export function formatChangelogFiles(lines, release, dryRun, style, indent = '')
42
42
  }
43
43
  }
44
44
  }
45
- export function formatPreviewFiles(lines, release, dryRun, indent = '') {
45
+ export function formatPreviewFiles(lines, release, isDryRun, indent = '') {
46
46
  const previewFiles = release.previewFiles ?? [];
47
47
  for (const file of previewFiles) {
48
- if (dryRun) {
48
+ if (isDryRun) {
49
49
  lines.push(dim(`${indent} [dry-run] Would write ${file}`));
50
50
  }
51
51
  else {
@@ -1,5 +1,5 @@
1
1
  import { formatStatusLine, truncateToWidth } from '@williamthorsen/nmr-core';
2
- const SUBJECT_COLUMN_BUDGET = 72;
2
+ const SUBJECT_BUDGET_COLUMNS = 72;
3
3
  export function formatChangeRecordWarnings(lines, release, style, indent = '') {
4
4
  const { malformedBlocks = [], undeclaredEntryTypes = [], unroutedEntryScopes = [] } = release;
5
5
  if (malformedBlocks.length > 0) {
@@ -45,13 +45,13 @@ export function formatPolicyViolations(lines, violations, style, indent = '') {
45
45
  }
46
46
  }
47
47
  export function formatUnparseableWarning(lines, release, style, indent = '') {
48
- const unparseable = release.unparseableCommits;
49
- if (unparseable === undefined || unparseable.length === 0) {
48
+ const unparseableCommits = release.unparseableCommits;
49
+ if (unparseableCommits === undefined || unparseableCommits.length === 0) {
50
50
  return;
51
51
  }
52
- const count = unparseable.length;
52
+ const count = unparseableCommits.length;
53
53
  lines.push(`${indent} ${formatStatusLine(style, 'warning', `${count} commit${count === 1 ? '' : 's'} could not be parsed`)}`);
54
- for (const commit of unparseable) {
54
+ for (const commit of unparseableCommits) {
55
55
  const shortHash = commit.hash.slice(0, 7);
56
56
  const truncatedSubject = truncateSubject(commit.subject);
57
57
  lines.push(`${indent} · ${shortHash} ${truncatedSubject}`);
@@ -68,5 +68,5 @@ export function formatWarnings(lines, result, style) {
68
68
  }
69
69
  }
70
70
  function truncateSubject(subject) {
71
- return truncateToWidth(subject, { width: SUBJECT_COLUMN_BUDGET });
71
+ return truncateToWidth(subject, { width: SUBJECT_BUDGET_COLUMNS });
72
72
  }
@@ -15,8 +15,8 @@ function hasPrettierKeyInPackageJson(packageJsonPath) {
15
15
  return false;
16
16
  }
17
17
  try {
18
- const parsed = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
19
- return isRecord(parsed) && 'prettier' in parsed;
18
+ const parsedJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
19
+ return isRecord(parsedJson) && 'prettier' in parsedJson;
20
20
  }
21
21
  catch {
22
22
  return false;
@@ -1,10 +1,10 @@
1
1
  import { execSync } from 'node:child_process';
2
2
  import { existsSync, readFileSync } from 'node:fs';
3
- import { GIT_OUTPUT_LIMIT } from '@williamthorsen/nmr-core';
3
+ import { GIT_OUTPUT_LIMIT_BYTES } from '@williamthorsen/nmr-core';
4
4
  import { parseJsonRecord } from "./parseJsonRecord.js";
5
5
  export function isGitRepo() {
6
6
  try {
7
- execSync('git rev-parse --is-inside-work-tree', { maxBuffer: GIT_OUTPUT_LIMIT, stdio: 'pipe' });
7
+ execSync('git rev-parse --is-inside-work-tree', { maxBuffer: GIT_OUTPUT_LIMIT_BYTES, stdio: 'pipe' });
8
8
  return { ok: true };
9
9
  }
10
10
  catch {
@@ -24,9 +24,11 @@ export function usesPnpm() {
24
24
  if (existsSync('pnpm-lock.yaml')) {
25
25
  return { ok: true };
26
26
  }
27
- const raw = readFileSync('package.json', 'utf8');
28
- const pkg = parseJsonRecord(raw);
29
- if (pkg !== undefined && typeof pkg['packageManager'] === 'string' && pkg['packageManager'].startsWith('pnpm')) {
27
+ const manifestJson = readFileSync('package.json', 'utf8');
28
+ const packageJson = parseJsonRecord(manifestJson);
29
+ if (packageJson !== undefined &&
30
+ typeof packageJson['packageManager'] === 'string' &&
31
+ packageJson['packageManager'].startsWith('pnpm')) {
30
32
  return { ok: true };
31
33
  }
32
34
  return {
@@ -5,9 +5,9 @@ export function detectRepoType() {
5
5
  return 'monorepo';
6
6
  }
7
7
  if (existsSync('package.json')) {
8
- const raw = readFileSync('package.json', 'utf8');
9
- const pkg = parseJsonRecord(raw);
10
- if (pkg !== undefined && Array.isArray(pkg['workspaces'])) {
8
+ const manifestJson = readFileSync('package.json', 'utf8');
9
+ const packageJson = parseJsonRecord(manifestJson);
10
+ if (packageJson !== undefined && Array.isArray(packageJson['workspaces'])) {
11
11
  return 'monorepo';
12
12
  }
13
13
  }
@@ -1,12 +1,12 @@
1
1
  import { type StreamStyles } from '@williamthorsen/nmr-core';
2
2
  interface InitOptions {
3
- dryRun: boolean;
4
- force: boolean;
3
+ isDryRun: boolean;
4
+ shouldForce: boolean;
5
5
  styles: StreamStyles;
6
- withConfig: boolean;
6
+ shouldScaffoldConfig: boolean;
7
7
  }
8
8
  /** Runs the eligibility checks, stopping at the first failure, and reports whether all passed. */
9
9
  export declare function checkEligibility(styles: StreamStyles): boolean;
10
10
  /** Runs the `release-kit init` command and returns the process exit code. */
11
- export declare function initCommand({ dryRun, force, styles, withConfig }: InitOptions): number;
11
+ export declare function initCommand({ isDryRun, shouldForce, styles, shouldScaffoldConfig }: InitOptions): number;
12
12
  export {};
@@ -10,8 +10,8 @@ export function checkEligibility(styles) {
10
10
  runRequiredCheck('package.json found', hasPackageJson(), styles) &&
11
11
  runRequiredCheck('pnpm detected', usesPnpm(), styles));
12
12
  }
13
- export function initCommand({ dryRun, force, styles, withConfig }) {
14
- if (dryRun) {
13
+ export function initCommand({ isDryRun, shouldForce, styles, shouldScaffoldConfig }) {
14
+ if (isDryRun) {
15
15
  console.info('[dry-run mode]');
16
16
  }
17
17
  let eligible;
@@ -43,25 +43,25 @@ export function initCommand({ dryRun, force, styles, withConfig }) {
43
43
  }
44
44
  let results;
45
45
  try {
46
- results = scaffoldFiles({ repoType, dryRun, overwrite: force, publishable, withConfig });
46
+ results = scaffoldFiles({ repoType, isDryRun, shouldOverwrite: shouldForce, publishable, shouldScaffoldConfig });
47
47
  }
48
48
  catch (error) {
49
49
  printError(`Failed to scaffold files: ${describeError(error)}`, styles.stderr);
50
50
  return 1;
51
51
  }
52
52
  for (const result of results) {
53
- reportWriteResult(result, dryRun, styles);
53
+ reportWriteResult(result, isDryRun, styles);
54
54
  }
55
55
  if (results.some((r) => r.outcome === 'failed')) {
56
56
  return 1;
57
57
  }
58
58
  printStep('Next steps');
59
- console.info(`\n${formatNextSteps({ publishable, withConfig })}\n`);
59
+ console.info(`\n${formatNextSteps({ publishable, shouldScaffoldConfig })}\n`);
60
60
  return 0;
61
61
  }
62
- function formatNextSteps({ publishable, withConfig }) {
62
+ function formatNextSteps({ publishable, shouldScaffoldConfig, }) {
63
63
  const steps = [
64
- withConfig
64
+ shouldScaffoldConfig
65
65
  ? '(Optional) Customize .config/release-kit.config.ts.'
66
66
  : '(Optional) Run again with --with-config to scaffold config files.',
67
67
  ...(publishable ? ['If this is a private repo, remove provenance: true from .github/workflows/publish.yaml.'] : []),
@@ -1,2 +1,2 @@
1
1
  /** Parses a JSON string, returning the result if it is a plain object and `undefined` otherwise. */
2
- export declare function parseJsonRecord(raw: string): Record<string, unknown> | undefined;
2
+ export declare function parseJsonRecord(jsonText: string): Record<string, unknown> | undefined;
@@ -1,11 +1,11 @@
1
1
  import { isRecord } from "../typeGuards.js";
2
- export function parseJsonRecord(raw) {
3
- let parsed;
2
+ export function parseJsonRecord(jsonText) {
3
+ let parsedJson;
4
4
  try {
5
- parsed = JSON.parse(raw);
5
+ parsedJson = JSON.parse(jsonText);
6
6
  }
7
7
  catch {
8
8
  return undefined;
9
9
  }
10
- return isRecord(parsed) ? parsed : undefined;
10
+ return isRecord(parsedJson) ? parsedJson : undefined;
11
11
  }
@@ -2,15 +2,15 @@ import { type WriteResult } from '@williamthorsen/nmr-core';
2
2
  import type { RepoType } from './detectRepoType.js';
3
3
  interface ScaffoldOptions {
4
4
  repoType: RepoType;
5
- dryRun: boolean;
6
- overwrite: boolean;
5
+ isDryRun: boolean;
6
+ shouldOverwrite: boolean;
7
7
  publishable: boolean;
8
- withConfig: boolean;
8
+ shouldScaffoldConfig: boolean;
9
9
  }
10
10
  export declare const CREATE_GITHUB_RELEASE_WORKFLOW_PATH = ".github/workflows/create-github-release.yaml";
11
11
  export declare const PUBLISH_WORKFLOW_PATH = ".github/workflows/publish.yaml";
12
12
  /** The workflows that act only on publishable packages, which a repo whose packages are all private does not get. */
13
13
  export declare const PUBLISHING_WORKFLOW_PATHS: readonly [".github/workflows/create-github-release.yaml", ".github/workflows/publish.yaml"];
14
14
  /** Scaffolds release-kit files for the target repo, returning a result for each file attempted. */
15
- export declare function scaffoldFiles({ repoType, dryRun, overwrite, publishable, withConfig, }: ScaffoldOptions): WriteResult[];
15
+ export declare function scaffoldFiles({ repoType, isDryRun, shouldOverwrite, publishable, shouldScaffoldConfig, }: ScaffoldOptions): WriteResult[];
16
16
  export {};
@@ -1,19 +1,28 @@
1
1
  import { writeFileWithCheck } from '@williamthorsen/nmr-core';
2
- import { createGithubReleaseWorkflow, publishWorkflow, releaseConfigScript, releaseWorkflow } from "./templates.js";
2
+ import { renderCreateGithubReleaseWorkflow, renderPublishWorkflow, renderReleaseConfigScript, renderReleaseWorkflow, } from "./templates.js";
3
3
  export const CREATE_GITHUB_RELEASE_WORKFLOW_PATH = '.github/workflows/create-github-release.yaml';
4
4
  export const PUBLISH_WORKFLOW_PATH = '.github/workflows/publish.yaml';
5
5
  export const PUBLISHING_WORKFLOW_PATHS = [CREATE_GITHUB_RELEASE_WORKFLOW_PATH, PUBLISH_WORKFLOW_PATH];
6
- export function scaffoldFiles({ repoType, dryRun, overwrite, publishable, withConfig, }) {
6
+ export function scaffoldFiles({ repoType, isDryRun, shouldOverwrite, publishable, shouldScaffoldConfig, }) {
7
7
  const results = [];
8
8
  if (publishable) {
9
- results.push(writeFileWithCheck(CREATE_GITHUB_RELEASE_WORKFLOW_PATH, createGithubReleaseWorkflow(repoType), {
10
- dryRun,
11
- overwrite,
12
- }), writeFileWithCheck(PUBLISH_WORKFLOW_PATH, publishWorkflow(repoType), { dryRun, overwrite }));
9
+ results.push(writeFileWithCheck(CREATE_GITHUB_RELEASE_WORKFLOW_PATH, renderCreateGithubReleaseWorkflow(repoType), {
10
+ isDryRun,
11
+ shouldOverwrite,
12
+ }), writeFileWithCheck(PUBLISH_WORKFLOW_PATH, renderPublishWorkflow(repoType), {
13
+ isDryRun,
14
+ shouldOverwrite,
15
+ }));
13
16
  }
14
- results.push(writeFileWithCheck('.github/workflows/release.yaml', releaseWorkflow(repoType), { dryRun, overwrite }));
15
- if (withConfig) {
16
- results.push(writeFileWithCheck('.config/release-kit.config.ts', releaseConfigScript(repoType), { dryRun, overwrite }));
17
+ results.push(writeFileWithCheck('.github/workflows/release.yaml', renderReleaseWorkflow(repoType), {
18
+ isDryRun,
19
+ shouldOverwrite,
20
+ }));
21
+ if (shouldScaffoldConfig) {
22
+ results.push(writeFileWithCheck('.config/release-kit.config.ts', renderReleaseConfigScript(repoType), {
23
+ isDryRun,
24
+ shouldOverwrite,
25
+ }));
17
26
  }
18
27
  return results;
19
28
  }
@@ -1,16 +1,16 @@
1
1
  import type { RepoType } from './detectRepoType.js';
2
- /** Generates the `.config/release-kit.config.ts` starter config, with commented-out options to customize. */
3
- export declare function releaseConfigScript(repoType: RepoType): string;
2
+ /** Renders the `.config/release-kit.config.ts` starter config, with commented-out options to customize. */
3
+ export declare function renderReleaseConfigScript(repoType: RepoType): string;
4
4
  /**
5
- * Generates the publish.yaml GitHub Actions entry-point workflow.
5
+ * Renders the publish.yaml GitHub Actions entry-point workflow.
6
6
  *
7
7
  * The caller's `permissions` block caps what the reusable workflow receives, so it must grant the `id-token: write`
8
- * that OIDC publishing needs. `provenance: false` omits the provenance input, which a private repo cannot use.
8
+ * that OIDC publishing needs. `shouldGenerateProvenance: false` omits the provenance input, which a private repo cannot use.
9
9
  */
10
- export declare function publishWorkflow(repoType: RepoType, { provenance }?: {
11
- provenance?: boolean;
10
+ export declare function renderPublishWorkflow(repoType: RepoType, { shouldGenerateProvenance }?: {
11
+ shouldGenerateProvenance?: boolean;
12
12
  }): string;
13
- /** Generates the create-github-release.yaml GitHub Actions caller workflow. */
14
- export declare function createGithubReleaseWorkflow(repoType: RepoType): string;
15
- /** Generates the release.yaml GitHub Actions workflow. */
16
- export declare function releaseWorkflow(repoType: RepoType): string;
13
+ /** Renders the create-github-release.yaml GitHub Actions caller workflow. */
14
+ export declare function renderCreateGithubReleaseWorkflow(repoType: RepoType): string;
15
+ /** Renders the release.yaml GitHub Actions workflow. */
16
+ export declare function renderReleaseWorkflow(repoType: RepoType): string;
@@ -1,4 +1,4 @@
1
- export function releaseConfigScript(repoType) {
1
+ export function renderReleaseConfigScript(repoType) {
2
2
  if (repoType === 'monorepo') {
3
3
  return `import { defineConfig } from '@williamthorsen/release-kit/config';
4
4
 
@@ -39,7 +39,7 @@ export default defineConfig({
39
39
  });
40
40
  `;
41
41
  }
42
- export function publishWorkflow(repoType, { provenance = true } = {}) {
42
+ export function renderPublishWorkflow(repoType, { shouldGenerateProvenance = true } = {}) {
43
43
  const tagPattern = repoType === 'monorepo' ? "'*-v[0-9]*.[0-9]*.[0-9]*'" : "'v[0-9]*.[0-9]*.[0-9]*'";
44
44
  return `# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
45
45
  name: Publish
@@ -57,10 +57,10 @@ jobs:
57
57
  publish:
58
58
  uses: williamthorsen/node-monorepo-tools/.github/workflows/publish.reusable.yaml@workflow/publish-v1
59
59
  with:
60
- ${provenance ? ' provenance: true\n' : ''} tags: \${{ github.ref_name }}
60
+ ${shouldGenerateProvenance ? ' provenance: true\n' : ''} tags: \${{ github.ref_name }}
61
61
  `;
62
62
  }
63
- export function createGithubReleaseWorkflow(repoType) {
63
+ export function renderCreateGithubReleaseWorkflow(repoType) {
64
64
  const tagPattern = repoType === 'monorepo' ? "'*-v[0-9]*.[0-9]*.[0-9]*'" : "'v[0-9]*.[0-9]*.[0-9]*'";
65
65
  return `# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
66
66
  name: Create GitHub release
@@ -80,7 +80,7 @@ jobs:
80
80
  tag: \${{ github.ref_name }}
81
81
  `;
82
82
  }
83
- export function releaseWorkflow(repoType) {
83
+ export function renderReleaseWorkflow(repoType) {
84
84
  if (repoType === 'monorepo') {
85
85
  return `# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
86
86
  name: Release
@@ -1,6 +1,6 @@
1
1
  import { type StreamStyles } from '@williamthorsen/nmr-core';
2
2
  interface UpdateTemplatesOptions {
3
- dryRun: boolean;
3
+ isDryRun: boolean;
4
4
  styles: StreamStyles;
5
5
  }
6
6
  /**
@@ -10,5 +10,5 @@ interface UpdateTemplatesOptions {
10
10
  * `sync-labels.yaml` is refreshed only when it exists, as are the publishing workflows in a repo whose packages are
11
11
  * all private. Config files are never read or written.
12
12
  */
13
- export declare function updateTemplatesCommand({ dryRun, styles }: UpdateTemplatesOptions): number;
13
+ export declare function updateTemplatesCommand({ isDryRun, styles }: UpdateTemplatesOptions): number;
14
14
  export {};
@@ -1,16 +1,16 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import { printError, printSkip, printStep, printSuccess, reportTemplateUpdate, updateManagedFile, } from '@williamthorsen/nmr-core';
3
3
  import { describeError } from '@williamthorsen/toolbelt.errors';
4
- import { syncLabelsWorkflow } from "../sync-labels/templates.js";
4
+ import { readSyncLabelsWorkflowTemplate } from "../sync-labels/templates.js";
5
5
  import { detectRepoType } from "./detectRepoType.js";
6
6
  import { hasProvenance } from "./hasProvenance.js";
7
7
  import { formatPrivateWorkflowSkip, hasPublishablePackage } from "./hasPublishablePackage.js";
8
8
  import { checkEligibility } from "./initCommand.js";
9
9
  import { CREATE_GITHUB_RELEASE_WORKFLOW_PATH, PUBLISH_WORKFLOW_PATH, PUBLISHING_WORKFLOW_PATHS } from "./scaffold.js";
10
- import { createGithubReleaseWorkflow, publishWorkflow, releaseWorkflow } from "./templates.js";
10
+ import { renderCreateGithubReleaseWorkflow, renderPublishWorkflow, renderReleaseWorkflow } from "./templates.js";
11
11
  const SYNC_LABELS_WORKFLOW_PATH = '.github/workflows/sync-labels.yaml';
12
- export function updateTemplatesCommand({ dryRun, styles }) {
13
- if (dryRun) {
12
+ export function updateTemplatesCommand({ isDryRun, styles }) {
13
+ if (isDryRun) {
14
14
  console.info('[dry-run mode]');
15
15
  }
16
16
  let eligible;
@@ -36,32 +36,34 @@ export function updateTemplatesCommand({ dryRun, styles }) {
36
36
  printStep('Updating workflows');
37
37
  let results;
38
38
  try {
39
- const { files, skipped } = buildManagedFiles(repoType, hasPublishablePackage());
40
- for (const filePath of skipped) {
39
+ const { files, skippedPaths } = buildManagedFiles(repoType, hasPublishablePackage());
40
+ for (const filePath of skippedPaths) {
41
41
  printSkip(formatPrivateWorkflowSkip(filePath), styles.stdout);
42
42
  }
43
- results = files.map(([filePath, content]) => updateManagedFile(filePath, content, { dryRun }));
43
+ results = files.map(([filePath, content]) => updateManagedFile(filePath, content, { isDryRun }));
44
44
  }
45
45
  catch (error) {
46
46
  printError(`Failed to render workflows: ${describeError(error)}`, styles.stderr);
47
47
  return 1;
48
48
  }
49
49
  for (const result of results) {
50
- reportTemplateUpdate(result, dryRun, styles);
50
+ reportTemplateUpdate(result, isDryRun, styles);
51
51
  }
52
52
  return results.some((result) => result.outcome === 'failed') ? 1 : 0;
53
53
  }
54
54
  function buildManagedFiles(repoType, publishable) {
55
- const skipped = publishable ? [] : PUBLISHING_WORKFLOW_PATHS.filter((filePath) => !existsSync(filePath));
55
+ const skippedPaths = publishable
56
+ ? []
57
+ : PUBLISHING_WORKFLOW_PATHS.filter((filePath) => !existsSync(filePath));
56
58
  const files = [
57
- [CREATE_GITHUB_RELEASE_WORKFLOW_PATH, createGithubReleaseWorkflow(repoType)],
58
- [PUBLISH_WORKFLOW_PATH, publishWorkflow(repoType, { provenance: readProvenanceSetting() })],
59
- ['.github/workflows/release.yaml', releaseWorkflow(repoType)],
59
+ [CREATE_GITHUB_RELEASE_WORKFLOW_PATH, renderCreateGithubReleaseWorkflow(repoType)],
60
+ [PUBLISH_WORKFLOW_PATH, renderPublishWorkflow(repoType, { shouldGenerateProvenance: readProvenanceSetting() })],
61
+ ['.github/workflows/release.yaml', renderReleaseWorkflow(repoType)],
60
62
  ];
61
63
  if (existsSync(SYNC_LABELS_WORKFLOW_PATH)) {
62
- files.push([SYNC_LABELS_WORKFLOW_PATH, syncLabelsWorkflow()]);
64
+ files.push([SYNC_LABELS_WORKFLOW_PATH, readSyncLabelsWorkflowTemplate()]);
63
65
  }
64
- return { files: files.filter(([filePath]) => !skipped.includes(filePath)), skipped };
66
+ return { files: files.filter(([filePath]) => !skippedPaths.includes(filePath)), skippedPaths };
65
67
  }
66
68
  function readProvenanceSetting() {
67
69
  if (!existsSync(PUBLISH_WORKFLOW_PATH))
@@ -16,7 +16,7 @@ export type RenderInjectedReadmeSkipReason = 'no-entry' | 'empty-body';
16
16
  /** Discriminated outcome of rendering release notes for a tag. */
17
17
  export type RenderInjectedReadmeResult = {
18
18
  status: 'rendered';
19
- rendered: RenderedInjectedReadme;
19
+ renderedReadme: RenderedInjectedReadme;
20
20
  } | {
21
21
  status: 'skipped';
22
22
  reason: RenderInjectedReadmeSkipReason;