@williamthorsen/release-kit 15.0.3 → 16.1.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 (146) hide show
  1. package/.meta/changelog.json +93 -0
  2. package/.readyup/kits/default.js +14 -14
  3. package/.readyup/kits/npm-auto-publish.js +4 -4
  4. package/.readyup/manifest.json +13 -13
  5. package/CHANGELOG.md +27 -0
  6. package/README.md +12 -3
  7. package/dist/esm/applyChangelogOverrides.js +6 -6
  8. package/dist/esm/assertReleasesOnNpm.js +11 -11
  9. package/dist/esm/assertTaggedBaseline.js +5 -5
  10. package/dist/esm/assertTarballsComplete.d.ts +9 -0
  11. package/dist/esm/assertTarballsComplete.js +52 -0
  12. package/dist/esm/bin/release-kit.js +16 -16
  13. package/dist/esm/buildChangelogEntries.d.ts +19 -19
  14. package/dist/esm/buildChangelogEntries.js +40 -36
  15. package/dist/esm/buildChangelogItem.js +24 -24
  16. package/dist/esm/buildDependencyGraph.js +23 -23
  17. package/dist/esm/buildReleasedResult.js +21 -19
  18. package/dist/esm/buildSyntheticChangelogEntry.js +2 -2
  19. package/dist/esm/bumpVersion.js +8 -8
  20. package/dist/esm/changelogArchive.d.ts +1 -1
  21. package/dist/esm/changelogArchive.js +2 -2
  22. package/dist/esm/changelogJsonFile.js +5 -5
  23. package/dist/esm/changelogJsonUtils.js +3 -3
  24. package/dist/esm/changelogOverrides.d.ts +5 -5
  25. package/dist/esm/changelogOverrides.js +23 -23
  26. package/dist/esm/classifyChangelogCommit.js +4 -4
  27. package/dist/esm/commitCommand.js +3 -3
  28. package/dist/esm/compareVersions.js +13 -13
  29. package/dist/esm/configSchema.d.ts +3 -2
  30. package/dist/esm/configSchema.js +2 -1
  31. package/dist/esm/createGithubRelease.d.ts +4 -4
  32. package/dist/esm/createGithubRelease.js +10 -10
  33. package/dist/esm/createGithubReleaseCommand.js +9 -9
  34. package/dist/esm/createTags.d.ts +2 -2
  35. package/dist/esm/createTags.js +8 -8
  36. package/dist/esm/decideDirectReleases.d.ts +5 -5
  37. package/dist/esm/decideDirectReleases.js +25 -25
  38. package/dist/esm/decideRelease.d.ts +1 -1
  39. package/dist/esm/decideRelease.js +2 -2
  40. package/dist/esm/deriveDirectoryConfig.d.ts +1 -1
  41. package/dist/esm/deriveDirectoryConfig.js +18 -18
  42. package/dist/esm/deriveWorkspaceConfig.js +4 -4
  43. package/dist/esm/detectPackageManager.d.ts +2 -0
  44. package/dist/esm/detectPackageManager.js +8 -5
  45. package/dist/esm/detectUndeclaredTagPrefixes.js +6 -6
  46. package/dist/esm/enumerateReleaseWindows.d.ts +1 -1
  47. package/dist/esm/enumerateReleaseWindows.js +7 -7
  48. package/dist/esm/findMissingManifestPaths.d.ts +14 -0
  49. package/dist/esm/findMissingManifestPaths.js +90 -0
  50. package/dist/esm/findTransitiveDependents.js +5 -5
  51. package/dist/esm/findUnroutedEntryScopes.js +11 -11
  52. package/dist/esm/format.d.ts +1 -1
  53. package/dist/esm/format.js +1 -1
  54. package/dist/esm/formatPrepareFiles.d.ts +3 -3
  55. package/dist/esm/formatPrepareFiles.js +10 -10
  56. package/dist/esm/formatPrepareWarnings.js +6 -6
  57. package/dist/esm/hasPrettierConfig.js +2 -2
  58. package/dist/esm/init/checks.js +5 -3
  59. package/dist/esm/init/detectRepoType.js +3 -3
  60. package/dist/esm/init/initCommand.d.ts +4 -4
  61. package/dist/esm/init/initCommand.js +7 -7
  62. package/dist/esm/init/parseJsonRecord.d.ts +1 -1
  63. package/dist/esm/init/parseJsonRecord.js +4 -4
  64. package/dist/esm/init/scaffold.d.ts +4 -4
  65. package/dist/esm/init/scaffold.js +15 -15
  66. package/dist/esm/init/templates.d.ts +10 -10
  67. package/dist/esm/init/templates.js +5 -5
  68. package/dist/esm/init/updateTemplatesCommand.d.ts +2 -2
  69. package/dist/esm/init/updateTemplatesCommand.js +14 -12
  70. package/dist/esm/injectReleaseNotesIntoReadme.d.ts +1 -1
  71. package/dist/esm/injectReleaseNotesIntoReadme.js +6 -6
  72. package/dist/esm/injectSection.js +8 -8
  73. package/dist/esm/loadChangelogOverrides.d.ts +1 -1
  74. package/dist/esm/loadChangelogOverrides.js +9 -9
  75. package/dist/esm/loadConfig.d.ts +3 -3
  76. package/dist/esm/loadConfig.js +10 -10
  77. package/dist/esm/loadValidatedConfig.js +4 -4
  78. package/dist/esm/mergeConfig.d.ts +1 -1
  79. package/dist/esm/mergeConfig.js +27 -27
  80. package/dist/esm/monorepoConfigAssertions.js +15 -15
  81. package/dist/esm/npmRegistry.js +4 -4
  82. package/dist/esm/packFromCleanCheckout.d.ts +11 -0
  83. package/dist/esm/packFromCleanCheckout.js +81 -0
  84. package/dist/esm/packsPath.js +3 -3
  85. package/dist/esm/parseChangeRecordBlock.js +33 -33
  86. package/dist/esm/parseCommitMessage.js +5 -5
  87. package/dist/esm/planChangelogFiles.js +8 -8
  88. package/dist/esm/planReleaseNotesPreviews.js +10 -10
  89. package/dist/esm/planVersionBump.js +24 -16
  90. package/dist/esm/prepareArgs.d.ts +9 -9
  91. package/dist/esm/prepareArgs.js +11 -11
  92. package/dist/esm/prepareCommand.js +27 -24
  93. package/dist/esm/prepareComposite.d.ts +4 -4
  94. package/dist/esm/prepareComposite.js +16 -16
  95. package/dist/esm/{releasePrepareTargets.d.ts → prepareReleaseTargets.d.ts} +9 -9
  96. package/dist/esm/{releasePrepareTargets.js → prepareReleaseTargets.js} +40 -40
  97. package/dist/esm/prepareRunContext.d.ts +1 -1
  98. package/dist/esm/prepareRunContext.js +5 -5
  99. package/dist/esm/prepareTarget.d.ts +3 -3
  100. package/dist/esm/prepareTarget.js +41 -39
  101. package/dist/esm/previewTagPrefixes.js +19 -19
  102. package/dist/esm/propagateBumps.js +8 -8
  103. package/dist/esm/publish.d.ts +3 -3
  104. package/dist/esm/publish.js +6 -11
  105. package/dist/esm/publishCommand.d.ts +3 -3
  106. package/dist/esm/publishCommand.js +28 -20
  107. package/dist/esm/pushCommand.js +8 -8
  108. package/dist/esm/pushRelease.d.ts +1 -1
  109. package/dist/esm/pushRelease.js +2 -2
  110. package/dist/esm/readChangelogSections.d.ts +1 -1
  111. package/dist/esm/readChangelogSections.js +16 -16
  112. package/dist/esm/releasePlan.js +25 -25
  113. package/dist/esm/renderChangelogMarkdown.d.ts +4 -4
  114. package/dist/esm/renderChangelogMarkdown.js +18 -15
  115. package/dist/esm/renderReleaseNotes.d.ts +1 -1
  116. package/dist/esm/renderReleaseNotes.js +16 -16
  117. package/dist/esm/reportPrepare.js +34 -34
  118. package/dist/esm/resolveCommandTags.js +9 -9
  119. package/dist/esm/resolveReleaseDeclaration.d.ts +2 -2
  120. package/dist/esm/resolveReleaseDeclaration.js +22 -22
  121. package/dist/esm/resolveReleaseTags.js +17 -15
  122. package/dist/esm/resolveReleaseTargets.js +2 -2
  123. package/dist/esm/showTagPrefixesCommand.js +4 -4
  124. package/dist/esm/sync-labels/generateCommand.d.ts +3 -3
  125. package/dist/esm/sync-labels/generateCommand.js +10 -10
  126. package/dist/esm/sync-labels/initCommand.d.ts +3 -3
  127. package/dist/esm/sync-labels/initCommand.js +15 -15
  128. package/dist/esm/sync-labels/presets.js +3 -3
  129. package/dist/esm/sync-labels/resolveLabels.js +13 -13
  130. package/dist/esm/sync-labels/templates.d.ts +2 -2
  131. package/dist/esm/sync-labels/templates.js +1 -1
  132. package/dist/esm/tagCommand.js +4 -4
  133. package/dist/esm/topologicalSort.d.ts +2 -2
  134. package/dist/esm/topologicalSort.js +7 -7
  135. package/dist/esm/types.d.ts +3 -3
  136. package/dist/esm/validateAllChangelogOverrides.js +9 -9
  137. package/dist/esm/validateConfig.d.ts +1 -1
  138. package/dist/esm/validateConfig.js +60 -50
  139. package/dist/esm/validateOverridesCommand.js +2 -2
  140. package/docs/changelogs.md +5 -5
  141. package/docs/configuration.md +16 -15
  142. package/docs/publishing.md +4 -0
  143. package/docs/releasing.md +6 -0
  144. package/docs/work-types.md +1 -1
  145. package/package.json +2 -2
  146. package/presets/labels/common.yaml +3 -0
@@ -1,5 +1,5 @@
1
1
  import { formatGlyphLine, formatStatusLine, measureGlyphColumn, STATUS_GLYPHS, } from '@williamthorsen/nmr-core';
2
- import { bold, dim, sectionHeader } from "./format.js";
2
+ import { bold, dim, renderSectionHeader } from "./format.js";
3
3
  import { formatBumpFiles, formatChangelogFiles, formatPreviewFiles } from "./formatPrepareFiles.js";
4
4
  import { formatChangeRecordWarnings, formatPolicyViolations, formatUnparseableWarning, formatWarnings, } from "./formatPrepareWarnings.js";
5
5
  import { RELEASE_GLYPHS } from "./glyphs.js";
@@ -12,15 +12,15 @@ export function reportPrepare(plan, options) {
12
12
  return formatSingleWorkspace(plan, options);
13
13
  }
14
14
  function formatSingleWorkspace(result, options) {
15
- const dryRun = !options.applied;
15
+ const isDryRun = !options.applied;
16
16
  const { style } = options;
17
17
  const lines = [];
18
18
  const workspace = result.targets[0];
19
19
  if (workspace === undefined || workspace.kind === 'composite') {
20
20
  return '';
21
21
  }
22
- const since = workspace.previousTag === undefined ? 'the beginning' : workspace.previousTag;
23
- lines.push(dim(`Found ${workspace.commitCount} commits since ${since}`));
22
+ const sinceLabel = workspace.previousTag === undefined ? 'the beginning' : workspace.previousTag;
23
+ lines.push(dim(`Found ${workspace.commitCount} commits since ${sinceLabel}`));
24
24
  if (workspace.parsedCommitCount !== undefined) {
25
25
  lines.push(dim(` Parsed ${workspace.parsedCommitCount} typed commits`));
26
26
  }
@@ -32,8 +32,8 @@ function formatSingleWorkspace(result, options) {
32
32
  formatWarnings(lines, result, style);
33
33
  return lines.join('\n');
34
34
  }
35
- if (workspace.setVersion !== undefined) {
36
- lines.push(` Using version override: ${workspace.setVersion}`);
35
+ if (workspace.versionOverride !== undefined) {
36
+ lines.push(` Using version override: ${workspace.versionOverride}`);
37
37
  }
38
38
  else if (workspace.bumpOverride !== undefined) {
39
39
  lines.push(` Using bump override: ${workspace.bumpOverride}`);
@@ -41,35 +41,35 @@ function formatSingleWorkspace(result, options) {
41
41
  if (workspace.releaseType !== undefined) {
42
42
  lines.push(dim(`Bumping versions (${workspace.releaseType})...`));
43
43
  }
44
- else if (workspace.setVersion !== undefined) {
44
+ else if (workspace.versionOverride !== undefined) {
45
45
  lines.push(dim(`Bumping versions (version override)...`));
46
46
  }
47
- if (workspace.setVersion !== undefined) {
47
+ if (workspace.versionOverride !== undefined) {
48
48
  lines.push(formatGlyphLine(RELEASE_GLYPHS, style, 'bump', `${workspace.currentVersion} → ${bold(workspace.newVersion)} (version override)`));
49
49
  }
50
50
  else if (workspace.releaseType !== undefined) {
51
51
  lines.push(formatGlyphLine(RELEASE_GLYPHS, style, 'bump', `${workspace.currentVersion} → ${bold(workspace.newVersion)} (${workspace.releaseType})`));
52
52
  }
53
53
  formatChangeRecordWarnings(lines, workspace, style);
54
- formatBumpFiles(lines, workspace, dryRun);
54
+ formatBumpFiles(lines, workspace, isDryRun);
55
55
  lines.push(dim('Generating changelogs...'));
56
- formatChangelogFiles(lines, workspace, dryRun, style);
57
- formatPreviewFiles(lines, workspace, dryRun);
56
+ formatChangelogFiles(lines, workspace, isDryRun, style);
57
+ formatPreviewFiles(lines, workspace, isDryRun);
58
58
  formatFormatCommand(lines, result, options);
59
59
  formatWarnings(lines, result, style);
60
60
  lines.push(formatStatusLine(style, 'passed', 'Release preparation complete.'), ` ${formatGlyphLine(RELEASE_GLYPHS, style, 'tag', bold(workspace.tag))}`);
61
61
  return lines.join('\n');
62
62
  }
63
63
  function formatMultiWorkspace(result, options) {
64
- const dryRun = !options.applied;
64
+ const isDryRun = !options.applied;
65
65
  const { style } = options;
66
66
  const lines = [];
67
67
  for (const target of result.targets) {
68
68
  if (target.kind === 'composite') {
69
- formatProjectSection(lines, target, dryRun, style);
69
+ formatProjectSection(lines, target, isDryRun, style);
70
70
  }
71
71
  else {
72
- formatWorkspaceSection(lines, target, dryRun, style);
72
+ formatWorkspaceSection(lines, target, isDryRun, style);
73
73
  }
74
74
  }
75
75
  formatFormatCommand(lines, result, options);
@@ -85,10 +85,10 @@ function formatMultiWorkspace(result, options) {
85
85
  }
86
86
  return lines.join('\n');
87
87
  }
88
- function formatProjectSection(lines, project, dryRun, style) {
89
- lines.push(`\n${sectionHeader(project.targetId === PROJECT_TARGET_ID ? 'project' : project.targetId)}`);
90
- const since = project.previousTag === undefined ? '(no previous release found)' : `since ${project.previousTag}`;
91
- lines.push(dim(` Found ${project.commitCount} commits ${since}`));
88
+ function formatProjectSection(lines, project, isDryRun, style) {
89
+ lines.push(`\n${renderSectionHeader(project.targetId === PROJECT_TARGET_ID ? 'project' : project.targetId)}`);
90
+ const sinceLabel = project.previousTag === undefined ? '(no previous release found)' : `since ${project.previousTag}`;
91
+ lines.push(dim(` Found ${project.commitCount} commits ${sinceLabel}`));
92
92
  formatPolicyViolations(lines, project.policyViolations, style, ' ');
93
93
  if (project.status === 'skipped') {
94
94
  formatUnparseableWarning(lines, project, style, ' ');
@@ -107,7 +107,7 @@ function formatProjectSection(lines, project, dryRun, style) {
107
107
  formatChangeRecordWarnings(lines, project, style, ' ');
108
108
  lines.push(dim(` Bumping versions (${releaseType})...`), ` ${formatGlyphLine(RELEASE_GLYPHS, style, 'bump', `${currentVersion} → ${bold(newVersion)} (${releaseType})`)}`);
109
109
  for (const file of project.bumpedFiles) {
110
- if (dryRun) {
110
+ if (isDryRun) {
111
111
  lines.push(dim(` [dry-run] Would bump ${file}`));
112
112
  }
113
113
  else {
@@ -115,16 +115,16 @@ function formatProjectSection(lines, project, dryRun, style) {
115
115
  }
116
116
  }
117
117
  lines.push(dim(' Generating changelogs...'));
118
- formatChangelogFiles(lines, project, dryRun, style, ' ');
119
- formatPreviewFiles(lines, project, dryRun, ' ');
118
+ formatChangelogFiles(lines, project, isDryRun, style, ' ');
119
+ formatPreviewFiles(lines, project, isDryRun, ' ');
120
120
  lines.push(` ${formatGlyphLine(RELEASE_GLYPHS, style, 'tag', bold(tag))}`);
121
121
  }
122
- function formatWorkspaceSection(lines, workspace, dryRun, style) {
122
+ function formatWorkspaceSection(lines, workspace, isDryRun, style) {
123
123
  if (workspace.name !== undefined) {
124
- lines.push(`\n${sectionHeader(workspace.name)}`);
124
+ lines.push(`\n${renderSectionHeader(workspace.name)}`);
125
125
  }
126
- const since = workspace.previousTag === undefined ? '(no previous release found)' : `since ${workspace.previousTag}`;
127
- lines.push(dim(` Found ${workspace.commitCount} commits ${since}`));
126
+ const sinceLabel = workspace.previousTag === undefined ? '(no previous release found)' : `since ${workspace.previousTag}`;
127
+ lines.push(dim(` Found ${workspace.commitCount} commits ${sinceLabel}`));
128
128
  if (workspace.status === 'skipped') {
129
129
  formatUnparseableWarning(lines, workspace, style, ' ');
130
130
  formatPolicyViolations(lines, workspace.policyViolations, style, ' ');
@@ -140,24 +140,24 @@ function formatWorkspaceSection(lines, workspace, dryRun, style) {
140
140
  formatChangeRecordWarnings(lines, workspace, style, ' ');
141
141
  formatBumpLabels(lines, workspace, isPropagatedOnly);
142
142
  formatVersionLine(lines, workspace, propagatedFrom, isPropagatedOnly, style);
143
- formatBumpFiles(lines, workspace, dryRun, ' ');
143
+ formatBumpFiles(lines, workspace, isDryRun, ' ');
144
144
  lines.push(dim(' Generating changelogs...'));
145
- formatChangelogFiles(lines, workspace, dryRun, style, ' ');
146
- formatPreviewFiles(lines, workspace, dryRun, ' ');
145
+ formatChangelogFiles(lines, workspace, isDryRun, style, ' ');
146
+ formatPreviewFiles(lines, workspace, isDryRun, ' ');
147
147
  lines.push(` ${formatGlyphLine(RELEASE_GLYPHS, style, 'tag', bold(workspace.tag))}`);
148
148
  }
149
149
  function formatCommitSummary(lines, workspace, propagatedFrom, isPropagatedOnly) {
150
150
  if (isPropagatedOnly && propagatedFrom !== undefined) {
151
- const depNames = propagatedFrom.map((p) => p.packageName).join(', ');
152
- lines.push(dim(` Bumped via dependency: ${depNames}`));
151
+ const dependencyNames = propagatedFrom.map((p) => p.packageName).join(', ');
152
+ lines.push(dim(` Bumped via dependency: ${dependencyNames}`));
153
153
  }
154
154
  else if (workspace.parsedCommitCount !== undefined && workspace.parsedCommitCount > 0) {
155
155
  lines.push(dim(` Parsed ${workspace.parsedCommitCount} typed commits`));
156
156
  }
157
157
  }
158
158
  function formatBumpLabels(lines, workspace, isPropagatedOnly) {
159
- if (workspace.setVersion !== undefined) {
160
- lines.push(` Using version override: ${workspace.setVersion}`);
159
+ if (workspace.versionOverride !== undefined) {
160
+ lines.push(` Using version override: ${workspace.versionOverride}`);
161
161
  }
162
162
  else if (workspace.bumpOverride !== undefined && !isPropagatedOnly) {
163
163
  lines.push(` Using bump override: ${workspace.bumpOverride}`);
@@ -165,13 +165,13 @@ function formatBumpLabels(lines, workspace, isPropagatedOnly) {
165
165
  if (workspace.releaseType !== undefined) {
166
166
  lines.push(dim(` Bumping versions (${workspace.releaseType})...`));
167
167
  }
168
- else if (workspace.setVersion !== undefined) {
168
+ else if (workspace.versionOverride !== undefined) {
169
169
  lines.push(dim(` Bumping versions (version override)...`));
170
170
  }
171
171
  }
172
172
  function formatVersionLine(lines, workspace, propagatedFrom, isPropagatedOnly, style) {
173
173
  const versions = `${workspace.currentVersion} → ${bold(workspace.newVersion)}`;
174
- if (workspace.setVersion !== undefined) {
174
+ if (workspace.versionOverride !== undefined) {
175
175
  lines.push(` ${formatGlyphLine(RELEASE_GLYPHS, style, 'bump', `${versions} (version override)`)}`);
176
176
  }
177
177
  else if (workspace.releaseType !== undefined) {
@@ -29,12 +29,12 @@ export function resolveCommandTags(tags, userConfig) {
29
29
  singleWorkspace = deriveWorkspaceConfig('.');
30
30
  }
31
31
  else {
32
- const merged = mergeMonorepoConfig(workspace.packageDirs, userConfig, readRootPackageVersion());
33
- const excluded = merged.excludedWorkspaces ?? [];
34
- workspaces = [...merged.workspaces, ...excluded];
35
- directories = merged.directories ?? [];
36
- project = merged.project;
37
- excludedPaths = new Set(excluded.map((excludedWorkspace) => excludedWorkspace.workspacePath));
32
+ const mergedConfig = mergeMonorepoConfig(workspace.packageDirs, userConfig, readRootPackageVersion());
33
+ const excludedWorkspaces = mergedConfig.excludedWorkspaces ?? [];
34
+ workspaces = [...mergedConfig.workspaces, ...excludedWorkspaces];
35
+ directories = mergedConfig.directories ?? [];
36
+ project = mergedConfig.project;
37
+ excludedPaths = new Set(excludedWorkspaces.map((excludedWorkspace) => excludedWorkspace.workspacePath));
38
38
  }
39
39
  }
40
40
  catch (error) {
@@ -69,15 +69,15 @@ export function resolveCommandTags(tags, userConfig) {
69
69
  return dropExcludedTags(resolvedTags, excludedPaths, userConfig?.releases === undefined ? 'legacy' : 'releases');
70
70
  }
71
71
  function dropExcludedTags(resolvedTags, excludedPaths, surface) {
72
- const retained = [];
72
+ const retainedTags = [];
73
73
  for (const resolvedTag of resolvedTags) {
74
74
  if (resolvedTag.kind === 'package' && excludedPaths.has(resolvedTag.workspacePath)) {
75
75
  const setting = surface === 'releases' ? `releases.${resolvedTag.dir}: false` : undefined;
76
76
  console.warn(formatExcludedSkip(resolvedTag, setting));
77
77
  }
78
78
  else {
79
- retained.push(resolvedTag);
79
+ retainedTags.push(resolvedTag);
80
80
  }
81
81
  }
82
- return retained;
82
+ return retainedTags;
83
83
  }
@@ -24,9 +24,9 @@ export interface DeclaredDirectory {
24
24
  /** The release targets that a config declares over the discovered workspaces. */
25
25
  export interface ReleaseDeclaration {
26
26
  /** Retained workspaces in discovery order, each with its target name and legacy identities applied. */
27
- retained: WorkspaceConfig[];
27
+ retainedWorkspaces: WorkspaceConfig[];
28
28
  /** Discovered workspaces that the config excludes, in discovery order. */
29
- excluded: WorkspaceConfig[];
29
+ excludedWorkspaces: WorkspaceConfig[];
30
30
  /** Directories that `releases` entries declare as targets, in config order. */
31
31
  directories: DeclaredDirectory[];
32
32
  composite?: DeclaredComposite;
@@ -3,8 +3,8 @@ export function getTargetName(workspace) {
3
3
  return workspace.targetName ?? workspace.dir;
4
4
  }
5
5
  export function normalizeWorkspacePath(configuredPath) {
6
- const normalized = path.posix.normalize(configuredPath.replaceAll('\\', '/'));
7
- return normalized.replace(/^\.\//, '').replace(/\/+$/, '');
6
+ const normalizedPath = path.posix.normalize(configuredPath.replaceAll('\\', '/'));
7
+ return normalizedPath.replace(/^\.\//, '').replace(/\/+$/, '');
8
8
  }
9
9
  export function resolveReleaseDeclaration(workspaces, userConfig) {
10
10
  if (userConfig?.releases !== undefined) {
@@ -19,9 +19,9 @@ function applyLegacyIdentities(workspace, legacyIdentities) {
19
19
  return { ...workspace, legacyIdentities: legacyIdentities.map((identity) => ({ ...identity })) };
20
20
  }
21
21
  function claimPath(entryByPath, name, claimedPath, kind) {
22
- const claimedBy = entryByPath.get(claimedPath);
23
- if (claimedBy !== undefined) {
24
- throw new Error(`releases.${name}: ${kind} '${claimedPath}' is already declared by releases.${claimedBy}; declare each ${kind} once`);
22
+ const claimingEntryName = entryByPath.get(claimedPath);
23
+ if (claimingEntryName !== undefined) {
24
+ throw new Error(`releases.${name}: ${kind} '${claimedPath}' is already declared by releases.${claimingEntryName}; declare each ${kind} once`);
25
25
  }
26
26
  entryByPath.set(claimedPath, name);
27
27
  }
@@ -40,9 +40,9 @@ function declareDirectory(name, entry, normalizedPath) {
40
40
  }),
41
41
  };
42
42
  }
43
- function resolveCompositeMembers(composite, retained, excluded, directories) {
43
+ function resolveCompositeMembers(composite, retainedWorkspaces, excludedWorkspaces, directories) {
44
44
  const membersByName = new Map([
45
- ...retained.map((workspace) => [getTargetName(workspace), { name: getTargetName(workspace), paths: workspace.paths }]),
45
+ ...retainedWorkspaces.map((workspace) => [getTargetName(workspace), { name: getTargetName(workspace), paths: workspace.paths }]),
46
46
  ...directories.map((directory) => [directory.name, { name: directory.name, paths: directory.paths }]),
47
47
  ]);
48
48
  return composite.includes.map((memberName) => {
@@ -54,7 +54,7 @@ function resolveCompositeMembers(composite, retained, excluded, directories) {
54
54
  if (memberName === composite.name) {
55
55
  throw new Error(`${label} is the composite itself; a composite includes package and directory targets only`);
56
56
  }
57
- if (excluded.some((workspace) => workspace.dir === memberName)) {
57
+ if (excludedWorkspaces.some((workspace) => workspace.dir === memberName)) {
58
58
  throw new Error(`${label} is excluded, so the composite cannot include it`);
59
59
  }
60
60
  throw new Error(`${label} is not a release target. Known targets: ${membersByName.keys().toArray().join(', ')}`);
@@ -62,18 +62,18 @@ function resolveCompositeMembers(composite, retained, excluded, directories) {
62
62
  }
63
63
  function resolveLegacyBlocks(workspaces, overrides, project) {
64
64
  const overridesByDir = new Map(overrides.map((override) => [override.dir, override]));
65
- const retained = [];
66
- const excluded = [];
65
+ const retainedWorkspaces = [];
66
+ const excludedWorkspaces = [];
67
67
  for (const workspace of workspaces) {
68
68
  const override = overridesByDir.get(workspace.dir);
69
69
  if (override?.shouldExclude === true) {
70
- excluded.push(workspace);
70
+ excludedWorkspaces.push(workspace);
71
71
  }
72
72
  else {
73
- retained.push(applyLegacyIdentities(workspace, override?.legacyIdentities));
73
+ retainedWorkspaces.push(applyLegacyIdentities(workspace, override?.legacyIdentities));
74
74
  }
75
75
  }
76
- const declaration = { retained, excluded, directories: [] };
76
+ const declaration = { retainedWorkspaces, excludedWorkspaces, directories: [] };
77
77
  if (project !== undefined) {
78
78
  declaration.composite = {
79
79
  ...(project.paths !== undefined && { paths: [...project.paths] }),
@@ -87,7 +87,7 @@ function resolveReleasesBlock(workspaces, releases) {
87
87
  const workspaceByDir = new Map(workspaces.map((workspace) => [workspace.dir, workspace]));
88
88
  const entryByPath = new Map();
89
89
  const excludedPaths = new Set();
90
- const renamed = new Map();
90
+ const renamedWorkspaces = new Map();
91
91
  const directories = [];
92
92
  let composite;
93
93
  for (const [name, entry] of Object.entries(releases)) {
@@ -126,22 +126,22 @@ function resolveReleasesBlock(workspaces, releases) {
126
126
  "whose tag prefix derives from its package name; declare the workspace's earlier prefixes in legacyIdentities");
127
127
  }
128
128
  claimPath(entryByPath, name, workspace.workspacePath, 'workspace');
129
- const named = applyLegacyIdentities(workspace, entry.legacyIdentities);
130
- renamed.set(workspace.workspacePath, name === workspace.dir ? named : { ...named, targetName: name });
129
+ const identifiedWorkspace = applyLegacyIdentities(workspace, entry.legacyIdentities);
130
+ renamedWorkspaces.set(workspace.workspacePath, name === workspace.dir ? identifiedWorkspace : { ...identifiedWorkspace, targetName: name });
131
131
  }
132
- const retained = [];
133
- const excluded = [];
132
+ const retainedWorkspaces = [];
133
+ const excludedWorkspaces = [];
134
134
  for (const workspace of workspaces) {
135
135
  if (excludedPaths.has(workspace.workspacePath)) {
136
- excluded.push(workspace);
136
+ excludedWorkspaces.push(workspace);
137
137
  }
138
138
  else {
139
- retained.push(renamed.get(workspace.workspacePath) ?? workspace);
139
+ retainedWorkspaces.push(renamedWorkspaces.get(workspace.workspacePath) ?? workspace);
140
140
  }
141
141
  }
142
- const declaration = { retained, excluded, directories };
142
+ const declaration = { retainedWorkspaces, excludedWorkspaces, directories };
143
143
  if (composite !== undefined) {
144
- const members = resolveCompositeMembers(composite, retained, excluded, directories);
144
+ const members = resolveCompositeMembers(composite, retainedWorkspaces, excludedWorkspaces, directories);
145
145
  declaration.composite = {
146
146
  name: composite.name,
147
147
  members: members.map((member) => member.name),
@@ -22,32 +22,34 @@ export function resolveReleaseTags(args) {
22
22
  return resolveSinglePackageTags(tags, args.singleWorkspace);
23
23
  }
24
24
  function resolveSinglePackageTags(tags, singleWorkspace) {
25
- const matched = tags.filter((tag) => VERSION_PATTERN.test(tag));
25
+ const matchedTags = tags.filter((tag) => VERSION_PATTERN.test(tag));
26
26
  const isPublishable = singleWorkspace?.isPublishable ?? true;
27
- if (matched.length > 1) {
28
- console.warn(`Warning: Multiple version tags found on HEAD: ${matched.join(', ')}. ` +
27
+ if (matchedTags.length > 1) {
28
+ console.warn(`Warning: Multiple version tags found on HEAD: ${matchedTags.join(', ')}. ` +
29
29
  `Publishing the same package multiple times is almost certainly unintended. Using only the first tag.`);
30
- return matched.slice(0, 1).map((tag) => ({ tag, kind: 'package', dir: '.', workspacePath: '.', isPublishable }));
30
+ return matchedTags
31
+ .slice(0, 1)
32
+ .map((tag) => ({ tag, kind: 'package', dir: '.', workspacePath: '.', isPublishable }));
31
33
  }
32
- return matched.map((tag) => ({ tag, kind: 'package', dir: '.', workspacePath: '.', isPublishable }));
34
+ return matchedTags.map((tag) => ({ tag, kind: 'package', dir: '.', workspacePath: '.', isPublishable }));
33
35
  }
34
36
  function resolveMonorepoTags(tags, workspaces, directories, project) {
35
37
  const sortedWorkspaces = workspaces.toSorted((a, b) => b.tagPrefix.length - a.tagPrefix.length);
36
- const resolved = [];
38
+ const resolvedTags = [];
37
39
  for (const tag of tags) {
38
- const match = findMatchingWorkspace(tag, sortedWorkspaces);
40
+ const matchedWorkspace = findMatchingWorkspace(tag, sortedWorkspaces);
39
41
  const directory = directories.find((candidate) => hasVersionAfterPrefix(tag, candidate.tagPrefix));
40
- if (match !== undefined) {
41
- resolved.push({
42
+ if (matchedWorkspace !== undefined) {
43
+ resolvedTags.push({
42
44
  tag,
43
45
  kind: 'package',
44
- dir: getTargetName(match),
45
- workspacePath: match.workspacePath,
46
- isPublishable: match.isPublishable,
46
+ dir: getTargetName(matchedWorkspace),
47
+ workspacePath: matchedWorkspace.workspacePath,
48
+ isPublishable: matchedWorkspace.isPublishable,
47
49
  });
48
50
  }
49
51
  else if (directory !== undefined) {
50
- resolved.push({
52
+ resolvedTags.push({
51
53
  tag,
52
54
  kind: 'directory',
53
55
  dir: directory.name,
@@ -56,7 +58,7 @@ function resolveMonorepoTags(tags, workspaces, directories, project) {
56
58
  });
57
59
  }
58
60
  else if (project !== undefined && hasVersionAfterPrefix(tag, project.tagPrefix)) {
59
- resolved.push({
61
+ resolvedTags.push({
60
62
  tag,
61
63
  kind: 'project',
62
64
  dir: project.name ?? PROJECT_TARGET_ID,
@@ -65,7 +67,7 @@ function resolveMonorepoTags(tags, workspaces, directories, project) {
65
67
  });
66
68
  }
67
69
  }
68
- return resolved;
70
+ return resolvedTags;
69
71
  }
70
72
  function findMatchingWorkspace(tag, sortedWorkspaces) {
71
73
  return sortedWorkspaces.find((workspace) => hasVersionAfterPrefix(tag, workspace.tagPrefix));
@@ -13,8 +13,8 @@ export function resolveReleaseTargets(userConfig, discovery) {
13
13
  return projectMonorepoConfig(mergeMonorepoConfig(discovery.packageDirs, userConfig, readRootPackageVersion()));
14
14
  }
15
15
  export function isSinglePackageTargets(targets) {
16
- const [only] = targets;
17
- return targets.length === 1 && only?.kind === 'package' && !only.isWorkspace;
16
+ const [onlyTarget] = targets;
17
+ return targets.length === 1 && onlyTarget?.kind === 'package' && !onlyTarget.isWorkspace;
18
18
  }
19
19
  export function projectMonorepoConfig(config) {
20
20
  const targets = [
@@ -59,12 +59,12 @@ function renderWorkspaceRow(row, style) {
59
59
  lines.push(` ${row.workspacePath}: derived prefix '${row.derivedPrefix}', ${statusMarker}`);
60
60
  for (const entry of row.legacyEntries) {
61
61
  if (entry.tagCount > 0) {
62
- const recognized = `${entry.tagCount} legacy tags with '${entry.prefix}' prefix (recognized)`;
63
- lines.push(` ${formatStatusLine(style, 'passed', recognized)}`);
62
+ const recognizedMessage = `${entry.tagCount} legacy tags with '${entry.prefix}' prefix (recognized)`;
63
+ lines.push(` ${formatStatusLine(style, 'passed', recognizedMessage)}`);
64
64
  }
65
65
  else {
66
- const tagless = `recorded legacy prefix '${entry.prefix}' does not have any tags`;
67
- lines.push(` ${formatStatusLine(style, 'warning', tagless)}`);
66
+ const taglessMessage = `recorded legacy prefix '${entry.prefix}' does not have any tags`;
67
+ lines.push(` ${formatStatusLine(style, 'warning', taglessMessage)}`);
68
68
  }
69
69
  }
70
70
  return lines;
@@ -20,7 +20,7 @@ export declare function loadRepoLabelsConfig(stderrStyle: OutputStyle, configPat
20
20
  /** Options for the `sync-labels generate` subcommand. */
21
21
  interface GenerateOptions {
22
22
  /** Compares the regenerated content against the committed file instead of writing. */
23
- check?: boolean;
23
+ shouldCheck?: boolean;
24
24
  /** Config file to read, relative to the working directory. Defaults to `CONFIG_FILE_PATH`. */
25
25
  configPath?: string;
26
26
  styles: StreamStyles;
@@ -28,11 +28,11 @@ interface GenerateOptions {
28
28
  /**
29
29
  * Runs the `sync-labels generate` command and returns the process exit code.
30
30
  *
31
- * Writes `.github/labels.yaml` from the config's `repoLabels` block, or, with `check`, reports whether the committed
31
+ * Writes `.github/labels.yaml` from the config's `repoLabels` block, or, with `shouldCheck`, reports whether the committed
32
32
  * file is stale and writes nothing.
33
33
  *
34
34
  * The header names the config by its POSIX path relative to the working directory, the repo root, so that the file
35
35
  * does not depend on the invocation directory or on the machine on which the command ran.
36
36
  */
37
- export declare function generateCommand({ check, configPath, styles }: GenerateOptions): Promise<number>;
37
+ export declare function generateCommand({ shouldCheck, configPath, styles }: GenerateOptions): Promise<number>;
38
38
  export {};
@@ -15,14 +15,14 @@ export function formatLabelsYaml(labels, presetHashes, configFilePath = CONFIG_F
15
15
  for (const [name, hash] of sortedPresetHashes) {
16
16
  headerLines.push(`# ${name} preset hash: ${hash}`);
17
17
  }
18
- const declared = labels.map(({ aliases, archived, color, description, name }) => ({
18
+ const declaredLabels = labels.map(({ aliases, archived, color, description, name }) => ({
19
19
  name,
20
20
  color,
21
21
  description: description ?? '',
22
22
  ...(aliases !== undefined && { aliases }),
23
23
  ...(archived !== undefined && { archived }),
24
24
  }));
25
- const yamlBody = stringify(declared, { singleQuote: true, lineWidth: 0 });
25
+ const yamlBody = stringify(declaredLabels, { singleQuote: true, lineWidth: 0 });
26
26
  return headerLines.join('\n') + '\n' + yamlBody;
27
27
  }
28
28
  export async function loadRepoLabelsConfig(stderrStyle, configPath) {
@@ -41,7 +41,7 @@ export async function loadRepoLabelsConfig(stderrStyle, configPath) {
41
41
  }
42
42
  return result.config.repoLabels;
43
43
  }
44
- export async function generateCommand({ check = false, configPath, styles }) {
44
+ export async function generateCommand({ shouldCheck = false, configPath, styles }) {
45
45
  if (checkRetiredSyncLabelsConfig(configPath)) {
46
46
  return 1;
47
47
  }
@@ -63,8 +63,8 @@ export async function generateCommand({ check = false, configPath, styles }) {
63
63
  for (const presetName of presetNames) {
64
64
  presetHashes.set(presetName, hashPreset(presetName));
65
65
  }
66
- const content = formatLabelsYaml(labels, presetHashes, toRootRelativePosixPath(configPath ?? CONFIG_FILE_PATH));
67
- if (check) {
66
+ const content = formatLabelsYaml(labels, presetHashes, convertToRootRelativePosixPath(configPath ?? CONFIG_FILE_PATH));
67
+ if (shouldCheck) {
68
68
  return compareAgainstCommittedFile(content);
69
69
  }
70
70
  try {
@@ -79,22 +79,22 @@ export async function generateCommand({ check = false, configPath, styles }) {
79
79
  console.info(`Generated ${LABELS_OUTPUT_PATH} with ${String(labels.length)} labels.`);
80
80
  return 0;
81
81
  }
82
- function compareAgainstCommittedFile(expected) {
83
- let existing;
82
+ function compareAgainstCommittedFile(expectedContent) {
83
+ let existingContent;
84
84
  try {
85
- existing = readFileSync(LABELS_OUTPUT_PATH, 'utf8');
85
+ existingContent = readFileSync(LABELS_OUTPUT_PATH, 'utf8');
86
86
  }
87
87
  catch {
88
88
  reportError(`${LABELS_OUTPUT_PATH} is missing. Run \`release-kit sync-labels generate\` and commit the result.`);
89
89
  return 1;
90
90
  }
91
- if (existing !== expected) {
91
+ if (existingContent !== expectedContent) {
92
92
  reportError(`${LABELS_OUTPUT_PATH} is stale. Run \`release-kit sync-labels generate\` and commit the result.`);
93
93
  return 1;
94
94
  }
95
95
  console.info(`${LABELS_OUTPUT_PATH} is up to date.`);
96
96
  return 0;
97
97
  }
98
- function toRootRelativePosixPath(filePath) {
98
+ function convertToRootRelativePosixPath(filePath) {
99
99
  return path.relative(process.cwd(), path.resolve(filePath)).split(path.sep).join('/');
100
100
  }
@@ -3,8 +3,8 @@ import { type StreamStyles } from '@williamthorsen/nmr-core';
3
3
  interface InitOptions {
4
4
  /** Config file to read, relative to the working directory. Defaults to `CONFIG_FILE_PATH`. */
5
5
  configPath?: string;
6
- dryRun: boolean;
7
- force: boolean;
6
+ isDryRun: boolean;
7
+ shouldForce: boolean;
8
8
  styles: StreamStyles;
9
9
  }
10
10
  /**
@@ -17,5 +17,5 @@ interface InitOptions {
17
17
  * `configPath` names the config to read. Because the command fails when the named config does not exist, it
18
18
  * reaches the scaffolding branch only under the default path, and that branch always writes to `CONFIG_FILE_PATH`.
19
19
  */
20
- export declare function syncLabelsInitCommand({ configPath, dryRun, force, styles }: InitOptions): Promise<number>;
20
+ export declare function syncLabelsInitCommand({ configPath, isDryRun, shouldForce, styles, }: InitOptions): Promise<number>;
21
21
  export {};
@@ -6,14 +6,14 @@ import { CONFIG_FILE_PATH } from "../loadConfig.js";
6
6
  import { loadValidatedConfig, reportConfigProblem } from "../loadValidatedConfig.js";
7
7
  import { generateCommand, LABELS_OUTPUT_PATH } from "./generateCommand.js";
8
8
  import { checkRetiredSyncLabelsConfig } from "./retiredConfig.js";
9
- import { buildScopeLabels, readSyncLabelsWorkflowTemplate, renderRepoLabelsBlock, repoLabelsConfigScript, } from "./templates.js";
9
+ import { buildScopeLabels, readSyncLabelsWorkflowTemplate, renderRepoLabelsBlock, renderRepoLabelsConfigScript, } from "./templates.js";
10
10
  const WORKFLOW_PATH = '.github/workflows/sync-labels.yaml';
11
- export async function syncLabelsInitCommand({ configPath, dryRun, force, styles }) {
11
+ export async function syncLabelsInitCommand({ configPath, isDryRun, shouldForce, styles, }) {
12
12
  const configFilePath = configPath ?? CONFIG_FILE_PATH;
13
13
  if (checkRetiredSyncLabelsConfig(configPath)) {
14
14
  return 1;
15
15
  }
16
- if (dryRun) {
16
+ if (isDryRun) {
17
17
  console.info('[dry-run mode]');
18
18
  }
19
19
  console.info('\n> Discovering workspaces');
@@ -36,8 +36,8 @@ export async function syncLabelsInitCommand({ configPath, dryRun, force, styles
36
36
  else {
37
37
  console.info(` Found ${String(workspace.packageDirs.length)} workspaces`);
38
38
  }
39
- const configExists = configPath !== undefined || existsSync(CONFIG_FILE_PATH);
40
- const retiredNames = configExists ? await loadRetiredPackageNames(styles, configPath) : [];
39
+ const doesConfigExist = configPath !== undefined || existsSync(CONFIG_FILE_PATH);
40
+ const retiredNames = doesConfigExist ? await loadRetiredPackageNames(styles, configPath) : [];
41
41
  if (retiredNames === undefined) {
42
42
  return 1;
43
43
  }
@@ -51,9 +51,9 @@ export async function syncLabelsInitCommand({ configPath, dryRun, force, styles
51
51
  process.stderr.write(` ${describeError(error)}\n`);
52
52
  return 1;
53
53
  }
54
- const workflowResult = writeFileWithCheck(WORKFLOW_PATH, workflow, { isDryRun: dryRun, shouldOverwrite: force });
55
- reportWriteResult(workflowResult, dryRun, styles);
56
- if (configExists) {
54
+ const workflowResult = writeFileWithCheck(WORKFLOW_PATH, workflow, { isDryRun, shouldOverwrite: shouldForce });
55
+ reportWriteResult(workflowResult, isDryRun, styles);
56
+ if (doesConfigExist) {
57
57
  console.info(`\n> ${configFilePath} already exists; add this block to the object passed to defineConfig:\n`);
58
58
  console.info(renderRepoLabelsBlock(scopeLabels));
59
59
  if (workflowResult.outcome === 'failed') {
@@ -69,16 +69,16 @@ export async function syncLabelsInitCommand({ configPath, dryRun, force, styles
69
69
  `);
70
70
  return 0;
71
71
  }
72
- const configResult = writeFileWithCheck(CONFIG_FILE_PATH, repoLabelsConfigScript(scopeLabels), {
73
- isDryRun: dryRun,
74
- shouldOverwrite: force,
72
+ const configResult = writeFileWithCheck(CONFIG_FILE_PATH, renderRepoLabelsConfigScript(scopeLabels), {
73
+ isDryRun,
74
+ shouldOverwrite: shouldForce,
75
75
  });
76
- reportWriteResult(configResult, dryRun, styles);
76
+ reportWriteResult(configResult, isDryRun, styles);
77
77
  if (workflowResult.outcome === 'failed' || configResult.outcome === 'failed') {
78
78
  process.stderr.write('Failed to scaffold one or more files.\n');
79
79
  return 1;
80
80
  }
81
- if (dryRun) {
81
+ if (isDryRun) {
82
82
  console.info(`\n> [dry-run] Would generate ${LABELS_OUTPUT_PATH}`);
83
83
  }
84
84
  else {
@@ -109,8 +109,8 @@ async function loadRetiredPackageNames(styles, configPath) {
109
109
  if (result.status === 'missing') {
110
110
  return [];
111
111
  }
112
- return (result.config.retiredPackages ?? []).map((retired) => toUnscopedName(retired.name));
112
+ return (result.config.retiredPackages ?? []).map((retired) => stripNpmScope(retired.name));
113
113
  }
114
- function toUnscopedName(name) {
114
+ function stripNpmScope(name) {
115
115
  return name.startsWith('@') ? name.slice(name.indexOf('/') + 1) : name;
116
116
  }
@@ -25,12 +25,12 @@ export function loadPreset(presetName) {
25
25
  catch (error) {
26
26
  throw chainError(`Failed to read preset "${presetName}"`, error);
27
27
  }
28
- const parsed = parse(content);
29
- if (!Array.isArray(parsed)) {
28
+ const parsedYaml = parse(content);
29
+ if (!Array.isArray(parsedYaml)) {
30
30
  throw new TypeError(`Preset "${presetName}" must be a YAML array of label definitions`);
31
31
  }
32
32
  const labels = [];
33
- for (const entry of parsed) {
33
+ for (const entry of parsedYaml) {
34
34
  if (!isRecord(entry)) {
35
35
  throw new Error(`Preset "${presetName}" contains an invalid label entry: ${JSON.stringify(entry)}`);
36
36
  }