@williamthorsen/release-kit 18.1.1 → 18.2.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.
- package/.meta/changelog.json +60 -0
- package/.readyup/kits/default.js +595 -31
- package/.readyup/kits/npm-auto-publish.js +1 -1
- package/.readyup/manifest.json +55 -33
- package/CHANGELOG.md +18 -0
- package/README.md +19 -1
- package/dist/esm/cli/maintenanceCommands.js +1 -1
- package/dist/esm/init/managed-workflows.d.ts +10 -0
- package/dist/esm/init/managed-workflows.js +18 -0
- package/dist/esm/init/updateTemplatesCommand.js +5 -11
- package/dist/esm/previewTagPrefixes.d.ts +7 -1
- package/dist/esm/previewTagPrefixes.js +9 -4
- package/dist/esm/showTagPrefixesCommand.d.ts +6 -6
- package/dist/esm/showTagPrefixesCommand.js +94 -39
- package/dist/esm/sync-labels/generateCommand.js +0 -4
- package/dist/esm/sync-labels/initCommand.js +0 -4
- package/dist/esm/sync-labels/syncCommand.js +0 -4
- package/docs/configuration.md +3 -3
- package/docs/labels.md +0 -2
- package/package.json +7 -7
- package/dist/esm/sync-labels/retiredConfig.d.ts +0 -11
- package/dist/esm/sync-labels/retiredConfig.js +0 -12
package/.readyup/manifest.json
CHANGED
|
@@ -3,20 +3,19 @@
|
|
|
3
3
|
"kits": [
|
|
4
4
|
{
|
|
5
5
|
"bundledDependencies": {
|
|
6
|
-
"@williamthorsen/toolbelt.datetime": "4.1.
|
|
7
|
-
"@williamthorsen/toolbelt.errors": "0.
|
|
8
|
-
"@williamthorsen/toolbelt.filesystem": "0.10.
|
|
9
|
-
"@williamthorsen/toolbelt.numbers": "
|
|
10
|
-
"@williamthorsen/toolbelt.objects": "4.4.
|
|
11
|
-
"@williamthorsen/toolbelt.packaging": "0.7.
|
|
12
|
-
"@williamthorsen/toolbelt.terminal": "0.3.
|
|
6
|
+
"@williamthorsen/toolbelt.datetime": "4.1.4",
|
|
7
|
+
"@williamthorsen/toolbelt.errors": "0.10.1",
|
|
8
|
+
"@williamthorsen/toolbelt.filesystem": "0.10.3",
|
|
9
|
+
"@williamthorsen/toolbelt.numbers": "8.0.1",
|
|
10
|
+
"@williamthorsen/toolbelt.objects": "4.4.3",
|
|
11
|
+
"@williamthorsen/toolbelt.packaging": "0.7.3",
|
|
12
|
+
"@williamthorsen/toolbelt.terminal": "0.3.1",
|
|
13
13
|
"ansi-regex": "6.6.0",
|
|
14
|
-
"ansi-styles": "6.2.3",
|
|
15
|
-
"cli-truncate": "6.
|
|
14
|
+
"ansi-styles": "6.2.3, 7.0.0",
|
|
15
|
+
"cli-truncate": "6.2.0",
|
|
16
16
|
"diff": "9.0.0",
|
|
17
17
|
"get-east-asian-width": "1.7.0",
|
|
18
|
-
"
|
|
19
|
-
"slice-ansi": "9.0.1",
|
|
18
|
+
"slice-ansi": "10.0.1",
|
|
20
19
|
"string-width": "8.3.0",
|
|
21
20
|
"strip-ansi": "7.2.0",
|
|
22
21
|
"wrap-ansi": "10.0.2"
|
|
@@ -26,7 +25,7 @@
|
|
|
26
25
|
"checklist": "release-kit",
|
|
27
26
|
"checks": [
|
|
28
27
|
"@williamthorsen/release-kit in devDependencies",
|
|
29
|
-
"@williamthorsen/release-kit >= 18.
|
|
28
|
+
"@williamthorsen/release-kit >= 18.2.0",
|
|
30
29
|
"release.yaml workflow exists",
|
|
31
30
|
"release.yaml matches template",
|
|
32
31
|
"release.yaml does not reference deprecated tag ref",
|
|
@@ -51,8 +50,7 @@
|
|
|
51
50
|
"@changesets/cli not in devDependencies",
|
|
52
51
|
"sync-labels.yaml workflow exists",
|
|
53
52
|
"sync-labels.yaml matches template",
|
|
54
|
-
"sync-labels.yaml does not reference deprecated tag ref"
|
|
55
|
-
"retired .config/sync-labels.config.ts is absent"
|
|
53
|
+
"sync-labels.yaml does not reference deprecated tag ref"
|
|
56
54
|
]
|
|
57
55
|
}
|
|
58
56
|
],
|
|
@@ -142,7 +140,7 @@
|
|
|
142
140
|
"path": "../../nmr-core/dist/esm/timer.js"
|
|
143
141
|
},
|
|
144
142
|
{
|
|
145
|
-
"hash": "
|
|
143
|
+
"hash": "ee8d2dc8",
|
|
146
144
|
"kind": "module",
|
|
147
145
|
"path": "kits/default.ts"
|
|
148
146
|
},
|
|
@@ -157,12 +155,17 @@
|
|
|
157
155
|
"path": "lib/config-checks.ts"
|
|
158
156
|
},
|
|
159
157
|
{
|
|
160
|
-
"hash": "
|
|
158
|
+
"hash": "70633d7f",
|
|
159
|
+
"kind": "module",
|
|
160
|
+
"path": "lib/template-checks.ts"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"hash": "ec55cfef",
|
|
161
164
|
"kind": "module",
|
|
162
165
|
"path": "lib/workflow-hashes.ts"
|
|
163
166
|
},
|
|
164
167
|
{
|
|
165
|
-
"hash": "
|
|
168
|
+
"hash": "ec16f961",
|
|
166
169
|
"kind": "inline",
|
|
167
170
|
"path": "../package.json",
|
|
168
171
|
"paths": [
|
|
@@ -179,11 +182,31 @@
|
|
|
179
182
|
"kind": "module",
|
|
180
183
|
"path": "../src/init/detectRepoType.ts"
|
|
181
184
|
},
|
|
185
|
+
{
|
|
186
|
+
"hash": "d360febf",
|
|
187
|
+
"kind": "module",
|
|
188
|
+
"path": "../src/init/hasProvenance.ts"
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"hash": "3238f7e0",
|
|
192
|
+
"kind": "module",
|
|
193
|
+
"path": "../src/init/managed-workflows.ts"
|
|
194
|
+
},
|
|
182
195
|
{
|
|
183
196
|
"hash": "133be525",
|
|
184
197
|
"kind": "module",
|
|
185
198
|
"path": "../src/init/parseJsonRecord.ts"
|
|
186
199
|
},
|
|
200
|
+
{
|
|
201
|
+
"hash": "5950f562",
|
|
202
|
+
"kind": "module",
|
|
203
|
+
"path": "../src/init/scaffold.ts"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"hash": "e10ddb57",
|
|
207
|
+
"kind": "module",
|
|
208
|
+
"path": "../src/init/templates.ts"
|
|
209
|
+
},
|
|
187
210
|
{
|
|
188
211
|
"hash": "2210df36",
|
|
189
212
|
"kind": "module",
|
|
@@ -192,27 +215,26 @@
|
|
|
192
215
|
],
|
|
193
216
|
"name": "default",
|
|
194
217
|
"path": "kits/default.js",
|
|
195
|
-
"readyupVersion": "0.
|
|
218
|
+
"readyupVersion": "0.46.2",
|
|
196
219
|
"source": "kits/default.ts",
|
|
197
|
-
"sourceHash": "
|
|
198
|
-
"targetHash": "
|
|
220
|
+
"sourceHash": "ee8d2dc8",
|
|
221
|
+
"targetHash": "dfbfab4f"
|
|
199
222
|
},
|
|
200
223
|
{
|
|
201
224
|
"bundledDependencies": {
|
|
202
|
-
"@williamthorsen/toolbelt.datetime": "4.1.
|
|
203
|
-
"@williamthorsen/toolbelt.errors": "0.
|
|
204
|
-
"@williamthorsen/toolbelt.filesystem": "0.10.
|
|
205
|
-
"@williamthorsen/toolbelt.numbers": "
|
|
206
|
-
"@williamthorsen/toolbelt.objects": "4.4.
|
|
207
|
-
"@williamthorsen/toolbelt.packaging": "0.7.
|
|
208
|
-
"@williamthorsen/toolbelt.terminal": "0.3.
|
|
225
|
+
"@williamthorsen/toolbelt.datetime": "4.1.4",
|
|
226
|
+
"@williamthorsen/toolbelt.errors": "0.10.1",
|
|
227
|
+
"@williamthorsen/toolbelt.filesystem": "0.10.3",
|
|
228
|
+
"@williamthorsen/toolbelt.numbers": "8.0.1",
|
|
229
|
+
"@williamthorsen/toolbelt.objects": "4.4.3",
|
|
230
|
+
"@williamthorsen/toolbelt.packaging": "0.7.3",
|
|
231
|
+
"@williamthorsen/toolbelt.terminal": "0.3.1",
|
|
209
232
|
"ansi-regex": "6.6.0",
|
|
210
|
-
"ansi-styles": "6.2.3",
|
|
211
|
-
"cli-truncate": "6.
|
|
233
|
+
"ansi-styles": "6.2.3, 7.0.0",
|
|
234
|
+
"cli-truncate": "6.2.0",
|
|
212
235
|
"diff": "9.0.0",
|
|
213
236
|
"get-east-asian-width": "1.7.0",
|
|
214
|
-
"
|
|
215
|
-
"slice-ansi": "9.0.1",
|
|
237
|
+
"slice-ansi": "10.0.1",
|
|
216
238
|
"string-width": "8.3.0",
|
|
217
239
|
"strip-ansi": "7.2.0",
|
|
218
240
|
"wrap-ansi": "10.0.2"
|
|
@@ -345,10 +367,10 @@
|
|
|
345
367
|
],
|
|
346
368
|
"name": "npm-auto-publish",
|
|
347
369
|
"path": "kits/npm-auto-publish.js",
|
|
348
|
-
"readyupVersion": "0.
|
|
370
|
+
"readyupVersion": "0.46.2",
|
|
349
371
|
"source": "kits/npm-auto-publish.ts",
|
|
350
372
|
"sourceHash": "682fdd4a",
|
|
351
|
-
"targetHash": "
|
|
373
|
+
"targetHash": "2bfaa0b5"
|
|
352
374
|
}
|
|
353
375
|
]
|
|
354
376
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 18.2.0 — 2026-11-13
|
|
6
|
+
|
|
7
|
+
### 🎉 Features
|
|
8
|
+
|
|
9
|
+
- Changes `release-kit show-tag-prefixes` to print one block per target that lists the derived prefix and each declared legacy identity with their tag counts in aligned columns, and to print the "Undeclared tag prefixes" section on every run, showing `(none)` when the scan does not find any candidates. (#1332)
|
|
10
|
+
- Adds a "Retired packages" section to `release-kit show-tag-prefixes`, which lists each entry declared in `retiredPackages` with its tag prefix, tag count, name, and successor. (#1332)
|
|
11
|
+
- Adds a closing note to `release-kit show-tag-prefixes` when a derived prefix does not have any tags yet, which explains that `release-kit tag` creates the first tag from the tags file that `release-kit prepare` writes. (#1332)
|
|
12
|
+
- Makes the template checks for `release.yaml`, `publish.yaml`, and `create-github-release.yaml` report the differing hunks, and distinguish a missing file from an unreadable one, rather than report only that a hash differs. (#1336)
|
|
13
|
+
|
|
14
|
+
### 🪦 Removed
|
|
15
|
+
|
|
16
|
+
- Removes the check for the retired `.config/sync-labels.config.ts`, which made `sync-labels init`, `generate`, and `sync` exit with an error and made the release-kit readyup kit fail while the file existed. (#1333)
|
|
17
|
+
|
|
18
|
+
### 🐛 Bug fixes
|
|
19
|
+
|
|
20
|
+
- Fixes the issue that `release-kit`'s ReadyUp kit reported the warning `releaseNotes.shouldInjectIntoReadme is true`, which the consumer could not clear, in a repo without any publishable package, by making the check skip with the reason `no publishable packages`. (#1334)
|
|
21
|
+
- Fixes the issue that the `publish.yaml matches template` check in `rdy run --from npm:@williamthorsen/release-kit` failed a `publish.yaml` that omits provenance, a setting that `release-kit update-templates` preserves. (#1336)
|
|
22
|
+
|
|
5
23
|
## 18.1.1 — 2026-11-12
|
|
6
24
|
|
|
7
25
|
### ⚙️ Tooling
|
package/README.md
CHANGED
|
@@ -6,7 +6,25 @@ Version-bumping and changelog-generation toolkit for release workflows.
|
|
|
6
6
|
|
|
7
7
|
Provides a self-contained CLI that auto-discovers workspaces from `pnpm-workspace.yaml`, parses conventional commits, determines version bumps, updates `package.json` files, and generates changelogs from the same commit history that decides each bump (with optional [editorial overrides](docs/editorial-overrides.md)).
|
|
8
8
|
|
|
9
|
-
<!-- section:release-notes
|
|
9
|
+
<!-- section:release-notes -->
|
|
10
|
+
## Release notes — v18.2.0 (2026-11-13)
|
|
11
|
+
|
|
12
|
+
### 🎉 Features
|
|
13
|
+
|
|
14
|
+
- Changes `release-kit show-tag-prefixes` to print one block per target that lists the derived prefix and each declared legacy identity with their tag counts in aligned columns, and to print the "Undeclared tag prefixes" section on every run, showing `(none)` when the scan does not find any candidates. (#1332)
|
|
15
|
+
- Adds a "Retired packages" section to `release-kit show-tag-prefixes`, which lists each entry declared in `retiredPackages` with its tag prefix, tag count, name, and successor. (#1332)
|
|
16
|
+
- Adds a closing note to `release-kit show-tag-prefixes` when a derived prefix does not have any tags yet, which explains that `release-kit tag` creates the first tag from the tags file that `release-kit prepare` writes. (#1332)
|
|
17
|
+
- Makes the template checks for `release.yaml`, `publish.yaml`, and `create-github-release.yaml` report the differing hunks, and distinguish a missing file from an unreadable one, rather than report only that a hash differs. (#1336)
|
|
18
|
+
|
|
19
|
+
### 🪦 Removed
|
|
20
|
+
|
|
21
|
+
- Removes the check for the retired `.config/sync-labels.config.ts`, which made `sync-labels init`, `generate`, and `sync` exit with an error and made the release-kit readyup kit fail while the file existed. (#1333)
|
|
22
|
+
|
|
23
|
+
### 🐛 Bug fixes
|
|
24
|
+
|
|
25
|
+
- Fixes the issue that `release-kit`'s ReadyUp kit reported the warning `releaseNotes.shouldInjectIntoReadme is true`, which the consumer could not clear, in a repo without any publishable package, by making the check skip with the reason `no publishable packages`. (#1334)
|
|
26
|
+
- Fixes the issue that the `publish.yaml matches template` check in `rdy run --from npm:@williamthorsen/release-kit` failed a `publish.yaml` that omits provenance, a setting that `release-kit update-templates` preserves. (#1336)
|
|
27
|
+
<!-- /section:release-notes -->
|
|
10
28
|
|
|
11
29
|
## Installation
|
|
12
30
|
|
|
@@ -12,7 +12,7 @@ import { CONFIG_FLAG, runReportingFailures } from "./commandKit.js";
|
|
|
12
12
|
const { defineCommand, defineGroup } = createCli();
|
|
13
13
|
export const showTagPrefixes = defineCommand({
|
|
14
14
|
summary: 'Show derived and declared legacy tag prefixes per workspace',
|
|
15
|
-
description: 'Print
|
|
15
|
+
description: 'Print one block per workspace with its derived tag prefix, declared legacy identities, and tag counts, followed by the declared retired packages. Reports any release-shaped tags whose prefix is neither derived nor declared, with a copy-pasteable config snippet.',
|
|
16
16
|
flags: CONFIG_FLAG,
|
|
17
17
|
run: ({ flags, context }) => runReportingFailures(context.styles, () => {
|
|
18
18
|
enterRepoRoot();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RepoType } from './detectRepoType.js';
|
|
2
|
+
/** Renders the create-github-release workflow that the repo should contain. */
|
|
3
|
+
export declare function renderExpectedCreateGithubReleaseWorkflow(repoType: RepoType): string;
|
|
4
|
+
/**
|
|
5
|
+
* Renders the publish workflow that the repo should contain, keeping the provenance setting of the existing
|
|
6
|
+
* `publish.yaml` and enabling provenance when the file is missing.
|
|
7
|
+
*/
|
|
8
|
+
export declare function renderExpectedPublishWorkflow(repoType: RepoType): string;
|
|
9
|
+
/** Renders the release workflow that the repo should contain. */
|
|
10
|
+
export declare function renderExpectedReleaseWorkflow(repoType: RepoType): string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { hasProvenance } from "./hasProvenance.js";
|
|
3
|
+
import { PUBLISH_WORKFLOW_PATH } from "./scaffold.js";
|
|
4
|
+
import { renderCreateGithubReleaseWorkflow, renderPublishWorkflow, renderReleaseWorkflow } from "./templates.js";
|
|
5
|
+
export function renderExpectedCreateGithubReleaseWorkflow(repoType) {
|
|
6
|
+
return renderCreateGithubReleaseWorkflow(repoType);
|
|
7
|
+
}
|
|
8
|
+
export function renderExpectedPublishWorkflow(repoType) {
|
|
9
|
+
return renderPublishWorkflow(repoType, { shouldGenerateProvenance: readProvenanceSetting() });
|
|
10
|
+
}
|
|
11
|
+
export function renderExpectedReleaseWorkflow(repoType) {
|
|
12
|
+
return renderReleaseWorkflow(repoType);
|
|
13
|
+
}
|
|
14
|
+
function readProvenanceSetting() {
|
|
15
|
+
if (!existsSync(PUBLISH_WORKFLOW_PATH))
|
|
16
|
+
return true;
|
|
17
|
+
return hasProvenance(readFileSync(PUBLISH_WORKFLOW_PATH, 'utf8'));
|
|
18
|
+
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { existsSync
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
2
|
import { isAnticipatedFailure, printError, printSkip, printStep, printSuccess, reportTemplateUpdate, updateManagedFile, } from '@williamthorsen/nmr-core';
|
|
3
3
|
import { describeError } from '@williamthorsen/toolbelt.errors';
|
|
4
4
|
import { readSyncLabelsWorkflowTemplate } from "../sync-labels/templates.js";
|
|
5
5
|
import { detectRepoType } from "./detectRepoType.js";
|
|
6
|
-
import { hasProvenance } from "./hasProvenance.js";
|
|
7
6
|
import { formatPrivateWorkflowSkip, hasPublishablePackage } from "./hasPublishablePackage.js";
|
|
8
7
|
import { checkEligibility } from "./initCommand.js";
|
|
8
|
+
import { renderExpectedCreateGithubReleaseWorkflow, renderExpectedPublishWorkflow, renderExpectedReleaseWorkflow, } from "./managed-workflows.js";
|
|
9
9
|
import { CREATE_GITHUB_RELEASE_WORKFLOW_PATH, PUBLISH_WORKFLOW_PATH, PUBLISHING_WORKFLOW_PATHS } from "./scaffold.js";
|
|
10
|
-
import { renderCreateGithubReleaseWorkflow, renderPublishWorkflow, renderReleaseWorkflow } from "./templates.js";
|
|
11
10
|
const SYNC_LABELS_WORKFLOW_PATH = '.github/workflows/sync-labels.yaml';
|
|
12
11
|
export function updateTemplatesCommand({ isDryRun, styles }) {
|
|
13
12
|
if (isDryRun) {
|
|
@@ -65,17 +64,12 @@ function buildManagedFiles(repoType, publishable) {
|
|
|
65
64
|
? []
|
|
66
65
|
: PUBLISHING_WORKFLOW_PATHS.filter((filePath) => !existsSync(filePath));
|
|
67
66
|
const files = [
|
|
68
|
-
[CREATE_GITHUB_RELEASE_WORKFLOW_PATH,
|
|
69
|
-
[PUBLISH_WORKFLOW_PATH,
|
|
70
|
-
['.github/workflows/release.yaml',
|
|
67
|
+
[CREATE_GITHUB_RELEASE_WORKFLOW_PATH, renderExpectedCreateGithubReleaseWorkflow(repoType)],
|
|
68
|
+
[PUBLISH_WORKFLOW_PATH, renderExpectedPublishWorkflow(repoType)],
|
|
69
|
+
['.github/workflows/release.yaml', renderExpectedReleaseWorkflow(repoType)],
|
|
71
70
|
];
|
|
72
71
|
if (existsSync(SYNC_LABELS_WORKFLOW_PATH)) {
|
|
73
72
|
files.push([SYNC_LABELS_WORKFLOW_PATH, readSyncLabelsWorkflowTemplate()]);
|
|
74
73
|
}
|
|
75
74
|
return { files: files.filter(([filePath]) => !skippedPaths.includes(filePath)), skippedPaths };
|
|
76
75
|
}
|
|
77
|
-
function readProvenanceSetting() {
|
|
78
|
-
if (!existsSync(PUBLISH_WORKFLOW_PATH))
|
|
79
|
-
return true;
|
|
80
|
-
return hasProvenance(readFileSync(PUBLISH_WORKFLOW_PATH, 'utf8'));
|
|
81
|
-
}
|
|
@@ -6,6 +6,11 @@ export interface TagPrefixPreviewRow {
|
|
|
6
6
|
workspacePath: string;
|
|
7
7
|
/** Directory basename (e.g., `core`). */
|
|
8
8
|
dir: string;
|
|
9
|
+
/**
|
|
10
|
+
* The workspace's `package.json` name or the directory target's `releases` key; `null` when a workspace's derivation
|
|
11
|
+
* failed.
|
|
12
|
+
*/
|
|
13
|
+
name: string | null;
|
|
9
14
|
/** The derived tag prefix, or `null` when derivation failed. */
|
|
10
15
|
derivedPrefix: string | null;
|
|
11
16
|
/** Human-readable reason derivation failed, or `null` when it succeeded. */
|
|
@@ -15,8 +20,9 @@ export interface TagPrefixPreviewRow {
|
|
|
15
20
|
/** One entry per declared legacy prefix, with its current tag count. */
|
|
16
21
|
legacyEntries: LegacyTagPrefixEntry[];
|
|
17
22
|
}
|
|
18
|
-
/** A single declared legacy prefix and its tag count. */
|
|
23
|
+
/** A single declared legacy identity's prefix and its tag count. */
|
|
19
24
|
export interface LegacyTagPrefixEntry {
|
|
25
|
+
name: string;
|
|
20
26
|
prefix: string;
|
|
21
27
|
tagCount: number;
|
|
22
28
|
}
|
|
@@ -17,7 +17,7 @@ export function previewTagPrefixes(config) {
|
|
|
17
17
|
const workspacePaths = workspace.kind === 'packages' ? workspace.packageDirs : [];
|
|
18
18
|
const overridesByPath = buildOverrideMap(config, workspacePaths);
|
|
19
19
|
const workspaces = [
|
|
20
|
-
...Array.from(workspacePaths, (workspacePath) => buildPreviewRow(workspacePath, () => deriveWorkspaceConfig(workspacePath)
|
|
20
|
+
...Array.from(workspacePaths, (workspacePath) => buildPreviewRow(workspacePath, null, () => deriveWorkspaceConfig(workspacePath), overridesByPath)),
|
|
21
21
|
...buildDirectoryRows(config, workspacePaths, overridesByPath),
|
|
22
22
|
];
|
|
23
23
|
const retiredPackages = buildRetiredPreviewEntries(config?.retiredPackages ?? []);
|
|
@@ -59,15 +59,18 @@ function buildDirectoryRows(config, workspacePaths, overridesByPath) {
|
|
|
59
59
|
path: directoryPath,
|
|
60
60
|
...(entry.tagPrefix !== undefined && { tagPrefix: entry.tagPrefix }),
|
|
61
61
|
};
|
|
62
|
-
return [buildPreviewRow(directoryPath, () => deriveDirectoryConfig(declaredDirectory)
|
|
62
|
+
return [buildPreviewRow(directoryPath, name, () => deriveDirectoryConfig(declaredDirectory), overridesByPath)];
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
|
-
function buildPreviewRow(workspacePath,
|
|
65
|
+
function buildPreviewRow(workspacePath, knownName, deriveTarget, overridesByPath) {
|
|
66
66
|
const dir = basename(workspacePath);
|
|
67
|
+
let name = knownName;
|
|
67
68
|
let derivedPrefix = null;
|
|
68
69
|
let derivationError = null;
|
|
69
70
|
try {
|
|
70
|
-
|
|
71
|
+
const target = deriveTarget();
|
|
72
|
+
name = target.name;
|
|
73
|
+
derivedPrefix = target.tagPrefix;
|
|
71
74
|
}
|
|
72
75
|
catch (error) {
|
|
73
76
|
derivationError = describeError(error);
|
|
@@ -75,12 +78,14 @@ function buildPreviewRow(workspacePath, derivePrefix, overridesByPath) {
|
|
|
75
78
|
const derivedTagCount = derivedPrefix === null ? 0 : countTagsMatching(derivedPrefix);
|
|
76
79
|
const declaredIdentities = overridesByPath.get(workspacePath) ?? [];
|
|
77
80
|
const legacyEntries = declaredIdentities.map((identity) => ({
|
|
81
|
+
name: identity.name,
|
|
78
82
|
prefix: identity.tagPrefix,
|
|
79
83
|
tagCount: countTagsMatching(identity.tagPrefix),
|
|
80
84
|
}));
|
|
81
85
|
return {
|
|
82
86
|
workspacePath,
|
|
83
87
|
dir,
|
|
88
|
+
name,
|
|
84
89
|
derivedPrefix,
|
|
85
90
|
derivationError,
|
|
86
91
|
derivedTagCount,
|
|
@@ -2,11 +2,11 @@ import { type StreamStyles } from '@williamthorsen/nmr-core';
|
|
|
2
2
|
/**
|
|
3
3
|
* Runs the CLI `show-tag-prefixes` command and returns its exit code.
|
|
4
4
|
*
|
|
5
|
-
* Prints
|
|
6
|
-
*
|
|
7
|
-
* derivation failure or collision and `0` otherwise; undeclared
|
|
8
|
-
* exists and either fails to load or fails validation, the
|
|
9
|
-
* modes, because a default-config preview would understate
|
|
10
|
-
* absent, the command previews against derived defaults.
|
|
5
|
+
* Prints one block per target, with its derived prefix and declared legacy identities and their tag counts, then the
|
|
6
|
+
* declared retired packages, the candidate-shaped tags outside the known set, and a footer on creating the first tag
|
|
7
|
+
* when a target does not have any. Returns `1` on any derivation failure or collision and `0` otherwise; undeclared
|
|
8
|
+
* candidates do not affect the exit code. When a config exists and either fails to load or fails validation, the
|
|
9
|
+
* command reports it to stderr and returns `1` in both repo modes, because a default-config preview would understate
|
|
10
|
+
* the declared legacy prefixes. When the default config is absent, the command previews against derived defaults.
|
|
11
11
|
*/
|
|
12
12
|
export declare function showTagPrefixesCommand(styles: StreamStyles, configPath?: string): Promise<number>;
|
|
@@ -2,7 +2,7 @@ import { formatStatusLine, isAnticipatedFailure, reportError, } from '@williamth
|
|
|
2
2
|
import { BIN } from "./bin.js";
|
|
3
3
|
import { detectRepoType } from "./init/detectRepoType.js";
|
|
4
4
|
import { loadValidatedConfig, reportConfigProblem } from "./loadValidatedConfig.js";
|
|
5
|
-
import { previewTagPrefixes } from "./previewTagPrefixes.js";
|
|
5
|
+
import { previewTagPrefixes, } from "./previewTagPrefixes.js";
|
|
6
6
|
export async function showTagPrefixesCommand(styles, configPath) {
|
|
7
7
|
const result = await loadValidatedConfig(configPath);
|
|
8
8
|
if (result.status === 'invalid') {
|
|
@@ -27,59 +27,114 @@ export async function showTagPrefixesCommand(styles, configPath) {
|
|
|
27
27
|
process.stdout.write(renderMonorepo(preview, styles.stdout));
|
|
28
28
|
return computeExitCode(preview);
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
const LABEL_WIDTH = 'legacy identity'.length;
|
|
31
|
+
const FIRST_TAG_FOOTER = 'A workspace marked "no derived tags yet" has not been released under its derived prefix. `release-kit tag` creates its first tag from the tags file that `release-kit prepare` writes.';
|
|
32
|
+
function computeExitCode(preview) {
|
|
33
|
+
const hasDerivationFailure = preview.workspaces.some((row) => row.derivedPrefix === null);
|
|
34
|
+
const hasCollision = preview.collisions.length > 0;
|
|
35
|
+
return hasDerivationFailure || hasCollision ? 1 : 0;
|
|
36
|
+
}
|
|
37
|
+
function formatPrefixColumns(columns, prefix, tagCount, note) {
|
|
38
|
+
const cells = `${prefix.padEnd(columns.prefixWidth)} ${String(tagCount).padStart(columns.countDigits)} tags`;
|
|
39
|
+
return note === undefined ? cells : `${cells} ${note}`;
|
|
40
|
+
}
|
|
41
|
+
function formatRow(label, body) {
|
|
42
|
+
return ` ${label.padEnd(LABEL_WIDTH)} ${body}`;
|
|
43
|
+
}
|
|
44
|
+
function measureColumns(preview) {
|
|
45
|
+
const entries = preview.retiredPackages.map((entry) => ({
|
|
46
|
+
prefix: entry.tagPrefix,
|
|
47
|
+
tagCount: entry.tagCount,
|
|
48
|
+
}));
|
|
49
|
+
for (const row of preview.workspaces) {
|
|
50
|
+
if (row.derivedPrefix !== null)
|
|
51
|
+
entries.push({ prefix: row.derivedPrefix, tagCount: row.derivedTagCount });
|
|
52
|
+
entries.push(...row.legacyEntries);
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
prefixWidth: Math.max(0, ...entries.map((entry) => entry.prefix.length)),
|
|
56
|
+
countDigits: Math.max(1, ...entries.map((entry) => String(entry.tagCount).length)),
|
|
57
|
+
};
|
|
37
58
|
}
|
|
38
59
|
function renderMonorepo(preview, style) {
|
|
39
|
-
const
|
|
60
|
+
const columns = measureColumns(preview);
|
|
61
|
+
const lines = ['Workspace tag prefixes'];
|
|
40
62
|
for (const row of preview.workspaces) {
|
|
41
|
-
lines.push(...
|
|
63
|
+
lines.push('', ...renderTargetBlock(row, preview.collisions, columns, style));
|
|
42
64
|
}
|
|
43
|
-
if (preview.
|
|
44
|
-
lines.push('',
|
|
65
|
+
if (preview.retiredPackages.length > 0) {
|
|
66
|
+
lines.push('', 'Retired packages', '', ...renderRetiredLines(preview.retiredPackages, columns, style));
|
|
45
67
|
}
|
|
46
|
-
|
|
47
|
-
|
|
68
|
+
lines.push('', 'Undeclared tag prefixes', '', ...renderUndeclaredSection(preview.undeclaredCandidates, style));
|
|
69
|
+
if (preview.workspaces.some((row) => row.derivedPrefix !== null && row.derivedTagCount === 0)) {
|
|
70
|
+
lines.push('', formatStatusLine(style, 'info', FIRST_TAG_FOOTER));
|
|
48
71
|
}
|
|
49
72
|
lines.push('');
|
|
50
73
|
return lines.join('\n');
|
|
51
74
|
}
|
|
52
|
-
function
|
|
53
|
-
|
|
75
|
+
function renderRetiredLines(retiredPackages, columns, style) {
|
|
76
|
+
return retiredPackages.map((entry) => {
|
|
77
|
+
const identity = entry.successor === undefined ? entry.name : `${entry.name}, successor: ${entry.successor}`;
|
|
78
|
+
const status = entry.tagCount > 0 ? 'passed' : 'warning';
|
|
79
|
+
return ` ${formatStatusLine(style, status, formatPrefixColumns(columns, entry.tagPrefix, entry.tagCount, identity))}`;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function renderSinglePackage() {
|
|
83
|
+
const lines = [
|
|
84
|
+
'Workspace tag prefixes',
|
|
85
|
+
'',
|
|
86
|
+
'. (single-package mode)',
|
|
87
|
+
formatRow('derived prefix', 'v'),
|
|
88
|
+
'',
|
|
89
|
+
];
|
|
90
|
+
return lines.join('\n');
|
|
91
|
+
}
|
|
92
|
+
function renderSuggestedSnippet(candidates) {
|
|
93
|
+
const entries = candidates
|
|
94
|
+
.map((candidate) => ` { dir: '${candidate.suggestedDir}', legacyIdentities: [{ name: 'TODO-fill-in-legacy-npm-name', tagPrefix: '${candidate.prefix}' }] },`)
|
|
95
|
+
.join('\n');
|
|
96
|
+
return ` workspaces: [\n${entries}\n ],`;
|
|
97
|
+
}
|
|
98
|
+
function renderTargetBlock(row, collisions, columns, style) {
|
|
99
|
+
const lines = [row.name === null ? row.workspacePath : `${row.workspacePath} (${row.name})`];
|
|
54
100
|
if (row.derivedPrefix === null) {
|
|
55
101
|
const failure = formatStatusLine(style, 'failed', `derivation failed: ${row.derivationError ?? 'unknown error'}`);
|
|
56
|
-
lines.push(
|
|
102
|
+
lines.push(formatRow('derived prefix', failure));
|
|
57
103
|
return lines;
|
|
58
104
|
}
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
105
|
+
const collidingPaths = collisions
|
|
106
|
+
.filter((collision) => collision.tagPrefix === row.derivedPrefix)
|
|
107
|
+
.flatMap((collision) => collision.workspacePaths)
|
|
108
|
+
.filter((path) => path !== row.workspacePath);
|
|
109
|
+
let derivedStatus = 'passed';
|
|
110
|
+
let derivedNote;
|
|
111
|
+
if (collidingPaths.length > 0) {
|
|
112
|
+
derivedStatus = 'failed';
|
|
113
|
+
derivedNote = `collides with ${collidingPaths.join(', ')}`;
|
|
114
|
+
}
|
|
115
|
+
else if (row.derivedTagCount === 0) {
|
|
116
|
+
derivedStatus = 'warning';
|
|
117
|
+
derivedNote = 'no derived tags yet';
|
|
118
|
+
}
|
|
119
|
+
const derivedCells = formatPrefixColumns(columns, row.derivedPrefix, row.derivedTagCount, derivedNote);
|
|
120
|
+
lines.push(formatRow('derived prefix', formatStatusLine(style, derivedStatus, derivedCells)));
|
|
63
121
|
for (const entry of row.legacyEntries) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
const taglessMessage = `recorded legacy prefix '${entry.prefix}' does not have any tags`;
|
|
70
|
-
lines.push(` ${formatStatusLine(style, 'warning', taglessMessage)}`);
|
|
71
|
-
}
|
|
122
|
+
const status = entry.tagCount > 0 ? 'passed' : 'warning';
|
|
123
|
+
const legacyCells = formatPrefixColumns(columns, entry.prefix, entry.tagCount, entry.name);
|
|
124
|
+
lines.push(formatRow('legacy identity', formatStatusLine(style, status, legacyCells)));
|
|
72
125
|
}
|
|
73
126
|
return lines;
|
|
74
127
|
}
|
|
75
|
-
function
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
128
|
+
function renderUndeclaredSection(candidates, style) {
|
|
129
|
+
if (candidates.length === 0)
|
|
130
|
+
return [' (none)'];
|
|
131
|
+
return [
|
|
132
|
+
...candidates.map((candidate) => ` ${formatStatusLine(style, 'warning', `'${candidate.prefix}': ${candidate.tagCount} tags (e.g., ${candidate.exampleTags.join(', ')})`)}`),
|
|
133
|
+
'',
|
|
134
|
+
'Suggested config snippet (adjust `dir` to match the workspace if the guess is wrong, and replace the `name` placeholder with the legacy npm name):',
|
|
135
|
+
'',
|
|
136
|
+
renderSuggestedSnippet(candidates),
|
|
137
|
+
'',
|
|
138
|
+
"If the suggested `dir` does not match the workspace, adjust it before pasting. Each legacy identity requires a `name`: Replace the `TODO-fill-in-legacy-npm-name` placeholder with the package's prior npm name.",
|
|
139
|
+
];
|
|
85
140
|
}
|
|
@@ -8,7 +8,6 @@ import { CONFIG_FILE_PATH } from "../loadConfig.js";
|
|
|
8
8
|
import { loadValidatedConfig, reportConfigProblem } from "../loadValidatedConfig.js";
|
|
9
9
|
import { hashPreset } from "./presets.js";
|
|
10
10
|
import { resolveLabels } from "./resolveLabels.js";
|
|
11
|
-
import { checkRetiredSyncLabelsConfig } from "./retiredConfig.js";
|
|
12
11
|
export const LABELS_OUTPUT_PATH = '.github/labels.yaml';
|
|
13
12
|
export function formatLabelsYaml(labels, presetHashes, configFilePath = CONFIG_FILE_PATH) {
|
|
14
13
|
const headerLines = ['# Generated by release-kit sync-labels — do not edit.', `# Source: ${configFilePath}`];
|
|
@@ -43,9 +42,6 @@ export async function loadRepoLabelsConfig(stderrStyle, configPath) {
|
|
|
43
42
|
return result.config.repoLabels;
|
|
44
43
|
}
|
|
45
44
|
export async function generateCommand({ shouldCheck = false, configPath, styles }) {
|
|
46
|
-
if (checkRetiredSyncLabelsConfig(configPath)) {
|
|
47
|
-
return 1;
|
|
48
|
-
}
|
|
49
45
|
const repoLabels = await loadRepoLabelsConfig(styles.stderr, configPath);
|
|
50
46
|
if (repoLabels === undefined) {
|
|
51
47
|
return 1;
|
|
@@ -5,14 +5,10 @@ import { describeEmptyWorkspace, discoverWorkspaces } from "../discoverWorkspace
|
|
|
5
5
|
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
|
-
import { checkRetiredSyncLabelsConfig } from "./retiredConfig.js";
|
|
9
8
|
import { buildScopeLabels, readSyncLabelsWorkflowTemplate, renderRepoLabelsBlock, renderRepoLabelsConfigScript, } from "./templates.js";
|
|
10
9
|
const WORKFLOW_PATH = '.github/workflows/sync-labels.yaml';
|
|
11
10
|
export async function syncLabelsInitCommand({ configPath, isDryRun, shouldForce, styles, }) {
|
|
12
11
|
const configFilePath = configPath ?? CONFIG_FILE_PATH;
|
|
13
|
-
if (checkRetiredSyncLabelsConfig(configPath)) {
|
|
14
|
-
return 1;
|
|
15
|
-
}
|
|
16
12
|
if (isDryRun) {
|
|
17
13
|
console.info('[dry-run mode]');
|
|
18
14
|
}
|
|
@@ -3,7 +3,6 @@ import { existsSync } from 'node:fs';
|
|
|
3
3
|
import { GIT_OUTPUT_LIMIT_BYTES, reportError } from '@williamthorsen/nmr-core';
|
|
4
4
|
import { describeError } from '@williamthorsen/toolbelt.errors';
|
|
5
5
|
import { BIN } from "../bin.js";
|
|
6
|
-
import { checkRetiredSyncLabelsConfig } from "./retiredConfig.js";
|
|
7
6
|
const WORKFLOW_FILE = '.github/workflows/sync-labels.yaml';
|
|
8
7
|
function checkGhAvailable() {
|
|
9
8
|
try {
|
|
@@ -15,9 +14,6 @@ function checkGhAvailable() {
|
|
|
15
14
|
}
|
|
16
15
|
}
|
|
17
16
|
export function syncLabelsCommand() {
|
|
18
|
-
if (checkRetiredSyncLabelsConfig()) {
|
|
19
|
-
return 1;
|
|
20
|
-
}
|
|
21
17
|
if (!checkGhAvailable()) {
|
|
22
18
|
reportError(BIN, 'The `gh` CLI is not installed or not in PATH. Install it from https://cli.github.com/');
|
|
23
19
|
return 1;
|