@williamthorsen/release-kit 10.9.0 → 11.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.
- package/.meta/changelog.json +57 -0
- package/.readyup/kits/default.js +1 -1
- package/.readyup/kits/npm-auto-publish.js +42 -22
- package/.readyup/manifest.json +5 -5
- package/CHANGELOG.md +48 -0
- package/README.md +37 -18
- package/dist/esm/bin/release-kit.js +30 -22
- package/dist/esm/buildChangelogEntries.js +1 -0
- package/dist/esm/configFlagSchema.d.ts +12 -0
- package/dist/esm/configFlagSchema.js +3 -0
- package/dist/esm/createGithubReleaseCommand.js +6 -2
- package/dist/esm/discoverWorkspaces.d.ts +53 -8
- package/dist/esm/discoverWorkspaces.js +57 -37
- package/dist/esm/help/prepareHelp.d.ts +1 -1
- package/dist/esm/help/prepareHelp.js +1 -0
- package/dist/esm/loadConfig.d.ts +7 -4
- package/dist/esm/loadConfig.js +6 -3
- package/dist/esm/loadValidatedConfig.d.ts +46 -5
- package/dist/esm/loadValidatedConfig.js +32 -15
- package/dist/esm/prepareCommand.d.ts +5 -0
- package/dist/esm/prepareCommand.js +26 -35
- package/dist/esm/previewTagPrefixes.d.ts +9 -6
- package/dist/esm/previewTagPrefixes.js +12 -24
- package/dist/esm/publishCommand.d.ts +2 -2
- package/dist/esm/publishCommand.js +8 -2
- package/dist/esm/pushCommand.d.ts +1 -1
- package/dist/esm/pushCommand.js +2 -2
- package/dist/esm/reportPrepare.js +8 -4
- package/dist/esm/resolveCommandTags.d.ts +3 -2
- package/dist/esm/resolveCommandTags.js +10 -6
- package/dist/esm/resolveReleaseNotesConfig.d.ts +9 -11
- package/dist/esm/resolveReleaseNotesConfig.js +9 -28
- package/dist/esm/showTagPrefixesCommand.d.ts +4 -2
- package/dist/esm/showTagPrefixesCommand.js +17 -3
- package/dist/esm/sync-labels/generateCommand.d.ts +16 -8
- package/dist/esm/sync-labels/generateCommand.js +12 -11
- package/dist/esm/sync-labels/initCommand.d.ts +9 -4
- package/dist/esm/sync-labels/initCommand.js +21 -15
- package/dist/esm/sync-labels/retiredConfig.d.ts +4 -2
- package/dist/esm/sync-labels/retiredConfig.js +2 -2
- package/dist/esm/validateOverridesCommand.d.ts +10 -4
- package/dist/esm/validateOverridesCommand.js +23 -31
- package/docs/configuration.md +12 -0
- package/docs/labels.md +2 -0
- package/package.json +5 -6
package/.meta/changelog.json
CHANGED
|
@@ -1,4 +1,61 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "11.0.0",
|
|
4
|
+
"date": "2026-09-22",
|
|
5
|
+
"sections": [
|
|
6
|
+
{
|
|
7
|
+
"title": "🎉 Features",
|
|
8
|
+
"audience": "all",
|
|
9
|
+
"items": [
|
|
10
|
+
{
|
|
11
|
+
"description": "Return the provenance check's remediation as the outcome's fix (#855)",
|
|
12
|
+
"body": "- Moves the remediation of the `npm-auto-publish` kit's `Provenance setting matches repo visibility` check from the failing outcome's `detail` into its `fix`, so that readyup marks it as a remedy, lists it in the `Fixes` recap, and reports it under `rdy run --json --detail summary` instead of printing it as a plain reason line.\n- Declares `minReadyupVersion: '0.37.0'` on the kit, the readyup release that introduced `CheckOutcome.fix`, which retires the kit's `version-skew` advisory and makes an older runner fail to load the kit.\n\nMigration: Upgrade readyup to 0.37.0 or later before consuming this release of the `npm-auto-publish` kit.",
|
|
13
|
+
"breaking": true,
|
|
14
|
+
"migration": "Upgrade readyup to 0.37.0 or later before consuming this release of the `npm-auto-publish` kit.",
|
|
15
|
+
"hash": "2455edc46611a47e95707f79cdebda539a844431"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"description": "Accept a --config argument on every config-reading subcommand (#857)",
|
|
19
|
+
"body": "- Adds `--config <path>` to `prepare`, `publish`, `create-github-release`, `show-tag-prefixes`, `overrides validate`, `sync-labels init`, and `sync-labels generate`, each of which then reads the named file in place of `.config/release-kit.config.ts`.\n- Requires a named `--config` file to exist, failing if it does not; an absent default path continues to mean that the repo declares no config.\n- Confines scaffolding to the default path: `release-kit init` and `sync-labels init` still write `.config/release-kit.config.ts`, and `sync-labels init --config` reads the named file and fails when it is absent.",
|
|
20
|
+
"hash": "f605a6fd7e48b27b17fb90bad161f4507979e5aa"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"description": "Adopt the shared workspace resolver in release-kit, honoring exclusions (#865)",
|
|
24
|
+
"body": "- 🚨 **Breaking:** Narrows `no-pattern` in `@williamthorsen/nmr-core`'s `EmptyWorkspaceCause`, moving an absent or empty `packages` list onto `no-packages-list` and a value that is not a list of strings onto `unreadable-packages`.\n- Stops `release-kit` from tagging, publishing, and label-syncing a package that a `!` entry in `pnpm-workspace.yaml` excludes, which its previous `glob`-based resolution could not remove from the match.\n- Replaces the release of the root package alone with a failure naming the condition that emptied the workspace, when `pnpm-workspace.yaml` does not hold valid YAML or declares a workspace that does not resolve to a package.\n- Replaces the `no-pattern` remedy that `nmr` printed for a `pnpm-workspace.yaml` declaring no `packages` list, and for one declaring a `packages` value that is not a list of strings.\n- Raises `engines.node` to `>=24.16.0` in `@williamthorsen/nmr-core` and `@williamthorsen/release-kit`, because Node 24.0 through 24.15 ignores the `followSymlinks` option that the workspace matcher passes to `globSync` and drops a symlinked package directory from the resolution without reporting it.\n\nMigration: Add a `no-packages-list` arm and an `unreadable-packages` arm to any `switch` that covers `EmptyWorkspaceCause` exhaustively. `no-pattern` now names only a list that the resolver read in full and whose entries all failed to become a positive pattern, so move the handling of an absent `packages` key, an empty list, and a value that is not a list of strings out of the `no-pattern` arm into the two new ones. Route `no-packages-list` to single-package behavior rather than to a failure path: pnpm resolves such a manifest to the root package alone.",
|
|
25
|
+
"breaking": true,
|
|
26
|
+
"migration": "Add a `no-packages-list` arm and an `unreadable-packages` arm to any `switch` that covers `EmptyWorkspaceCause` exhaustively. `no-pattern` now names only a list that the resolver read in full and whose entries all failed to become a positive pattern, so move the handling of an absent `packages` key, an empty list, and a value that is not a list of strings out of the `no-pattern` arm into the two new ones. Route `no-packages-list` to single-package behavior rather than to a failure path: pnpm resolves such a manifest to the root package alone.",
|
|
27
|
+
"hash": "b1126866159402b8f027a9b82f2a19591a6e9e1b"
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"title": "🐛 Bug fixes",
|
|
33
|
+
"audience": "all",
|
|
34
|
+
"items": [
|
|
35
|
+
{
|
|
36
|
+
"description": "Truncate release-kit commit subjects by display column (#840)",
|
|
37
|
+
"body": "- Fixes the issue that the `release-kit` prepare report cut a commit subject at 69 UTF-16 code units instead of at display columns, so a subject of CJK characters printed about twice the intended 72-column width and a cut inside an emoji left a broken character that a terminal drew as a replacement glyph.\n- Replaces the `...` marker on a truncated subject with `…`, the default of the width-aware truncation that now does the cutting.\n- Exports `truncateToWidth` and `measureWidth` from `@williamthorsen/nmr-core`, which measure and cut text by display width without splitting a grapheme cluster.",
|
|
38
|
+
"hash": "f75d9b4abd9fbda264d5dd40ca5b7abb64f5a3f3"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"description": "Abort show-tag-prefixes on an unusable config (#861)",
|
|
42
|
+
"body": "- Fixes the issue that `release-kit show-tag-prefixes` silently ignored a config file that failed schema validation, which left the preview reading no `legacyIdentities` and no `retiredPackages` and reporting already-declared and retired tag prefixes as undeclared candidates; the command now prints those validation errors and exits 1 with no preview.",
|
|
43
|
+
"hash": "2177873d9a79247385e5a1f09e95971449488d9f"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"description": "Abort every config-reading command on an unusable default config (#869)",
|
|
47
|
+
"body": "- Fixes `publish` proceeding on derived defaults when the default config file exists and fails to load, which silently dropped a configured `releaseNotes.shouldInjectIntoReadme`, `changelogJson.outputPath`, or `workTypes`; it now reports the failure and exits 1, as every other config-reading subcommand does.\n- Fixes `publish` and `create-github-release` ignoring a broken or invalid default config when every requested tag names a private package, a case in which both commands return before any loader runs.",
|
|
48
|
+
"hash": "5b2873f2b9b7e42f1011d90506ca7ea6945d09a1"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"description": "Strip trailing Change trailers from changelog item bodies (#870)",
|
|
52
|
+
"body": "- Fixes a changelog item body that kept a commit's trailing `Change:` trailers, which then appeared verbatim in the rendered release notes, including the notes injected into a README.",
|
|
53
|
+
"hash": "250e52b3a2947202e3a7246fb39ebcb79e2bd1fc"
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
},
|
|
2
59
|
{
|
|
3
60
|
"version": "10.9.0",
|
|
4
61
|
"date": "2026-09-18",
|
package/.readyup/kits/default.js
CHANGED
|
@@ -98,7 +98,7 @@ function translateGlob(pattern) {
|
|
|
98
98
|
|
|
99
99
|
// .readyup/kits/default.ts
|
|
100
100
|
function getMinVersion() {
|
|
101
|
-
const picked = { "version": "
|
|
101
|
+
const picked = { "version": "11.0.0" };
|
|
102
102
|
if (typeof picked["version"] !== "string") {
|
|
103
103
|
throw new TypeError("release-kit/package.json: 'version' must be a string");
|
|
104
104
|
}
|
|
@@ -94,6 +94,9 @@ var packagesChecklist = defineRdyChecklist({
|
|
|
94
94
|
});
|
|
95
95
|
var npm_auto_publish_default = defineRdyKit({
|
|
96
96
|
fixLocation: "inline",
|
|
97
|
+
// The release that introduced `CheckOutcome.fix`, on which the provenance check's remediation depends. An older
|
|
98
|
+
// runner drops that `fix` silently, so failing to load the kit is the lesser harm.
|
|
99
|
+
minReadyupVersion: "0.37.0",
|
|
97
100
|
checklists: [repoChecklist, packagesChecklist]
|
|
98
101
|
});
|
|
99
102
|
function belongsInPackagesChecklist(workspace) {
|
|
@@ -107,8 +110,8 @@ function buildSessionCheck() {
|
|
|
107
110
|
const capability = getCachedTrustCapability();
|
|
108
111
|
return capability.ok ? { ok: true } : { ok: false, detail: capability.detail };
|
|
109
112
|
},
|
|
110
|
-
// A plain string rather than a getter, because
|
|
111
|
-
//
|
|
113
|
+
// A plain string rather than a getter, because the remediation is the same however the session fails; only
|
|
114
|
+
// the `detail` above varies.
|
|
112
115
|
fix: 'Restore a usable npm session: log in with "npm login", supplying the one-time password when prompted, or restore access to the registry, which the trusted-publisher check queries directly'
|
|
113
116
|
};
|
|
114
117
|
}
|
|
@@ -175,29 +178,13 @@ function buildWorkspaceCheck(workspace) {
|
|
|
175
178
|
function checkProvenanceMatchesVisibility() {
|
|
176
179
|
const workflowPath = ".github/workflows/publish.yaml";
|
|
177
180
|
const content = readFile(workflowPath);
|
|
178
|
-
|
|
179
|
-
return { ok: false, detail: `Cannot read ${workflowPath} \u2014 check file permissions` };
|
|
180
|
-
}
|
|
181
|
-
const hasProvenance = parseProvenanceSetting(content);
|
|
182
|
-
let isPrivate;
|
|
181
|
+
let visibility;
|
|
183
182
|
try {
|
|
184
|
-
|
|
183
|
+
visibility = isRepoPrivate() ? "private" : "public";
|
|
185
184
|
} catch {
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
if (!isPrivate && !hasProvenance) {
|
|
189
|
-
return {
|
|
190
|
-
ok: false,
|
|
191
|
-
detail: "Set provenance: true in .github/workflows/publish.yaml \u2014 public repos should generate provenance attestations"
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
if (isPrivate && hasProvenance) {
|
|
195
|
-
return {
|
|
196
|
-
ok: false,
|
|
197
|
-
detail: "Make the GitHub repo public \u2014 OIDC publishing with provenance requires a public repo"
|
|
198
|
-
};
|
|
185
|
+
visibility = "unknown";
|
|
199
186
|
}
|
|
200
|
-
return
|
|
187
|
+
return classifyProvenanceSetting(content, visibility);
|
|
201
188
|
}
|
|
202
189
|
function checkTrustedPublisher(packageName) {
|
|
203
190
|
const result = getTrustQueryResult(packageName);
|
|
@@ -226,6 +213,38 @@ function classifyNpmAuth(result) {
|
|
|
226
213
|
}
|
|
227
214
|
return { status: "unreachable", detail: `The npm registry query failed (${error.code}): ${error.summary}` };
|
|
228
215
|
}
|
|
216
|
+
function classifyProvenanceSetting(workflowContent, visibility) {
|
|
217
|
+
if (workflowContent === void 0) {
|
|
218
|
+
return {
|
|
219
|
+
ok: false,
|
|
220
|
+
detail: "Cannot read .github/workflows/publish.yaml",
|
|
221
|
+
fix: "Check the file's permissions"
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
if (visibility === "unknown") {
|
|
225
|
+
return {
|
|
226
|
+
ok: false,
|
|
227
|
+
detail: "The GitHub CLI could not report the repo's visibility",
|
|
228
|
+
fix: "Install and authenticate the GitHub CLI: gh auth login"
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const hasProvenance = parseProvenanceSetting(workflowContent);
|
|
232
|
+
if (visibility === "public" && !hasProvenance) {
|
|
233
|
+
return {
|
|
234
|
+
ok: false,
|
|
235
|
+
detail: "The repo is public and publish.yaml does not set provenance: true",
|
|
236
|
+
fix: "Set provenance: true in .github/workflows/publish.yaml \u2014 public repos should generate provenance attestations"
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
if (visibility === "private" && hasProvenance) {
|
|
240
|
+
return {
|
|
241
|
+
ok: false,
|
|
242
|
+
detail: "The repo is private and publish.yaml sets provenance: true",
|
|
243
|
+
fix: "Make the GitHub repo public \u2014 OIDC publishing with provenance requires a public repo"
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
return { ok: true };
|
|
247
|
+
}
|
|
229
248
|
function classifyTrustCapability(auth, probe) {
|
|
230
249
|
if (auth.status !== "authenticated") {
|
|
231
250
|
return { ok: false, detail: auth.detail };
|
|
@@ -409,6 +428,7 @@ function skipIfNotPublishable(workspace) {
|
|
|
409
428
|
export {
|
|
410
429
|
buildWorkspaceCheck,
|
|
411
430
|
classifyNpmAuth,
|
|
431
|
+
classifyProvenanceSetting,
|
|
412
432
|
classifyTrustCapability,
|
|
413
433
|
classifyTrustQuery,
|
|
414
434
|
npm_auto_publish_default as default,
|
package/.readyup/manifest.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"path": "kits/default.ts"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
|
-
"hash": "
|
|
16
|
+
"hash": "e9aadbb2",
|
|
17
17
|
"kind": "inline",
|
|
18
18
|
"path": "../package.json",
|
|
19
19
|
"paths": [
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"readyupVersion": "0.38.0",
|
|
47
47
|
"source": "kits/default.ts",
|
|
48
48
|
"sourceHash": "a20ce64b",
|
|
49
|
-
"targetHash": "
|
|
49
|
+
"targetHash": "b3fd135a"
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
"checklists": [
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"esbuildVersion": "0.28.2",
|
|
57
57
|
"inputs": [
|
|
58
58
|
{
|
|
59
|
-
"hash": "
|
|
59
|
+
"hash": "c2d2d375",
|
|
60
60
|
"kind": "module",
|
|
61
61
|
"path": "kits/npm-auto-publish.ts"
|
|
62
62
|
}
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
"path": "kits/npm-auto-publish.js",
|
|
66
66
|
"readyupVersion": "0.38.0",
|
|
67
67
|
"source": "kits/npm-auto-publish.ts",
|
|
68
|
-
"sourceHash": "
|
|
69
|
-
"targetHash": "
|
|
68
|
+
"sourceHash": "c2d2d375",
|
|
69
|
+
"targetHash": "9d2d224b"
|
|
70
70
|
}
|
|
71
71
|
]
|
|
72
72
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,54 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 11.0.0 — 2026-09-22
|
|
6
|
+
|
|
7
|
+
### 🎉 Features
|
|
8
|
+
|
|
9
|
+
- 🚨 **Breaking:** Return the provenance check's remediation as the outcome's fix (#855)
|
|
10
|
+
|
|
11
|
+
- Moves the remediation of the `npm-auto-publish` kit's `Provenance setting matches repo visibility` check from the failing outcome's `detail` into its `fix`, so that readyup marks it as a remedy, lists it in the `Fixes` recap, and reports it under `rdy run --json --detail summary` instead of printing it as a plain reason line.
|
|
12
|
+
- Declares `minReadyupVersion: '0.37.0'` on the kit, the readyup release that introduced `CheckOutcome.fix`, which retires the kit's `version-skew` advisory and makes an older runner fail to load the kit.
|
|
13
|
+
|
|
14
|
+
Migration: Upgrade readyup to 0.37.0 or later before consuming this release of the `npm-auto-publish` kit.
|
|
15
|
+
|
|
16
|
+
- Accept a --config argument on every config-reading subcommand (#857)
|
|
17
|
+
|
|
18
|
+
- Adds `--config <path>` to `prepare`, `publish`, `create-github-release`, `show-tag-prefixes`, `overrides validate`, `sync-labels init`, and `sync-labels generate`, each of which then reads the named file in place of `.config/release-kit.config.ts`.
|
|
19
|
+
- Requires a named `--config` file to exist, failing if it does not; an absent default path continues to mean that the repo declares no config.
|
|
20
|
+
- Confines scaffolding to the default path: `release-kit init` and `sync-labels init` still write `.config/release-kit.config.ts`, and `sync-labels init --config` reads the named file and fails when it is absent.
|
|
21
|
+
|
|
22
|
+
- 🚨 **Breaking:** Adopt the shared workspace resolver in release-kit, honoring exclusions (#865)
|
|
23
|
+
|
|
24
|
+
- 🚨 **Breaking:** Narrows `no-pattern` in `@williamthorsen/nmr-core`'s `EmptyWorkspaceCause`, moving an absent or empty `packages` list onto `no-packages-list` and a value that is not a list of strings onto `unreadable-packages`.
|
|
25
|
+
- Stops `release-kit` from tagging, publishing, and label-syncing a package that a `!` entry in `pnpm-workspace.yaml` excludes, which its previous `glob`-based resolution could not remove from the match.
|
|
26
|
+
- Replaces the release of the root package alone with a failure naming the condition that emptied the workspace, when `pnpm-workspace.yaml` does not hold valid YAML or declares a workspace that does not resolve to a package.
|
|
27
|
+
- Replaces the `no-pattern` remedy that `nmr` printed for a `pnpm-workspace.yaml` declaring no `packages` list, and for one declaring a `packages` value that is not a list of strings.
|
|
28
|
+
- Raises `engines.node` to `>=24.16.0` in `@williamthorsen/nmr-core` and `@williamthorsen/release-kit`, because Node 24.0 through 24.15 ignores the `followSymlinks` option that the workspace matcher passes to `globSync` and drops a symlinked package directory from the resolution without reporting it.
|
|
29
|
+
|
|
30
|
+
Migration: Add a `no-packages-list` arm and an `unreadable-packages` arm to any `switch` that covers `EmptyWorkspaceCause` exhaustively. `no-pattern` now names only a list that the resolver read in full and whose entries all failed to become a positive pattern, so move the handling of an absent `packages` key, an empty list, and a value that is not a list of strings out of the `no-pattern` arm into the two new ones. Route `no-packages-list` to single-package behavior rather than to a failure path: pnpm resolves such a manifest to the root package alone.
|
|
31
|
+
|
|
32
|
+
### 🐛 Bug fixes
|
|
33
|
+
|
|
34
|
+
- Truncate release-kit commit subjects by display column (#840)
|
|
35
|
+
|
|
36
|
+
- Fixes the issue that the `release-kit` prepare report cut a commit subject at 69 UTF-16 code units instead of at display columns, so a subject of CJK characters printed about twice the intended 72-column width and a cut inside an emoji left a broken character that a terminal drew as a replacement glyph.
|
|
37
|
+
- Replaces the `...` marker on a truncated subject with `…`, the default of the width-aware truncation that now does the cutting.
|
|
38
|
+
- Exports `truncateToWidth` and `measureWidth` from `@williamthorsen/nmr-core`, which measure and cut text by display width without splitting a grapheme cluster.
|
|
39
|
+
|
|
40
|
+
- Abort show-tag-prefixes on an unusable config (#861)
|
|
41
|
+
|
|
42
|
+
- Fixes the issue that `release-kit show-tag-prefixes` silently ignored a config file that failed schema validation, which left the preview reading no `legacyIdentities` and no `retiredPackages` and reporting already-declared and retired tag prefixes as undeclared candidates; the command now prints those validation errors and exits 1 with no preview.
|
|
43
|
+
|
|
44
|
+
- Abort every config-reading command on an unusable default config (#869)
|
|
45
|
+
|
|
46
|
+
- Fixes `publish` proceeding on derived defaults when the default config file exists and fails to load, which silently dropped a configured `releaseNotes.shouldInjectIntoReadme`, `changelogJson.outputPath`, or `workTypes`; it now reports the failure and exits 1, as every other config-reading subcommand does.
|
|
47
|
+
- Fixes `publish` and `create-github-release` ignoring a broken or invalid default config when every requested tag names a private package, a case in which both commands return before any loader runs.
|
|
48
|
+
|
|
49
|
+
- Strip trailing Change trailers from changelog item bodies (#870)
|
|
50
|
+
|
|
51
|
+
- Fixes a changelog item body that kept a commit's trailing `Change:` trailers, which then appeared verbatim in the rendered release notes, including the notes injected into a README.
|
|
52
|
+
|
|
5
53
|
## 10.9.0 — 2026-09-18
|
|
6
54
|
|
|
7
55
|
### 🎉 Features
|
package/README.md
CHANGED
|
@@ -7,36 +7,53 @@ Version-bumping and changelog-generation toolkit for release workflows.
|
|
|
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 `git-cliff --context` output rendered in-process (with optional [editorial overrides](docs/editorial-overrides.md)).
|
|
8
8
|
|
|
9
9
|
<!-- section:release-notes -->
|
|
10
|
-
## Release notes —
|
|
10
|
+
## Release notes — v11.0.0 (2026-09-22)
|
|
11
11
|
|
|
12
12
|
### 🎉 Features
|
|
13
13
|
|
|
14
|
-
-
|
|
14
|
+
- 🚨 **Breaking:** Return the provenance check's remediation as the outcome's fix (#855)
|
|
15
15
|
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- Adds a required `style` parameter to `formatValidateOverridesResult`, which the package root exports.
|
|
16
|
+
- Moves the remediation of the `npm-auto-publish` kit's `Provenance setting matches repo visibility` check from the failing outcome's `detail` into its `fix`, so that readyup marks it as a remedy, lists it in the `Fixes` recap, and reports it under `rdy run --json --detail summary` instead of printing it as a plain reason line.
|
|
17
|
+
- Declares `minReadyupVersion: '0.37.0'` on the kit, the readyup release that introduced `CheckOutcome.fix`, which retires the kit's `version-skew` advisory and makes an older runner fail to load the kit.
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
Migration: Upgrade readyup to 0.37.0 or later before consuming this release of the `npm-auto-publish` kit.
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
21
|
+
- Accept a --config argument on every config-reading subcommand (#857)
|
|
22
|
+
|
|
23
|
+
- Adds `--config <path>` to `prepare`, `publish`, `create-github-release`, `show-tag-prefixes`, `overrides validate`, `sync-labels init`, and `sync-labels generate`, each of which then reads the named file in place of `.config/release-kit.config.ts`.
|
|
24
|
+
- Requires a named `--config` file to exist, failing if it does not; an absent default path continues to mean that the repo declares no config.
|
|
25
|
+
- Confines scaffolding to the default path: `release-kit init` and `sync-labels init` still write `.config/release-kit.config.ts`, and `sync-labels init --config` reads the named file and fails when it is absent.
|
|
26
|
+
|
|
27
|
+
- 🚨 **Breaking:** Adopt the shared workspace resolver in release-kit, honoring exclusions (#865)
|
|
28
|
+
|
|
29
|
+
- 🚨 **Breaking:** Narrows `no-pattern` in `@williamthorsen/nmr-core`'s `EmptyWorkspaceCause`, moving an absent or empty `packages` list onto `no-packages-list` and a value that is not a list of strings onto `unreadable-packages`.
|
|
30
|
+
- Stops `release-kit` from tagging, publishing, and label-syncing a package that a `!` entry in `pnpm-workspace.yaml` excludes, which its previous `glob`-based resolution could not remove from the match.
|
|
31
|
+
- Replaces the release of the root package alone with a failure naming the condition that emptied the workspace, when `pnpm-workspace.yaml` does not hold valid YAML or declares a workspace that does not resolve to a package.
|
|
32
|
+
- Replaces the `no-pattern` remedy that `nmr` printed for a `pnpm-workspace.yaml` declaring no `packages` list, and for one declaring a `packages` value that is not a list of strings.
|
|
33
|
+
- Raises `engines.node` to `>=24.16.0` in `@williamthorsen/nmr-core` and `@williamthorsen/release-kit`, because Node 24.0 through 24.15 ignores the `followSymlinks` option that the workspace matcher passes to `globSync` and drops a symlinked package directory from the resolution without reporting it.
|
|
34
|
+
|
|
35
|
+
Migration: Add a `no-packages-list` arm and an `unreadable-packages` arm to any `switch` that covers `EmptyWorkspaceCause` exhaustively. `no-pattern` now names only a list that the resolver read in full and whose entries all failed to become a positive pattern, so move the handling of an absent `packages` key, an empty list, and a value that is not a list of strings out of the `no-pattern` arm into the two new ones. Route `no-packages-list` to single-package behavior rather than to a failure path: pnpm resolves such a manifest to the root package alone.
|
|
25
36
|
|
|
26
37
|
### 🐛 Bug fixes
|
|
27
38
|
|
|
28
|
-
-
|
|
39
|
+
- Truncate release-kit commit subjects by display column (#840)
|
|
29
40
|
|
|
30
|
-
-
|
|
41
|
+
- Fixes the issue that the `release-kit` prepare report cut a commit subject at 69 UTF-16 code units instead of at display columns, so a subject of CJK characters printed about twice the intended 72-column width and a cut inside an emoji left a broken character that a terminal drew as a replacement glyph.
|
|
42
|
+
- Replaces the `...` marker on a truncated subject with `…`, the default of the width-aware truncation that now does the cutting.
|
|
43
|
+
- Exports `truncateToWidth` and `measureWidth` from `@williamthorsen/nmr-core`, which measure and cut text by display width without splitting a grapheme cluster.
|
|
31
44
|
|
|
32
|
-
-
|
|
45
|
+
- Abort show-tag-prefixes on an unusable config (#861)
|
|
33
46
|
|
|
34
|
-
-
|
|
47
|
+
- Fixes the issue that `release-kit show-tag-prefixes` silently ignored a config file that failed schema validation, which left the preview reading no `legacyIdentities` and no `retiredPackages` and reporting already-declared and retired tag prefixes as undeclared candidates; the command now prints those validation errors and exits 1 with no preview.
|
|
35
48
|
|
|
36
|
-
-
|
|
49
|
+
- Abort every config-reading command on an unusable default config (#869)
|
|
37
50
|
|
|
38
|
-
-
|
|
39
|
-
-
|
|
51
|
+
- Fixes `publish` proceeding on derived defaults when the default config file exists and fails to load, which silently dropped a configured `releaseNotes.shouldInjectIntoReadme`, `changelogJson.outputPath`, or `workTypes`; it now reports the failure and exits 1, as every other config-reading subcommand does.
|
|
52
|
+
- Fixes `publish` and `create-github-release` ignoring a broken or invalid default config when every requested tag names a private package, a case in which both commands return before any loader runs.
|
|
53
|
+
|
|
54
|
+
- Strip trailing Change trailers from changelog item bodies (#870)
|
|
55
|
+
|
|
56
|
+
- Fixes a changelog item body that kept a commit's trailing `Change:` trailers, which then appeared verbatim in the rendered release notes, including the notes injected into a README.
|
|
40
57
|
<!-- /section:release-notes -->
|
|
41
58
|
|
|
42
59
|
## Installation
|
|
@@ -89,8 +106,8 @@ The CLI applies defaults to every discovered workspace and uses the bundled `cli
|
|
|
89
106
|
|
|
90
107
|
## How it works
|
|
91
108
|
|
|
92
|
-
1. **Workspace discovery**: reads `pnpm-workspace.yaml` and resolves its `packages`
|
|
93
|
-
2. **Config loading**: loads `.config/release-kit.config.ts` (if present) and merges it with discovered defaults.
|
|
109
|
+
1. **Workspace discovery**: reads `pnpm-workspace.yaml` and resolves its `packages` patterns to find workspace directories, applying pnpm's semantics — a `!`-prefixed entry excludes what it matches, wherever it appears in the list. Each directory containing a `package.json` becomes a workspace. The repo is treated as a single-package project when it holds no workspace file, and when the workspace file declares no `packages` list — a file kept for `catalog:` or `overrides:` alone, which pnpm likewise resolves to the root package. A workspace file that declares patterns resolving to no package is an error naming the condition that emptied it.
|
|
110
|
+
2. **Config loading**: loads `.config/release-kit.config.ts` (if present), or the file named by `--config`, and merges it with discovered defaults.
|
|
94
111
|
3. **Commit analysis**: for each workspace, finds commits since the last version tag, parses them for type and scope, and determines the appropriate version bump.
|
|
95
112
|
4. **Version bump + changelog**: bumps `package.json` versions, builds structured `ChangelogEntry[]` from `git-cliff --context`, applies any [editorial overrides](docs/editorial-overrides.md) from per-scope `.meta/changelog-overrides.json` files, and renders both `CHANGELOG.md` and `.meta/changelog.json` from that single source. `git-cliff` is invoked only for its `--context` JSON; markdown rendering happens in-process so `.meta/changelog.json` and `CHANGELOG.md` always agree.
|
|
96
113
|
5. **Release tags file**: writes computed tags to `tmp/.release-tags` for the release workflow to read when tagging and pushing.
|
|
@@ -118,6 +135,8 @@ The `scope|type:` format scopes a commit to a specific workspace in a monorepo.
|
|
|
118
135
|
|
|
119
136
|
Configuration is optional. The CLI works out of the box by auto-discovering workspaces and applying defaults. Create `.config/release-kit.config.ts` only when you need to customize behavior.
|
|
120
137
|
|
|
138
|
+
Every subcommand that reads a config accepts `--config <path>` to read a file elsewhere. An absent default path means "no config"; an absent `--config` path fails the command. See [Config file location](docs/configuration.md#config-file-location).
|
|
139
|
+
|
|
121
140
|
```typescript
|
|
122
141
|
import { defineConfig } from '@williamthorsen/release-kit/config';
|
|
123
142
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { parseArgsOrExit, readPackageVersion, reportError } from '@williamthorsen/nmr-core';
|
|
3
3
|
import { describeError } from '@williamthorsen/toolbelt.errors';
|
|
4
4
|
import { commitCommand } from "../commitCommand.js";
|
|
5
|
+
import { configFlagSchema } from "../configFlagSchema.js";
|
|
5
6
|
import { createGithubReleaseCommand } from "../createGithubReleaseCommand.js";
|
|
6
7
|
import { showPrepareHelp } from "../help/prepareHelp.js";
|
|
7
8
|
import { initCommand } from "../init/initCommand.js";
|
|
@@ -68,9 +69,10 @@ retired packages, then generate .github/labels.yaml. When the config file alread
|
|
|
68
69
|
exists, print the block for manual paste instead of rewriting the file.
|
|
69
70
|
|
|
70
71
|
Options:
|
|
71
|
-
--
|
|
72
|
-
--
|
|
73
|
-
--
|
|
72
|
+
--config <path> Path to config file (default: .config/release-kit.config.ts)
|
|
73
|
+
--dry-run Preview changes without writing files
|
|
74
|
+
--force Overwrite existing files instead of skipping them
|
|
75
|
+
--help, -h Show this help message
|
|
74
76
|
`);
|
|
75
77
|
}
|
|
76
78
|
function showSyncLabelsGenerateHelp() {
|
|
@@ -80,8 +82,9 @@ Usage: release-kit sync-labels generate [options]
|
|
|
80
82
|
Regenerate .github/labels.yaml from the repoLabels block of .config/release-kit.config.ts.
|
|
81
83
|
|
|
82
84
|
Options:
|
|
83
|
-
--check
|
|
84
|
-
--
|
|
85
|
+
--check Report whether .github/labels.yaml is stale instead of writing it
|
|
86
|
+
--config <path> Path to config file (default: .config/release-kit.config.ts)
|
|
87
|
+
--help, -h Show this help message
|
|
85
88
|
`);
|
|
86
89
|
}
|
|
87
90
|
function showSyncLabelsSyncHelp() {
|
|
@@ -154,6 +157,7 @@ Create GitHub Releases from changelog.json for tags on HEAD. Private
|
|
|
154
157
|
(package.json#private) workspaces are skipped with a warning and get no Release.
|
|
155
158
|
|
|
156
159
|
Options:
|
|
160
|
+
--config <path> Path to config file (default: .config/release-kit.config.ts)
|
|
157
161
|
--dry-run Preview without creating releases
|
|
158
162
|
--tags=tag1,tag2 Only create releases for the named tags (comma-separated, full tag names)
|
|
159
163
|
--help, -h Show this help message
|
|
@@ -169,7 +173,8 @@ derived prefix nor declared in \`legacyIdentities\`, with a copy-pasteable
|
|
|
169
173
|
config snippet.
|
|
170
174
|
|
|
171
175
|
Options:
|
|
172
|
-
--
|
|
176
|
+
--config <path> Path to config file (default: .config/release-kit.config.ts)
|
|
177
|
+
--help, -h Show this help message
|
|
173
178
|
`);
|
|
174
179
|
}
|
|
175
180
|
function showOverridesHelp() {
|
|
@@ -198,7 +203,8 @@ Exit codes:
|
|
|
198
203
|
2 Schema/parse or ambiguous-prefix errors (errors dominate)
|
|
199
204
|
|
|
200
205
|
Options:
|
|
201
|
-
--
|
|
206
|
+
--config <path> Path to config file (default: .config/release-kit.config.ts)
|
|
207
|
+
--help, -h Show this help message
|
|
202
208
|
`);
|
|
203
209
|
}
|
|
204
210
|
function showPublishHelp() {
|
|
@@ -211,6 +217,7 @@ silently filtered out. With --tags, an unpublishable tag is skipped with a warni
|
|
|
211
217
|
any publishable tags still publish.
|
|
212
218
|
|
|
213
219
|
Options:
|
|
220
|
+
--config <path> Path to config file (default: .config/release-kit.config.ts)
|
|
214
221
|
--dry-run Preview without publishing
|
|
215
222
|
--no-git-checks Skip the clean-working-tree check
|
|
216
223
|
--tags=tag1,tag2 Only publish the named tags (comma-separated, full tag names)
|
|
@@ -269,7 +276,7 @@ if (command === 'push') {
|
|
|
269
276
|
showPushHelp();
|
|
270
277
|
process.exit(0);
|
|
271
278
|
}
|
|
272
|
-
|
|
279
|
+
pushCommand(flags);
|
|
273
280
|
process.exit(0);
|
|
274
281
|
}
|
|
275
282
|
if (command === 'create-github-release') {
|
|
@@ -293,11 +300,8 @@ if (command === 'show-tag-prefixes') {
|
|
|
293
300
|
showShowTagPrefixesHelp();
|
|
294
301
|
process.exit(0);
|
|
295
302
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
process.exit(1);
|
|
299
|
-
}
|
|
300
|
-
const exitCode = await showTagPrefixesCommand(styles);
|
|
303
|
+
const { config } = parseArgsOrExit(flags, configFlagSchema).flags;
|
|
304
|
+
const exitCode = await showTagPrefixesCommand(styles, config);
|
|
301
305
|
process.exit(exitCode);
|
|
302
306
|
}
|
|
303
307
|
if (command === 'init') {
|
|
@@ -327,11 +331,17 @@ if (command === 'sync-labels') {
|
|
|
327
331
|
process.exit(0);
|
|
328
332
|
}
|
|
329
333
|
const syncLabelsInitFlagSchema = {
|
|
334
|
+
...configFlagSchema,
|
|
330
335
|
dryRun: { long: '--dry-run', type: 'boolean' },
|
|
331
336
|
force: { long: '--force', type: 'boolean' },
|
|
332
337
|
};
|
|
333
|
-
const { dryRun, force } = parseArgsOrExit(subflags, syncLabelsInitFlagSchema).flags;
|
|
334
|
-
const exitCode = await syncLabelsInitCommand({
|
|
338
|
+
const { config, dryRun, force } = parseArgsOrExit(subflags, syncLabelsInitFlagSchema).flags;
|
|
339
|
+
const exitCode = await syncLabelsInitCommand({
|
|
340
|
+
...(config !== undefined && { configPath: config }),
|
|
341
|
+
dryRun,
|
|
342
|
+
force,
|
|
343
|
+
styles,
|
|
344
|
+
});
|
|
335
345
|
process.exit(exitCode);
|
|
336
346
|
}
|
|
337
347
|
if (subcommand === 'generate') {
|
|
@@ -340,10 +350,11 @@ if (command === 'sync-labels') {
|
|
|
340
350
|
process.exit(0);
|
|
341
351
|
}
|
|
342
352
|
const generateFlagSchema = {
|
|
353
|
+
...configFlagSchema,
|
|
343
354
|
check: { long: '--check', type: 'boolean' },
|
|
344
355
|
};
|
|
345
|
-
const { check } = parseArgsOrExit(subflags, generateFlagSchema).flags;
|
|
346
|
-
const exitCode = await generateCommand({ check, styles });
|
|
356
|
+
const { check, config } = parseArgsOrExit(subflags, generateFlagSchema).flags;
|
|
357
|
+
const exitCode = await generateCommand({ check, ...(config !== undefined && { configPath: config }), styles });
|
|
347
358
|
process.exit(exitCode);
|
|
348
359
|
}
|
|
349
360
|
if (subcommand === 'sync') {
|
|
@@ -374,11 +385,8 @@ if (command === 'overrides') {
|
|
|
374
385
|
showOverridesValidateHelp();
|
|
375
386
|
process.exit(0);
|
|
376
387
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
process.exit(1);
|
|
380
|
-
}
|
|
381
|
-
const result = await validateOverridesCommand(styles);
|
|
388
|
+
const { config } = parseArgsOrExit(subflags, configFlagSchema).flags;
|
|
389
|
+
const result = await validateOverridesCommand(styles, config);
|
|
382
390
|
if (result.exitCode === 0) {
|
|
383
391
|
console.info(result.message);
|
|
384
392
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `--config` flag, shared by every subcommand that reads the config file.
|
|
3
|
+
*
|
|
4
|
+
* Spread into a subcommand's own schema rather than repeated, so that seven subcommands cannot drift to seven
|
|
5
|
+
* spellings of one flag.
|
|
6
|
+
*/
|
|
7
|
+
export declare const configFlagSchema: {
|
|
8
|
+
config: {
|
|
9
|
+
long: string;
|
|
10
|
+
type: "string";
|
|
11
|
+
};
|
|
12
|
+
};
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import { parseArgsOrExit, reportError } from '@williamthorsen/nmr-core';
|
|
2
2
|
import { describeError } from '@williamthorsen/toolbelt.errors';
|
|
3
|
+
import { configFlagSchema } from "./configFlagSchema.js";
|
|
3
4
|
import { createGithubReleases } from "./createGithubRelease.js";
|
|
4
5
|
import { formatPrivateSkip } from "./formatPrivateSkip.js";
|
|
6
|
+
import { assertConfigUsable } from "./loadValidatedConfig.js";
|
|
5
7
|
import { parseRequestedTags } from "./parseRequestedTags.js";
|
|
6
8
|
import { resolveCommandTags } from "./resolveCommandTags.js";
|
|
7
9
|
import { resolveReleaseNotesConfig } from "./resolveReleaseNotesConfig.js";
|
|
8
10
|
const createGithubReleaseFlagSchema = {
|
|
11
|
+
...configFlagSchema,
|
|
9
12
|
dryRun: { long: '--dry-run', type: 'boolean' },
|
|
10
13
|
tags: { long: '--tags', type: 'string' },
|
|
11
14
|
};
|
|
12
15
|
export async function createGithubReleaseCommand(argv, styles) {
|
|
13
16
|
const parsed = parseArgsOrExit(argv, createGithubReleaseFlagSchema);
|
|
14
17
|
const { dryRun } = parsed.flags;
|
|
18
|
+
await assertConfigUsable(styles.stderr, parsed.flags.config);
|
|
15
19
|
const requestedTags = parseRequestedTags(parsed.flags.tags);
|
|
16
|
-
const resolvedTags =
|
|
20
|
+
const resolvedTags = resolveCommandTags(requestedTags);
|
|
17
21
|
const publishableTags = resolvedTags.filter((resolvedTag) => resolvedTag.isPublishable);
|
|
18
22
|
for (const resolvedTag of resolvedTags) {
|
|
19
23
|
if (!resolvedTag.isPublishable) {
|
|
@@ -24,7 +28,7 @@ export async function createGithubReleaseCommand(argv, styles) {
|
|
|
24
28
|
return;
|
|
25
29
|
}
|
|
26
30
|
const { changelogJsonOutputPath, sectionOrder } = await resolveReleaseNotesConfig(styles.stderr, {
|
|
27
|
-
|
|
31
|
+
...(parsed.flags.config !== undefined && { configPath: parsed.flags.config }),
|
|
28
32
|
});
|
|
29
33
|
let outcome;
|
|
30
34
|
try {
|