@williamthorsen/release-kit 13.1.0 → 14.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.
- package/.meta/changelog.json +118 -9
- package/.readyup/kits/default.js +4 -4
- package/.readyup/kits/npm-auto-publish.js +81 -41
- package/.readyup/manifest.json +19 -9
- package/CHANGELOG.md +38 -6
- package/README.md +14 -6
- package/dist/esm/assertReleasesOnNpm.d.ts +7 -0
- package/dist/esm/assertReleasesOnNpm.js +56 -0
- package/dist/esm/bin/release-kit.js +5 -2
- package/dist/esm/deriveWorkspaceConfig.js +2 -2
- package/dist/esm/enumerateReleaseWindows.d.ts +1 -1
- package/dist/esm/enumerateReleaseWindows.js +1 -3
- package/dist/esm/findTransitiveDependents.d.ts +3 -0
- package/dist/esm/findTransitiveDependents.js +20 -0
- package/dist/esm/help/prepareHelp.d.ts +1 -1
- package/dist/esm/help/prepareHelp.js +4 -2
- package/dist/esm/init/hasPublishablePackage.d.ts +10 -0
- package/dist/esm/init/hasPublishablePackage.js +28 -0
- package/dist/esm/init/initCommand.js +23 -13
- package/dist/esm/init/scaffold.d.ts +6 -1
- package/dist/esm/init/scaffold.js +10 -7
- package/dist/esm/init/templates.js +1 -1
- package/dist/esm/init/updateTemplatesCommand.d.ts +2 -1
- package/dist/esm/init/updateTemplatesCommand.js +12 -6
- package/dist/esm/isPublishableManifest.d.ts +2 -0
- package/dist/esm/isPublishableManifest.js +5 -0
- package/dist/esm/matchesTagPrefix.d.ts +2 -0
- package/dist/esm/matchesTagPrefix.js +4 -0
- package/dist/esm/npmRegistry.d.ts +35 -0
- package/dist/esm/npmRegistry.js +58 -0
- package/dist/esm/prepareCommand.d.ts +1 -0
- package/dist/esm/prepareCommand.js +52 -61
- package/dist/esm/previewTagPrefixes.js +2 -1
- package/dist/esm/releasePrepare.d.ts +2 -16
- package/dist/esm/releasePrepareMono.d.ts +17 -2
- package/dist/esm/releasePrepareMono.js +23 -11
- package/dist/esm/sync-labels/templates.js +1 -1
- package/docs/configuration.md +1 -1
- package/docs/labels.md +5 -3
- package/docs/project-releases.md +2 -2
- package/docs/readiness-checks.md +2 -2
- package/docs/releasing.md +20 -10
- package/package.json +8 -8
- package/dist/esm/validateOnlyExcludesStrandedDependents.d.ts +0 -37
- package/dist/esm/validateOnlyExcludesStrandedDependents.js +0 -115
package/.meta/changelog.json
CHANGED
|
@@ -1,4 +1,106 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "14.1.0",
|
|
4
|
+
"date": "2026-10-11",
|
|
5
|
+
"sections": [
|
|
6
|
+
{
|
|
7
|
+
"title": "🎉 Features",
|
|
8
|
+
"audience": "all",
|
|
9
|
+
"items": [
|
|
10
|
+
{
|
|
11
|
+
"description": "Stops `release-kit init` from scaffolding `publish.yaml` and `create-github-release.yaml` when every package is private, even with `--force`, and removes the provenance and trusted-publisher steps from the next steps that it prints. (#995)",
|
|
12
|
+
"hash": "93355490219535fac282ab2256179094ca920e47",
|
|
13
|
+
"entry": 1
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"description": "Stops `release-kit update-templates` from re-creating a deleted `publish.yaml` or `create-github-release.yaml` when every package is private, while it still refreshes either workflow that exists. (#995)",
|
|
17
|
+
"hash": "93355490219535fac282ab2256179094ca920e47",
|
|
18
|
+
"entry": 2
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"description": "Makes `release-kit prepare` refuse, before it writes any file and in a dry run too, to release a publishable package that npm does not list or that it cannot look up, and prints `npm publish --access public` as the fix for each unlisted package. (#996)",
|
|
22
|
+
"hash": "7b8b6d67b264af56dff761d0bf987eca8bc2f934",
|
|
23
|
+
"entry": 1
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"title": "🐛 Bug fixes",
|
|
29
|
+
"audience": "all",
|
|
30
|
+
"items": [
|
|
31
|
+
{
|
|
32
|
+
"description": "Fixes the issue that the `npm-auto-publish` kit's \"published to npm\" check reported a failed lookup, such as an unreachable registry or an authentication error, as an unpublished package and ignored `publishConfig.registry`. (#996)",
|
|
33
|
+
"hash": "7b8b6d67b264af56dff761d0bf987eca8bc2f934",
|
|
34
|
+
"entry": 2
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"description": "Fixes the issue that release-kit's changelog generation treated a floating major tag such as `v1` as a release and added a spurious release to the history, by counting a tag only when the rest of its name after the prefix is a complete SemVer version such as `1.0.0` or `1.0.0-beta.1`. (#1000)",
|
|
38
|
+
"hash": "712e7500109b4bb3db579b60c72e4bf85b308098",
|
|
39
|
+
"entry": 1
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"description": "Fixes the issue that `release-kit show-tag-prefixes` counted every tag that starts with a workspace's prefix, including floating pointers such as `core-v1` and non-release tags such as `core-vnext`, rather than only the tags that release-kit counts as releases. (#1000)",
|
|
43
|
+
"hash": "712e7500109b4bb3db579b60c72e4bf85b308098",
|
|
44
|
+
"entry": 2
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"version": "14.0.0",
|
|
52
|
+
"date": "2026-10-08",
|
|
53
|
+
"sections": [
|
|
54
|
+
{
|
|
55
|
+
"title": "🎉 Features",
|
|
56
|
+
"audience": "all",
|
|
57
|
+
"items": [
|
|
58
|
+
{
|
|
59
|
+
"description": "Changes monorepo `--set-version` to take comma-separated `<workspace>@N.N.N` entries, which `prepare` accepts without `--only` and together with `--bump` and `--force`, and which release each named workspace's dependents. (#970)",
|
|
60
|
+
"breaking": true,
|
|
61
|
+
"migration": "Replace `--only arrays --set-version 1.0.0` with `--set-version arrays@1.0.0 --only arrays`, and keep `--only` unless the release should cover every workspace, because a `--set-version` run without `--only` is a full run.",
|
|
62
|
+
"hash": "07e3e99cb03e6031619bd58dac6ee339ceac0e89",
|
|
63
|
+
"entry": 2
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"title": "🐛 Bug fixes",
|
|
69
|
+
"audience": "all",
|
|
70
|
+
"items": [
|
|
71
|
+
{
|
|
72
|
+
"description": "Fixes the issue that `release-kit prepare --only` left each dependent of the named workspaces published against the old version range of its dependency, by also releasing every transitive dependent: a dependent with commits of its own at its own bump, and one without at a propagated patch bump. (#970)",
|
|
73
|
+
"breaking": true,
|
|
74
|
+
"migration": "Expect each `--only` run to release the dependents of the named workspaces as well, and remove any dependents that were added to `--only` only to get past the stranded-dependents error, which `prepare` no longer reports.",
|
|
75
|
+
"hash": "07e3e99cb03e6031619bd58dac6ee339ceac0e89",
|
|
76
|
+
"entry": 1
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"title": "🧪 Tests",
|
|
82
|
+
"audience": "dev",
|
|
83
|
+
"items": [
|
|
84
|
+
{
|
|
85
|
+
"description": "Replaces the hand-rolled `console.warn` spies in release-kit's config-warning and push tests with `silenceConsole`, which restores the method when its `using` scope exits. (#964)",
|
|
86
|
+
"hash": "38cc179b4116bcd5aba8371b17b0816150c9e9a3",
|
|
87
|
+
"entry": 4
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"title": "📚 Documentation",
|
|
93
|
+
"audience": "dev",
|
|
94
|
+
"items": [
|
|
95
|
+
{
|
|
96
|
+
"description": "Updates the readyup examples in the `nmr`, `release-kit`, and `v11y-check` READMEs and the `nmr` rulebook to use the `sources` key and `rdy run --sources`, and states that `--sources` needs readyup 0.40 or later. (#977)",
|
|
97
|
+
"hash": "41177f8f562d59a4cf0aff9d24199dbd370bb1a1",
|
|
98
|
+
"entry": 4
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
},
|
|
2
104
|
{
|
|
3
105
|
"version": "13.1.0",
|
|
4
106
|
"date": "2026-10-02",
|
|
@@ -1923,10 +2025,22 @@
|
|
|
1923
2025
|
"audience": "all",
|
|
1924
2026
|
"items": [
|
|
1925
2027
|
{
|
|
1926
|
-
"description": "
|
|
1927
|
-
"body": "
|
|
1928
|
-
"hash": "
|
|
1929
|
-
}
|
|
2028
|
+
"description": "Allow git-cliff to be used without config (#31)",
|
|
2029
|
+
"body": "Adds a `resolveCliffConfigPath()` function that searches for a git-cliff config in a 4-step cascade (explicit path → `.config/git-cliff.toml` → `cliff.toml` → bundled `cliff.toml.template`), eliminating the requirement for consuming repos to maintain a cliff config copy. Restructures the `init` command to scaffold only the workflow file by default, with new `--with-config` and `--force` flags. Moves `.release-tags` from `/tmp/release-kit/` to project-local `tmp/` for predictable behavior in local runs.",
|
|
2030
|
+
"hash": "0cbd2605d6f5f53d1efe3dda8dd0f6e4376b499f"
|
|
2031
|
+
}
|
|
2032
|
+
]
|
|
2033
|
+
}
|
|
2034
|
+
]
|
|
2035
|
+
},
|
|
2036
|
+
{
|
|
2037
|
+
"version": "2.0.0",
|
|
2038
|
+
"date": "2026-03-16",
|
|
2039
|
+
"sections": [
|
|
2040
|
+
{
|
|
2041
|
+
"title": "🎉 Features",
|
|
2042
|
+
"audience": "all",
|
|
2043
|
+
"items": [
|
|
1930
2044
|
{
|
|
1931
2045
|
"description": "Slim down release workflow by removing unnecessary pnpm install (#21)",
|
|
1932
2046
|
"body": "Make release-kit self-contained by invoking git-cliff via `npx --yes` instead of requiring it on PATH, and by appending modified file paths to the format command so lightweight formatters like `npx prettier --write` work without a full `pnpm install`. Update init templates, README, and consuming repo config/workflow to reference workflow v3.",
|
|
@@ -1943,11 +2057,6 @@
|
|
|
1943
2057
|
"body": "Moves the reusable release workflow from `williamthorsen/.github` into this repo as `release-workflow.yaml`, stripping all pnpm-related steps since release-kit now runs git-cliff and prettier via `npx` internally. Updates this repo's caller workflow to use a relative path and update init templates to reference the new location. Establishes a naming convention (`{name}-workflow.yaml` for reusable, `{name}.yaml` for callers) and independent versioning strategy (`{name}-workflow-v{major}` tags), documented in `.github/workflows/README.md`.",
|
|
1944
2058
|
"breaking": true,
|
|
1945
2059
|
"hash": "f3416120cfe5bf0e7dbf51389e0c2647ccf41d30"
|
|
1946
|
-
},
|
|
1947
|
-
{
|
|
1948
|
-
"description": "Allow git-cliff to be used without config (#31)",
|
|
1949
|
-
"body": "Adds a `resolveCliffConfigPath()` function that searches for a git-cliff config in a 4-step cascade (explicit path → `.config/git-cliff.toml` → `cliff.toml` → bundled `cliff.toml.template`), eliminating the requirement for consuming repos to maintain a cliff config copy. Restructures the `init` command to scaffold only the workflow file by default, with new `--with-config` and `--force` flags. Moves `.release-tags` from `/tmp/release-kit/` to project-local `tmp/` for predictable behavior in local runs.",
|
|
1950
|
-
"hash": "0cbd2605d6f5f53d1efe3dda8dd0f6e4376b499f"
|
|
1951
2060
|
}
|
|
1952
2061
|
]
|
|
1953
2062
|
},
|
package/.readyup/kits/default.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @noformat -- @generated. Do not edit. Compiled by rdy. */
|
|
2
2
|
/* eslint-disable */
|
|
3
|
-
export const __readyupVersion = "0.
|
|
3
|
+
export const __readyupVersion = "0.40.0";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
// .readyup/kits/default.ts
|
|
@@ -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": "14.1.0" };
|
|
102
102
|
if (typeof picked["version"] !== "string") {
|
|
103
103
|
throw new TypeError("release-kit/package.json: 'version' must be a string");
|
|
104
104
|
}
|
|
@@ -115,8 +115,8 @@ var CONFIG_EXPORT_PATTERNS = [
|
|
|
115
115
|
/export\s*\*/
|
|
116
116
|
];
|
|
117
117
|
var COMMON_PRESET_HASH = "618bb5cbcbdd4f4f0c2a777add7e14d992d48483350dd9651bf8cf4c1fa9d418";
|
|
118
|
-
var SYNC_LABELS_WORKFLOW_HASH = "
|
|
119
|
-
var RELEASE_WORKFLOW_HASH_MONOREPO = "
|
|
118
|
+
var SYNC_LABELS_WORKFLOW_HASH = "0a88829d154c0de7cdd4246fede99e9311a89ab4199034dbe601663d641ab1e4";
|
|
119
|
+
var RELEASE_WORKFLOW_HASH_MONOREPO = "4a20ff3315155500f64a27133c54eb1bc1f07a4acc370ec0d83176109041c60d";
|
|
120
120
|
var RELEASE_WORKFLOW_HASH_SINGLE = "d26dd4ca186632b388ea46bd885721124c03d19918e511baa40821d2d760da69";
|
|
121
121
|
var PUBLISH_WORKFLOW_HASH_MONOREPO = "0afa9ffe914f3dc8f043e68252ebc604c8cc1a953422fcea37a909a4def370ee";
|
|
122
122
|
var PUBLISH_WORKFLOW_HASH_SINGLE = "6f31183e0a1e66be791a19266c3b028dadbd9fe010f7fc4452f3f8970c937b43";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @noformat -- @generated. Do not edit. Compiled by rdy. */
|
|
2
2
|
/* eslint-disable */
|
|
3
|
-
export const __readyupVersion = "0.
|
|
3
|
+
export const __readyupVersion = "0.40.0";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
// .readyup/kits/npm-auto-publish.ts
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
fileContains,
|
|
14
14
|
fileExists,
|
|
15
15
|
getJsonValue,
|
|
16
|
-
isRecord,
|
|
16
|
+
isRecord as isRecord2,
|
|
17
17
|
readFile,
|
|
18
18
|
readJsonFile
|
|
19
19
|
} from "readyup/check-utils";
|
|
@@ -23,10 +23,16 @@ function hasProvenance(workflowContent) {
|
|
|
23
23
|
return /^[^#]*provenance:\s*['"]?true['"]?/im.test(workflowContent);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
//
|
|
26
|
+
// src/npmRegistry.ts
|
|
27
|
+
import { execFileSync } from "node:child_process";
|
|
28
|
+
|
|
29
|
+
// src/typeGuards.ts
|
|
30
|
+
function isRecord(value) {
|
|
31
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/npmRegistry.ts
|
|
27
35
|
var AUTH_ERROR_CODES = /* @__PURE__ */ new Set(["E401", "ENEEDAUTH"]);
|
|
28
|
-
var OTP_ERROR_CODE = "EOTP";
|
|
29
|
-
var PUBLISH_WORKFLOW_FILE = "publish.yaml";
|
|
30
36
|
var UNREACHABLE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
31
37
|
"EAI_AGAIN",
|
|
32
38
|
"ECONNREFUSED",
|
|
@@ -36,6 +42,54 @@ var UNREACHABLE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
36
42
|
"ERR_SOCKET_TIMEOUT",
|
|
37
43
|
"ETIMEDOUT"
|
|
38
44
|
]);
|
|
45
|
+
function classifyNpmPackageLookup(result) {
|
|
46
|
+
if (result.exitOk) {
|
|
47
|
+
return { status: "published" };
|
|
48
|
+
}
|
|
49
|
+
const error = readNpmError(result.stdout);
|
|
50
|
+
if (error === void 0) {
|
|
51
|
+
return { status: "unverifiable", detail: "The npm registry query failed without a readable error payload" };
|
|
52
|
+
}
|
|
53
|
+
if (error.code === "E404") {
|
|
54
|
+
return { status: "unpublished" };
|
|
55
|
+
}
|
|
56
|
+
if (AUTH_ERROR_CODES.has(error.code)) {
|
|
57
|
+
return { status: "unverifiable", detail: `The npm registry rejected the session (${error.code})` };
|
|
58
|
+
}
|
|
59
|
+
if (UNREACHABLE_ERROR_CODES.has(error.code)) {
|
|
60
|
+
return { status: "unverifiable", detail: `Cannot reach the npm registry (${error.code})` };
|
|
61
|
+
}
|
|
62
|
+
return { status: "unverifiable", detail: `The npm registry query failed (${error.code}): ${error.summary}` };
|
|
63
|
+
}
|
|
64
|
+
function lookUpNpmPackage(packageName, registry) {
|
|
65
|
+
const args = ["view", packageName, "version", "--json", ...registry === void 0 ? [] : ["--registry", registry]];
|
|
66
|
+
return classifyNpmPackageLookup(runNpmJson(args));
|
|
67
|
+
}
|
|
68
|
+
function readNpmError(stdout) {
|
|
69
|
+
let parsed;
|
|
70
|
+
try {
|
|
71
|
+
parsed = JSON.parse(stdout);
|
|
72
|
+
} catch {
|
|
73
|
+
return void 0;
|
|
74
|
+
}
|
|
75
|
+
if (!isRecord(parsed) || !isRecord(parsed["error"]) || typeof parsed["error"]["code"] !== "string") {
|
|
76
|
+
return void 0;
|
|
77
|
+
}
|
|
78
|
+
const { code, summary } = parsed["error"];
|
|
79
|
+
return { code, summary: typeof summary === "string" ? summary : "" };
|
|
80
|
+
}
|
|
81
|
+
function runNpmJson(args) {
|
|
82
|
+
try {
|
|
83
|
+
return { exitOk: true, stdout: execFileSync("npm", args, { encoding: "utf8", stdio: "pipe" }) };
|
|
84
|
+
} catch (error) {
|
|
85
|
+
const stdout = isRecord(error) && typeof error["stdout"] === "string" ? error["stdout"] : "";
|
|
86
|
+
return { exitOk: false, stdout };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// .readyup/kits/npm-auto-publish.ts
|
|
91
|
+
var OTP_ERROR_CODE = "EOTP";
|
|
92
|
+
var PUBLISH_WORKFLOW_FILE = "publish.yaml";
|
|
39
93
|
var repoChecklist = defineRdyChecklist({
|
|
40
94
|
name: "repo",
|
|
41
95
|
checks: [
|
|
@@ -149,7 +203,7 @@ function buildWorkspaceCheck(workspace) {
|
|
|
149
203
|
const auth = getCachedNpmAuthStatus();
|
|
150
204
|
return auth.status === "unreachable" ? auth.detail : false;
|
|
151
205
|
},
|
|
152
|
-
check: () =>
|
|
206
|
+
check: () => describeNpmPackageLookup(lookUpNpmPackage(displayName, readPublishRegistry(workspace))),
|
|
153
207
|
fix: `Run "npm publish --access public" from ${workspace.dir} to bootstrap the package on npm`,
|
|
154
208
|
checks: [
|
|
155
209
|
{
|
|
@@ -290,6 +344,19 @@ function classifyTrustQuery(result, expectedRepo, expectedFile) {
|
|
|
290
344
|
detail: `Expected github ${expectedRepo} (${expectedFile}); found ${describeTrustRelationships(relationships)}`
|
|
291
345
|
};
|
|
292
346
|
}
|
|
347
|
+
function describeNpmPackageLookup(lookup) {
|
|
348
|
+
if (lookup.status === "published") {
|
|
349
|
+
return { ok: true };
|
|
350
|
+
}
|
|
351
|
+
if (lookup.status === "unpublished") {
|
|
352
|
+
return { ok: false, detail: "The npm registry does not list this package" };
|
|
353
|
+
}
|
|
354
|
+
return {
|
|
355
|
+
ok: false,
|
|
356
|
+
detail: lookup.detail,
|
|
357
|
+
fix: "Restore access to the npm registry, then run this check again"
|
|
358
|
+
};
|
|
359
|
+
}
|
|
293
360
|
function describeTrustRelationships(relationships) {
|
|
294
361
|
return relationships.map((relationship) => {
|
|
295
362
|
const type = typeof relationship.type === "string" ? relationship.type : "(unknown)";
|
|
@@ -300,7 +367,7 @@ function describeTrustRelationships(relationships) {
|
|
|
300
367
|
}
|
|
301
368
|
var getCachedNpmAuthStatus = /* @__PURE__ */ (() => {
|
|
302
369
|
let cached;
|
|
303
|
-
return () => cached ??= classifyNpmAuth(runNpmJson("
|
|
370
|
+
return () => cached ??= classifyNpmAuth(runNpmJson(["whoami", "--json"]));
|
|
304
371
|
})();
|
|
305
372
|
var getCachedOwnerRepo = /* @__PURE__ */ (() => {
|
|
306
373
|
let cached;
|
|
@@ -331,7 +398,7 @@ function getTrustQueryResult(packageName) {
|
|
|
331
398
|
return cached;
|
|
332
399
|
}
|
|
333
400
|
const result = classifyTrustQuery(
|
|
334
|
-
runNpmJson(
|
|
401
|
+
runNpmJson(["trust", "list", packageName, "--json"]),
|
|
335
402
|
getCachedOwnerRepo(),
|
|
336
403
|
PUBLISH_WORKFLOW_FILE
|
|
337
404
|
);
|
|
@@ -352,17 +419,6 @@ function hasTokenReferences() {
|
|
|
352
419
|
}
|
|
353
420
|
return false;
|
|
354
421
|
}
|
|
355
|
-
function isPublishedToNpm(packageName) {
|
|
356
|
-
try {
|
|
357
|
-
execSync(`npm view ${packageName} version`, {
|
|
358
|
-
encoding: "utf8",
|
|
359
|
-
stdio: "pipe"
|
|
360
|
-
});
|
|
361
|
-
return true;
|
|
362
|
-
} catch {
|
|
363
|
-
return false;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
422
|
function isRepoPrivate() {
|
|
367
423
|
const ownerRepo = getOwnerRepo();
|
|
368
424
|
const result = execSync(`gh api repos/${ownerRepo} --jq .private`, {
|
|
@@ -374,18 +430,9 @@ function probeTrustQuery() {
|
|
|
374
430
|
const probeName = selectProbeName();
|
|
375
431
|
return probeName === void 0 ? void 0 : getTrustQueryResult(probeName);
|
|
376
432
|
}
|
|
377
|
-
function
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
parsed = JSON.parse(stdout);
|
|
381
|
-
} catch {
|
|
382
|
-
return void 0;
|
|
383
|
-
}
|
|
384
|
-
if (!isRecord(parsed) || !isRecord(parsed["error"]) || typeof parsed["error"]["code"] !== "string") {
|
|
385
|
-
return void 0;
|
|
386
|
-
}
|
|
387
|
-
const { code, summary } = parsed["error"];
|
|
388
|
-
return { code, summary: typeof summary === "string" ? summary : "" };
|
|
433
|
+
function readPublishRegistry(workspace) {
|
|
434
|
+
const registry = getJsonValue(workspace.packageJson, "publishConfig", "registry");
|
|
435
|
+
return typeof registry === "string" ? registry : void 0;
|
|
389
436
|
}
|
|
390
437
|
function readTrustRelationships(stdout) {
|
|
391
438
|
let parsed;
|
|
@@ -395,9 +442,9 @@ function readTrustRelationships(stdout) {
|
|
|
395
442
|
return void 0;
|
|
396
443
|
}
|
|
397
444
|
if (Array.isArray(parsed)) {
|
|
398
|
-
return parsed.filter((entry) =>
|
|
445
|
+
return parsed.filter((entry) => isRecord2(entry) && "type" in entry);
|
|
399
446
|
}
|
|
400
|
-
if (!
|
|
447
|
+
if (!isRecord2(parsed)) {
|
|
401
448
|
return void 0;
|
|
402
449
|
}
|
|
403
450
|
return "type" in parsed ? [parsed] : [];
|
|
@@ -406,14 +453,6 @@ function resolveTrustCapability() {
|
|
|
406
453
|
const auth = getCachedNpmAuthStatus();
|
|
407
454
|
return classifyTrustCapability(auth, auth.status === "authenticated" ? probeTrustQuery() : void 0);
|
|
408
455
|
}
|
|
409
|
-
function runNpmJson(command) {
|
|
410
|
-
try {
|
|
411
|
-
return { exitOk: true, stdout: execSync(command, { encoding: "utf8", stdio: "pipe" }) };
|
|
412
|
-
} catch (error) {
|
|
413
|
-
const stdout = isRecord(error) && typeof error["stdout"] === "string" ? error["stdout"] : "";
|
|
414
|
-
return { exitOk: false, stdout };
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
456
|
function selectProbeName() {
|
|
418
457
|
return discoverWorkspaces({ filter: (workspace) => workspace.isPackage }).find(
|
|
419
458
|
(workspace) => workspace.name !== void 0
|
|
@@ -433,6 +472,7 @@ export {
|
|
|
433
472
|
classifyTrustCapability,
|
|
434
473
|
classifyTrustQuery,
|
|
435
474
|
npm_auto_publish_default as default,
|
|
475
|
+
describeNpmPackageLookup,
|
|
436
476
|
packagesChecklist,
|
|
437
477
|
selectProbeName,
|
|
438
478
|
skipIfNotPublishable,
|
package/.readyup/manifest.json
CHANGED
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
"esbuildVersion": "0.28.2",
|
|
9
9
|
"inputs": [
|
|
10
10
|
{
|
|
11
|
-
"hash": "
|
|
11
|
+
"hash": "dee24ab4",
|
|
12
12
|
"kind": "module",
|
|
13
13
|
"path": "kits/default.ts"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
|
-
"hash": "
|
|
16
|
+
"hash": "4aa0967e",
|
|
17
17
|
"kind": "inline",
|
|
18
18
|
"path": "../package.json",
|
|
19
19
|
"paths": [
|
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
],
|
|
44
44
|
"name": "default",
|
|
45
45
|
"path": "kits/default.js",
|
|
46
|
-
"readyupVersion": "0.
|
|
46
|
+
"readyupVersion": "0.40.0",
|
|
47
47
|
"source": "kits/default.ts",
|
|
48
|
-
"sourceHash": "
|
|
49
|
-
"targetHash": "
|
|
48
|
+
"sourceHash": "dee24ab4",
|
|
49
|
+
"targetHash": "25d17b58"
|
|
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": "70c0bb99",
|
|
60
60
|
"kind": "module",
|
|
61
61
|
"path": "kits/npm-auto-publish.ts"
|
|
62
62
|
},
|
|
@@ -64,14 +64,24 @@
|
|
|
64
64
|
"hash": "d360febf",
|
|
65
65
|
"kind": "module",
|
|
66
66
|
"path": "../src/init/hasProvenance.ts"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"hash": "3e39b9be",
|
|
70
|
+
"kind": "module",
|
|
71
|
+
"path": "../src/npmRegistry.ts"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"hash": "1424b343",
|
|
75
|
+
"kind": "module",
|
|
76
|
+
"path": "../src/typeGuards.ts"
|
|
67
77
|
}
|
|
68
78
|
],
|
|
69
79
|
"name": "npm-auto-publish",
|
|
70
80
|
"path": "kits/npm-auto-publish.js",
|
|
71
|
-
"readyupVersion": "0.
|
|
81
|
+
"readyupVersion": "0.40.0",
|
|
72
82
|
"source": "kits/npm-auto-publish.ts",
|
|
73
|
-
"sourceHash": "
|
|
74
|
-
"targetHash": "
|
|
83
|
+
"sourceHash": "70c0bb99",
|
|
84
|
+
"targetHash": "d97d6123"
|
|
75
85
|
}
|
|
76
86
|
]
|
|
77
87
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 14.1.0 — 2026-10-11
|
|
6
|
+
|
|
7
|
+
### 🎉 Features
|
|
8
|
+
|
|
9
|
+
- Stops `release-kit init` from scaffolding `publish.yaml` and `create-github-release.yaml` when every package is private, even with `--force`, and removes the provenance and trusted-publisher steps from the next steps that it prints. (#995)
|
|
10
|
+
- Stops `release-kit update-templates` from re-creating a deleted `publish.yaml` or `create-github-release.yaml` when every package is private, while it still refreshes either workflow that exists. (#995)
|
|
11
|
+
- Makes `release-kit prepare` refuse, before it writes any file and in a dry run too, to release a publishable package that npm does not list or that it cannot look up, and prints `npm publish --access public` as the fix for each unlisted package. (#996)
|
|
12
|
+
|
|
13
|
+
### 🐛 Bug fixes
|
|
14
|
+
|
|
15
|
+
- Fixes the issue that the `npm-auto-publish` kit's "published to npm" check reported a failed lookup, such as an unreachable registry or an authentication error, as an unpublished package and ignored `publishConfig.registry`. (#996)
|
|
16
|
+
- Fixes the issue that release-kit's changelog generation treated a floating major tag such as `v1` as a release and added a spurious release to the history, by counting a tag only when the rest of its name after the prefix is a complete SemVer version such as `1.0.0` or `1.0.0-beta.1`. (#1000)
|
|
17
|
+
- Fixes the issue that `release-kit show-tag-prefixes` counted every tag that starts with a workspace's prefix, including floating pointers such as `core-v1` and non-release tags such as `core-vnext`, rather than only the tags that release-kit counts as releases. (#1000)
|
|
18
|
+
|
|
19
|
+
## 14.0.0 — 2026-10-08
|
|
20
|
+
|
|
21
|
+
### 🎉 Features
|
|
22
|
+
|
|
23
|
+
- 🚨 **Breaking:** Changes monorepo `--set-version` to take comma-separated `<workspace>@N.N.N` entries, which `prepare` accepts without `--only` and together with `--bump` and `--force`, and which release each named workspace's dependents. (#970)
|
|
24
|
+
|
|
25
|
+
### 🐛 Bug fixes
|
|
26
|
+
|
|
27
|
+
- 🚨 **Breaking:** Fixes the issue that `release-kit prepare --only` left each dependent of the named workspaces published against the old version range of its dependency, by also releasing every transitive dependent: a dependent with commits of its own at its own bump, and one without at a propagated patch bump. (#970)
|
|
28
|
+
|
|
29
|
+
### 🧪 Tests
|
|
30
|
+
|
|
31
|
+
- Replaces the hand-rolled `console.warn` spies in release-kit's config-warning and push tests with `silenceConsole`, which restores the method when its `using` scope exits. (#964)
|
|
32
|
+
|
|
33
|
+
### 📚 Documentation
|
|
34
|
+
|
|
35
|
+
- Updates the readyup examples in the `nmr`, `release-kit`, and `v11y-check` READMEs and the `nmr` rulebook to use the `sources` key and `rdy run --sources`, and states that `--sources` needs readyup 0.40 or later. (#977)
|
|
36
|
+
|
|
5
37
|
## 13.1.0 — 2026-10-02
|
|
6
38
|
|
|
7
39
|
### 🎉 Features
|
|
@@ -1111,9 +1143,13 @@ All notable changes to this project will be documented in this file.
|
|
|
1111
1143
|
|
|
1112
1144
|
### 🎉 Features
|
|
1113
1145
|
|
|
1114
|
-
-
|
|
1146
|
+
- Allow git-cliff to be used without config (#31)
|
|
1115
1147
|
|
|
1116
|
-
|
|
1148
|
+
Adds a `resolveCliffConfigPath()` function that searches for a git-cliff config in a 4-step cascade (explicit path → `.config/git-cliff.toml` → `cliff.toml` → bundled `cliff.toml.template`), eliminating the requirement for consuming repos to maintain a cliff config copy. Restructures the `init` command to scaffold only the workflow file by default, with new `--with-config` and `--force` flags. Moves `.release-tags` from `/tmp/release-kit/` to project-local `tmp/` for predictable behavior in local runs.
|
|
1149
|
+
|
|
1150
|
+
## 2.0.0 — 2026-03-16
|
|
1151
|
+
|
|
1152
|
+
### 🎉 Features
|
|
1117
1153
|
|
|
1118
1154
|
- 🚨 **Breaking:** Slim down release workflow by removing unnecessary pnpm install (#21)
|
|
1119
1155
|
|
|
@@ -1127,10 +1163,6 @@ All notable changes to this project will be documented in this file.
|
|
|
1127
1163
|
|
|
1128
1164
|
Moves the reusable release workflow from `williamthorsen/.github` into this repo as `release-workflow.yaml`, stripping all pnpm-related steps since release-kit now runs git-cliff and prettier via `npx` internally. Updates this repo's caller workflow to use a relative path and update init templates to reference the new location. Establishes a naming convention (`{name}-workflow.yaml` for reusable, `{name}.yaml` for callers) and independent versioning strategy (`{name}-workflow-v{major}` tags), documented in `.github/workflows/README.md`.
|
|
1129
1165
|
|
|
1130
|
-
- Allow git-cliff to be used without config (#31)
|
|
1131
|
-
|
|
1132
|
-
Adds a `resolveCliffConfigPath()` function that searches for a git-cliff config in a 4-step cascade (explicit path → `.config/git-cliff.toml` → `cliff.toml` → bundled `cliff.toml.template`), eliminating the requirement for consuming repos to maintain a cliff config copy. Restructures the `init` command to scaffold only the workflow file by default, with new `--with-config` and `--force` flags. Moves `.release-tags` from `/tmp/release-kit/` to project-local `tmp/` for predictable behavior in local runs.
|
|
1133
|
-
|
|
1134
1166
|
### ♻️ Refactoring
|
|
1135
1167
|
|
|
1136
1168
|
- Clean up release-kit post-migration issues (#19)
|
package/README.md
CHANGED
|
@@ -7,11 +7,19 @@ 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 the same commit history that decides each bump (with optional [editorial overrides](docs/editorial-overrides.md)).
|
|
8
8
|
|
|
9
9
|
<!-- section:release-notes -->
|
|
10
|
-
## Release notes —
|
|
10
|
+
## Release notes — v14.1.0 (2026-10-11)
|
|
11
11
|
|
|
12
12
|
### 🎉 Features
|
|
13
13
|
|
|
14
|
-
-
|
|
14
|
+
- Stops `release-kit init` from scaffolding `publish.yaml` and `create-github-release.yaml` when every package is private, even with `--force`, and removes the provenance and trusted-publisher steps from the next steps that it prints. (#995)
|
|
15
|
+
- Stops `release-kit update-templates` from re-creating a deleted `publish.yaml` or `create-github-release.yaml` when every package is private, while it still refreshes either workflow that exists. (#995)
|
|
16
|
+
- Makes `release-kit prepare` refuse, before it writes any file and in a dry run too, to release a publishable package that npm does not list or that it cannot look up, and prints `npm publish --access public` as the fix for each unlisted package. (#996)
|
|
17
|
+
|
|
18
|
+
### 🐛 Bug fixes
|
|
19
|
+
|
|
20
|
+
- Fixes the issue that the `npm-auto-publish` kit's "published to npm" check reported a failed lookup, such as an unreachable registry or an authentication error, as an unpublished package and ignored `publishConfig.registry`. (#996)
|
|
21
|
+
- Fixes the issue that release-kit's changelog generation treated a floating major tag such as `v1` as a release and added a spurious release to the history, by counting a tag only when the rest of its name after the prefix is a complete SemVer version such as `1.0.0` or `1.0.0-beta.1`. (#1000)
|
|
22
|
+
- Fixes the issue that `release-kit show-tag-prefixes` counted every tag that starts with a workspace's prefix, including floating pointers such as `core-v1` and non-release tags such as `core-vnext`, rather than only the tags that release-kit counts as releases. (#1000)
|
|
15
23
|
<!-- /section:release-notes -->
|
|
16
24
|
|
|
17
25
|
## Installation
|
|
@@ -57,7 +65,7 @@ Commit the scaffolded workflows, then start a release from the `release` workflo
|
|
|
57
65
|
|
|
58
66
|
```sh
|
|
59
67
|
gh workflow run release.yaml # every workspace with release-worthy changes
|
|
60
|
-
gh workflow run release.yaml -f only=arrays # the named workspaces
|
|
68
|
+
gh workflow run release.yaml -f only=arrays # the named workspaces and their dependents
|
|
61
69
|
```
|
|
62
70
|
|
|
63
71
|
After upgrading release-kit, run `release-kit update-templates` to update the scaffolded workflows to its templates; it leaves the config files alone.
|
|
@@ -136,15 +144,15 @@ release-kit publishes two [readyup](https://www.npmjs.com/package/readyup) kits:
|
|
|
136
144
|
import { defineRdyConfig } from 'readyup';
|
|
137
145
|
|
|
138
146
|
export default defineRdyConfig({
|
|
139
|
-
|
|
147
|
+
sources: ['npm:@williamthorsen/release-kit'],
|
|
140
148
|
});
|
|
141
149
|
```
|
|
142
150
|
|
|
143
151
|
```bash
|
|
144
|
-
rdy run --
|
|
152
|
+
rdy run --sources
|
|
145
153
|
```
|
|
146
154
|
|
|
147
|
-
`rdy run` needs `readyup` 0.
|
|
155
|
+
`rdy run --sources` needs `readyup` 0.40 or later, and `@williamthorsen/release-kit` as a _direct_ devDependency: A strict pnpm layout links nothing else into the project; therefore, a transitive copy is unreachable.
|
|
148
156
|
|
|
149
157
|
[Readiness checks](docs/readiness-checks.md) covers running each kit alone and what `npm-auto-publish` needs from the npm session.
|
|
150
158
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Throws when npm doesn't list, or can't confirm, a publishable package among the given workspaces.
|
|
3
|
+
*
|
|
4
|
+
* Each workspace path is repo-relative and is read from the current directory. A private package is not looked up,
|
|
5
|
+
* and an empty list doesn't call the registry at all.
|
|
6
|
+
*/
|
|
7
|
+
export declare function assertReleasesOnNpm(workspacePaths: readonly string[]): void;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { isPublishableManifest } from "./isPublishableManifest.js";
|
|
4
|
+
import { lookUpNpmPackage } from "./npmRegistry.js";
|
|
5
|
+
import { isRecord } from "./typeGuards.js";
|
|
6
|
+
export function assertReleasesOnNpm(workspacePaths) {
|
|
7
|
+
const unpublished = [];
|
|
8
|
+
const unverifiable = [];
|
|
9
|
+
for (const workspacePath of workspacePaths) {
|
|
10
|
+
const candidate = buildNpmCandidate(workspacePath);
|
|
11
|
+
if (candidate === undefined) {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
const lookup = lookUpNpmPackage(candidate.name, candidate.registry);
|
|
15
|
+
if (lookup.status === 'unpublished') {
|
|
16
|
+
unpublished.push(candidate);
|
|
17
|
+
}
|
|
18
|
+
else if (lookup.status === 'unverifiable') {
|
|
19
|
+
unverifiable.push({ candidate, detail: lookup.detail });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (unpublished.length === 0 && unverifiable.length === 0) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
throw new Error(describeRefusal(unpublished, unverifiable));
|
|
26
|
+
}
|
|
27
|
+
function buildNpmCandidate(workspacePath) {
|
|
28
|
+
const manifest = JSON.parse(readFileSync(join(workspacePath, 'package.json'), 'utf8'));
|
|
29
|
+
if (!isRecord(manifest) || !isPublishableManifest(manifest) || typeof manifest['name'] !== 'string') {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
const publishConfig = manifest['publishConfig'];
|
|
33
|
+
const registry = isRecord(publishConfig) ? publishConfig['registry'] : undefined;
|
|
34
|
+
return {
|
|
35
|
+
name: manifest['name'],
|
|
36
|
+
workspacePath,
|
|
37
|
+
...(typeof registry === 'string' && { registry }),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function describeRefusal(unpublished, unverifiable) {
|
|
41
|
+
const sections = ['Cannot prepare the release: npm must already have every package that the release publishes.'];
|
|
42
|
+
if (unpublished.length > 0) {
|
|
43
|
+
sections.push([
|
|
44
|
+
'Not on npm yet:',
|
|
45
|
+
...unpublished.map(({ name, workspacePath }) => ` - ${name}: run "npm publish --access public" from ${workspacePath}`),
|
|
46
|
+
'Then register each one as a trusted publisher; "rdy run --from npm:@williamthorsen/release-kit npm-auto-publish" prints the command.',
|
|
47
|
+
].join('\n'));
|
|
48
|
+
}
|
|
49
|
+
if (unverifiable.length > 0) {
|
|
50
|
+
sections.push([
|
|
51
|
+
'Could not confirm on npm:',
|
|
52
|
+
...unverifiable.map(({ candidate, detail }) => ` - ${candidate.name}: ${detail}`),
|
|
53
|
+
].join('\n'));
|
|
54
|
+
}
|
|
55
|
+
return sections.join('\n\n');
|
|
56
|
+
}
|
|
@@ -108,7 +108,8 @@ function showInitHelp() {
|
|
|
108
108
|
Usage: release-kit init [options]
|
|
109
109
|
|
|
110
110
|
Initialize release-kit in the current repository.
|
|
111
|
-
By default, scaffolds only the GitHub Actions workflow files.
|
|
111
|
+
By default, scaffolds only the GitHub Actions workflow files. When every
|
|
112
|
+
package is private, skips publish.yaml and create-github-release.yaml.
|
|
112
113
|
|
|
113
114
|
Options:
|
|
114
115
|
--with-config Also scaffold .config/release-kit.config.ts
|
|
@@ -124,7 +125,9 @@ Usage: release-kit update-templates [options]
|
|
|
124
125
|
Update the GitHub Actions workflows that release-kit scaffolds to the templates
|
|
125
126
|
of the installed version, showing what changed in each file. Creates a missing
|
|
126
127
|
workflow that \`init\` would create, and refreshes sync-labels.yaml only when it
|
|
127
|
-
exists.
|
|
128
|
+
exists. When every package is private, refreshes publish.yaml and
|
|
129
|
+
create-github-release.yaml only when they exist. Keeps publish.yaml's provenance
|
|
130
|
+
setting. Never touches config files.
|
|
128
131
|
|
|
129
132
|
Options:
|
|
130
133
|
--dry-run Preview changes without writing files
|