@williamthorsen/release-kit 12.0.0 → 13.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 +229 -0
- package/.readyup/kits/default.js +18 -17
- package/.readyup/kits/npm-auto-publish.js +24 -23
- package/.readyup/manifest.json +16 -11
- package/CHANGELOG.md +64 -0
- package/README.md +27 -51
- package/bin/release-kit.js +1 -1
- package/dist/esm/assertCleanWorkingTree.d.ts +1 -5
- package/dist/esm/assertTaggedBaseline.d.ts +29 -0
- package/dist/esm/assertTaggedBaseline.js +41 -0
- package/dist/esm/attachChangelogDiagnostics.d.ts +1 -1
- package/dist/esm/attachChangelogDiagnostics.js +3 -0
- package/dist/esm/bin/release-kit.js +85 -22
- package/dist/esm/buildChangelogEntries.d.ts +23 -13
- package/dist/esm/buildChangelogEntries.js +36 -17
- package/dist/esm/buildDependencyGraph.d.ts +6 -6
- package/dist/esm/buildEmptyReleaseEntry.d.ts +1 -8
- package/dist/esm/buildReleaseSummary.d.ts +2 -8
- package/dist/esm/buildSyntheticChangelogEntry.d.ts +3 -5
- package/dist/esm/buildSyntheticChangelogEntry.js +2 -2
- package/dist/esm/bumpVersion.d.ts +1 -8
- package/dist/esm/changelogJsonFile.d.ts +5 -7
- package/dist/esm/changelogJsonFile.js +2 -17
- package/dist/esm/changelogJsonUtils.d.ts +7 -10
- package/dist/esm/changelogOverrides.d.ts +59 -98
- package/dist/esm/classifyChangelogCommit.d.ts +7 -9
- package/dist/esm/classifyChangelogCommit.js +3 -2
- package/dist/esm/commitCommand.d.ts +2 -4
- package/dist/esm/compareVersions.d.ts +10 -4
- package/dist/esm/compareVersions.js +16 -0
- package/dist/esm/configFlagSchema.d.ts +1 -1
- package/dist/esm/createGithubRelease.d.ts +7 -19
- package/dist/esm/createGithubReleaseCommand.d.ts +5 -5
- package/dist/esm/createGithubReleaseCommand.js +9 -9
- package/dist/esm/createTags.d.ts +2 -3
- package/dist/esm/decideRelease.d.ts +2 -6
- package/dist/esm/defaults.d.ts +5 -24
- package/dist/esm/defaults.js +4 -5
- package/dist/esm/defineConfig.d.ts +1 -1
- package/dist/esm/deleteFileIfExists.d.ts +1 -1
- package/dist/esm/deriveReleaseNotesConfig.d.ts +20 -0
- package/dist/esm/deriveReleaseNotesConfig.js +21 -0
- package/dist/esm/deriveWorkspaceConfig.d.ts +3 -5
- package/dist/esm/detectPackageManager.d.ts +2 -4
- package/dist/esm/detectUndeclaredTagPrefixes.d.ts +4 -6
- package/dist/esm/detectUndeclaredTagPrefixes.js +1 -1
- package/dist/esm/determineBumpType.d.ts +1 -1
- package/dist/esm/discoverWorkspaces.d.ts +14 -15
- package/dist/esm/discoverWorkspaces.js +12 -12
- package/dist/esm/enterRepoRoot.d.ts +12 -0
- package/dist/esm/enterRepoRoot.js +16 -0
- package/dist/esm/enumerateReleaseWindows.d.ts +8 -8
- package/dist/esm/extractMigration.d.ts +6 -8
- package/dist/esm/findUnroutedEntryScopes.d.ts +16 -0
- package/dist/esm/findUnroutedEntryScopes.js +57 -0
- package/dist/esm/formatExcludedSkip.d.ts +3 -0
- package/dist/esm/formatExcludedSkip.js +3 -0
- package/dist/esm/formatPrivateSkip.d.ts +1 -6
- package/dist/esm/generateChangelogs.d.ts +10 -5
- package/dist/esm/glyphs.d.ts +1 -1
- package/dist/esm/help/prepareHelp.d.ts +3 -4
- package/dist/esm/help/prepareHelp.js +4 -3
- package/dist/esm/init/checks.d.ts +3 -3
- package/dist/esm/init/checks.js +4 -1
- package/dist/esm/init/detectRepoType.d.ts +2 -3
- package/dist/esm/init/hasProvenance.d.ts +2 -0
- package/dist/esm/init/hasProvenance.js +3 -0
- package/dist/esm/init/initCommand.d.ts +3 -6
- package/dist/esm/init/initCommand.js +10 -10
- package/dist/esm/init/parseJsonRecord.d.ts +1 -4
- package/dist/esm/init/scaffold.d.ts +1 -1
- package/dist/esm/init/templates.d.ts +9 -11
- package/dist/esm/init/templates.js +12 -11
- package/dist/esm/init/updateTemplatesCommand.d.ts +13 -0
- package/dist/esm/init/updateTemplatesCommand.js +64 -0
- package/dist/esm/injectReleaseNotesIntoReadme.d.ts +12 -17
- package/dist/esm/injectSection.d.ts +3 -3
- package/dist/esm/loadConfig.d.ts +16 -14
- package/dist/esm/loadConfig.js +2 -2
- package/dist/esm/loadValidatedConfig.d.ts +16 -19
- package/dist/esm/loadValidatedConfig.js +6 -1
- package/dist/esm/packsPath.d.ts +9 -9
- package/dist/esm/parseChangeRecordBlock.d.ts +2 -2
- package/dist/esm/parseCommitMessage.d.ts +17 -32
- package/dist/esm/parseCommitMessage.js +28 -37
- package/dist/esm/parseRequestedTags.d.ts +3 -3
- package/dist/esm/planReleaseNotesPreviews.d.ts +6 -6
- package/dist/esm/planVersionBump.d.ts +5 -3
- package/dist/esm/planVersionBump.js +3 -0
- package/dist/esm/prepareCommand.d.ts +4 -7
- package/dist/esm/prepareCommand.js +13 -6
- package/dist/esm/previewTagPrefixes.d.ts +8 -10
- package/dist/esm/propagateBumps.d.ts +6 -7
- package/dist/esm/publish.d.ts +1 -1
- package/dist/esm/publishCommand.d.ts +4 -3
- package/dist/esm/publishCommand.js +8 -8
- package/dist/esm/pushCommand.d.ts +4 -3
- package/dist/esm/pushCommand.js +8 -2
- package/dist/esm/pushRelease.d.ts +2 -2
- package/dist/esm/readChangelogSections.d.ts +33 -0
- package/dist/esm/readChangelogSections.js +80 -0
- package/dist/esm/releaseFiles.d.ts +5 -7
- package/dist/esm/releasePlan.d.ts +11 -13
- package/dist/esm/releasePrepare.d.ts +23 -22
- package/dist/esm/releasePrepare.js +31 -11
- package/dist/esm/releasePrepareMono.d.ts +9 -7
- package/dist/esm/releasePrepareMono.js +85 -33
- package/dist/esm/releasePrepareProject.d.ts +19 -29
- package/dist/esm/releasePrepareProject.js +31 -12
- package/dist/esm/renderChangelogMarkdown.d.ts +10 -4
- package/dist/esm/renderChangelogMarkdown.js +27 -2
- package/dist/esm/renderReleaseNotes.d.ts +3 -11
- package/dist/esm/renderReleaseNotes.js +2 -6
- package/dist/esm/reportPrepare.d.ts +4 -5
- package/dist/esm/reportPrepare.js +33 -19
- package/dist/esm/resolveCommandTags.d.ts +15 -11
- package/dist/esm/resolveCommandTags.js +35 -5
- package/dist/esm/resolveConfigFlag.d.ts +7 -0
- package/dist/esm/resolveConfigFlag.js +4 -0
- package/dist/esm/resolveReleaseTags.d.ts +6 -8
- package/dist/esm/resolveReleaseTags.js +1 -1
- package/dist/esm/resolveStylesOrExit.d.ts +2 -2
- package/dist/esm/showTagPrefixesCommand.d.ts +7 -10
- package/dist/esm/showTagPrefixesCommand.js +4 -4
- package/dist/esm/stripEmojiPrefix.d.ts +1 -0
- package/dist/esm/stripScope.d.ts +2 -2
- package/dist/esm/stripScope.js +3 -3
- package/dist/esm/sync-labels/generateCommand.d.ts +11 -10
- package/dist/esm/sync-labels/generateCommand.js +17 -9
- package/dist/esm/sync-labels/initCommand.d.ts +6 -7
- package/dist/esm/sync-labels/initCommand.js +2 -2
- package/dist/esm/sync-labels/presets.d.ts +5 -4
- package/dist/esm/sync-labels/presets.js +9 -9
- package/dist/esm/sync-labels/resolveLabels.d.ts +7 -7
- package/dist/esm/sync-labels/resolveLabels.js +2 -1
- package/dist/esm/sync-labels/retiredConfig.d.ts +4 -5
- package/dist/esm/sync-labels/syncCommand.d.ts +1 -4
- package/dist/esm/sync-labels/templates.d.ts +3 -3
- package/dist/esm/sync-labels/templates.js +3 -3
- package/dist/esm/sync-labels/typeLabels.d.ts +14 -0
- package/dist/esm/sync-labels/typeLabels.js +38 -0
- package/dist/esm/sync-labels/types.d.ts +4 -2
- package/dist/esm/tagCommand.d.ts +1 -1
- package/dist/esm/typeGuards.d.ts +2 -2
- package/dist/esm/types.d.ts +122 -93
- package/dist/esm/types.js +2 -1
- package/dist/esm/validateConfig.d.ts +2 -11
- package/dist/esm/validateConfig.js +2 -2
- package/dist/esm/validateOnlyExcludesStrandedDependents.d.ts +14 -12
- package/dist/esm/validateOverridesCommand.d.ts +17 -20
- package/dist/esm/validateOverridesCommand.js +1 -1
- package/docs/api.md +6 -6
- package/docs/changelogs.md +63 -40
- package/docs/configuration.md +29 -27
- package/docs/editorial-overrides.md +23 -23
- package/docs/labels.md +37 -19
- package/docs/project-releases.md +13 -13
- package/docs/publishing.md +5 -5
- package/docs/readiness-checks.md +3 -3
- package/docs/releasing.md +50 -25
- package/docs/work-types.md +41 -57
- package/package.json +7 -6
- package/presets/labels/common.yaml +1 -41
- package/dist/esm/resolveReleaseNotesConfig.d.ts +0 -26
- package/dist/esm/resolveReleaseNotesConfig.js +0 -29
- package/dist/esm/workTypesData.d.ts +0 -50
- package/dist/esm/workTypesData.js +0 -145
- package/schemas/label-map.json +0 -24
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
How to correct a generated changelog entry without rewriting history: where override files live, how they compose, how a key targets items, what an entry may set, and how to validate the files.
|
|
4
4
|
|
|
5
|
-
Generated changelogs occasionally need editorial correction
|
|
5
|
+
Generated changelogs occasionally need editorial correction: typos, redacted scope, reworded entries, or historical commits whose bodies contain verbatim PR-template scaffolding (`## What`, `## Why`, etc.) that renders as literal text in user-facing release notes. Rewriting git history is not viable, and any in-place edit to a version that release-kit renders in `CHANGELOG.md` or `.meta/changelog.json` is overwritten on the next release, because release-kit regenerates that version in both artifacts from its entries.
|
|
6
6
|
|
|
7
|
-
Override files are the supported escape hatch.
|
|
7
|
+
Override files are the supported escape hatch. Add a checked-in JSON file at the conventional path for the scope that it should affect, keyed by commit hash or by commit hash and entry position, and `release-kit prepare` applies the overrides between `buildChangelogEntries` and serialization. Both `CHANGELOG.md` and `.meta/changelog.json` reflect the post-override view, so downstream consumers (the GitHub Release body, the in-app release-notes page, etc.) see the same content.
|
|
8
8
|
|
|
9
9
|
## File-location convention
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ Override files are the supported escape hatch. Drop a checked-in JSON file at th
|
|
|
14
14
|
| Workspace | `packages/<ws>/.meta/changelog-overrides.json` | Only that workspace's changelog |
|
|
15
15
|
| Single-package mode | `.meta/changelog-overrides.json` | The package's changelog (collapses to the project case) |
|
|
16
16
|
|
|
17
|
-
Filenames have
|
|
17
|
+
Filenames don't have a leading dot, because the `.meta/` directory already provides the visibility property and parallels its sibling artifacts (`changelog.json`, `label-map.json`).
|
|
18
18
|
|
|
19
19
|
## Composition: per-key shadowing
|
|
20
20
|
|
|
@@ -22,18 +22,18 @@ When a workspace's changelog is rendered, both files are consulted:
|
|
|
22
22
|
|
|
23
23
|
- The root file's overrides apply globally.
|
|
24
24
|
- The workspace file's overrides apply only to that workspace.
|
|
25
|
-
- When the **same key** (string-equal, byte-for-byte) appears in both files, the **workspace entry wins entirely** for that workspace's changelog
|
|
25
|
+
- When the **same key** (string-equal, byte-for-byte) appears in both files, the **workspace entry wins entirely** for that workspace's changelog: release-kit doesn't merge the two entries field by field; the workspace entry replaces the root entry.
|
|
26
26
|
- Non-identical keys that match the same item, such as a root `abc1234` beside a workspace `abc1234:2`, or two prefixes of one commit, do **not** shadow. The run fails with the [overlapping-keys error](#conflicting-keys), which names both keys.
|
|
27
27
|
- Other keys in the root file still apply for that workspace.
|
|
28
28
|
|
|
29
|
-
The project-level changelog applies only the root file. Per-workspace files describe per-workspace editorial intent and have
|
|
29
|
+
The project-level changelog applies only the root file. Per-workspace files describe per-workspace editorial intent and don't have any meaning at the aggregated project tier.
|
|
30
30
|
|
|
31
31
|
## Stale-key warnings
|
|
32
32
|
|
|
33
33
|
A key that doesn't match any commit gets a stale-reference warning. The warning's scope mirrors the file's scope:
|
|
34
34
|
|
|
35
35
|
- **Per-workspace files** are warned against their own apply context. A key in `packages/foo/.meta/changelog-overrides.json` that doesn't match any commit in foo's changelog is unambiguously stale and is warned immediately.
|
|
36
|
-
- **Root file** keys are aggregated globally
|
|
36
|
+
- **Root file** keys are aggregated globally: A root key that matches in any workspace or in the project changelog is non-stale; a root key matched nowhere is warned exactly once after all batches complete.
|
|
37
37
|
|
|
38
38
|
## File shape
|
|
39
39
|
|
|
@@ -65,7 +65,7 @@ The top-level `$schema` key is optional and names the [published JSON Schema](#p
|
|
|
65
65
|
| `body` | `string` | Replaces the entry's body (the prose that renders below the bullet). Other fields are preserved. |
|
|
66
66
|
| `breaking` | `boolean` | Toggles the `🚨 **Breaking:** ` marker on the bullet. |
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
An override entry doesn't take a `migration` key: On a title-derived item the field is derived from `body`, so an override that replaces `body` re-derives it, and an item derived from a change-record entry keeps its entry's `migration`. See [The `migration` field](changelogs.md#the-migration-field).
|
|
69
69
|
|
|
70
70
|
## Keys
|
|
71
71
|
|
|
@@ -76,13 +76,13 @@ A key takes one of two forms. In both, the hash part is lowercase hex and matche
|
|
|
76
76
|
| `<hash>` | Every item of the commit |
|
|
77
77
|
| `<hash>:<n>` | The one item derived from the commit's `n`th change-record entry |
|
|
78
78
|
|
|
79
|
-
`n` counts from 1 over the `entries` of the commit's [change-record block](changelogs.md#change-record-blocks), in the order in which the PR lists them, including entries that yield
|
|
79
|
+
`n` counts from 1 over the `entries` of the commit's [change-record block](changelogs.md#change-record-blocks), in the order in which the PR lists them, including entries that don't yield an item. An item derived from the commit's title doesn't have an entry position, so `<hash>:<n>` never matches it. Any other key fails loading.
|
|
80
80
|
|
|
81
81
|
The hash part can be the full 40-character SHA or a prefix. `prepare` resolves it against the distinct commit hashes in the changelog:
|
|
82
82
|
|
|
83
|
-
- **One commit
|
|
84
|
-
- **No commit
|
|
85
|
-
- **Several commits
|
|
83
|
+
- **One commit**: The override applies to the items that the key targets. A 7-character prefix is usually unambiguous within a single repo's history; longer prefixes are always safe.
|
|
84
|
+
- **No commit**: The override is treated as a stale reference (probably from a rebase or branch deletion) and prepare reports a warning. The release continues. An ordinal key whose commit doesn't have an item at position `n` is stale in the same way.
|
|
85
|
+
- **Several commits**: The release aborts with an error naming the key and the matching hashes. Lengthen the prefix or use the full SHA.
|
|
86
86
|
|
|
87
87
|
### Conflicting keys
|
|
88
88
|
|
|
@@ -104,13 +104,13 @@ Suppose commit `3f0c9a1` merged a PR whose change record lists three entries. It
|
|
|
104
104
|
|
|
105
105
|
A bare `"3f0c9a1": { "audience": "skip" }` would skip all three items instead. Adding it beside the keys above fails the run, because it overlaps each of them.
|
|
106
106
|
|
|
107
|
-
Override application errors abort the run with a non-zero exit; warnings (zero-match keys) are non-fatal and
|
|
107
|
+
Override application errors abort the run with a non-zero exit; warnings (zero-match keys) are non-fatal and appear in `PrepareResult.warnings`.
|
|
108
108
|
|
|
109
109
|
## Validation
|
|
110
110
|
|
|
111
|
-
The override file is validated when `release-kit prepare` loads it. Each error names the offending key so
|
|
111
|
+
The override file is validated when `release-kit prepare` loads it. Each error names the offending key so that the developer can locate it in the file:
|
|
112
112
|
|
|
113
|
-
- Missing file → empty map, no error (the no-op default
|
|
113
|
+
- Missing file → empty map, no error (the no-op default: Projects that do not need overrides skip the file entirely).
|
|
114
114
|
- Malformed JSON → error.
|
|
115
115
|
- A key that is neither `<hash>` nor `<hash>:<n>` (uppercase hex, non-hex characters, `:0`, a leading zero in `n`) → error.
|
|
116
116
|
- A top-level `$schema` that is not a string → error.
|
|
@@ -118,7 +118,7 @@ The override file is validated when `release-kit prepare` loads it. Each error n
|
|
|
118
118
|
- Unknown fields on an entry → error.
|
|
119
119
|
- Wrong field types (e.g., `description` as a number) → error.
|
|
120
120
|
- An entry with no fields set → error (a copy-paste mistake more often than not).
|
|
121
|
-
- `audience: 'all'` or `audience: 'dev'` → error in the current release:
|
|
121
|
+
- `audience: 'all'` or `audience: 'dev'` → error in the current release: Only `'skip'` is supported (see below).
|
|
122
122
|
|
|
123
123
|
Applying the overrides then aborts the run on an ambiguous prefix and on either of the [conflicting-key conditions](#conflicting-keys): a bare key setting `description` or `body` on a commit with several items, and two keys matching the same item.
|
|
124
124
|
|
|
@@ -137,9 +137,9 @@ This walks every `.meta/changelog-overrides.json` file across the project tier a
|
|
|
137
137
|
| Schema/parse errors | malformed JSON, malformed keys, unknown fields, wrong field types, no-field entries, unsupported `audience` | `2` |
|
|
138
138
|
| Ambiguous-prefix | an override key resolves to 2+ commit hashes | `2` |
|
|
139
139
|
| Conflicting keys | a bare key sets `description` or `body` on a commit with several items; two keys match the same item | `2` |
|
|
140
|
-
| Stale-key warnings | an override key
|
|
140
|
+
| Stale-key warnings | an override key doesn't resolve to any item in its applicable scope | `1` |
|
|
141
141
|
|
|
142
|
-
Tier-aware stale-key semantics match `release-kit prepare`'s match-set exactly:
|
|
142
|
+
Tier-aware stale-key semantics match `release-kit prepare`'s match-set exactly: A workspace-tier key is stale if it does not match in its own workspace's history; a root-tier key is stale only if it doesn't match in **any** scope (neither any workspace nor the project release window).
|
|
143
143
|
|
|
144
144
|
Conflicting keys are found within one file and across the root and workspace files, as `prepare` composes them. An overlap between a root key and a workspace key is reported against the workspace file.
|
|
145
145
|
|
|
@@ -166,13 +166,13 @@ The schema states the key form and the entry fields. It accepts `audience` value
|
|
|
166
166
|
|
|
167
167
|
## Audience semantics: v1 supports `'skip'` only
|
|
168
168
|
|
|
169
|
-
The on-disk format declares the full `'all' | 'dev' | 'skip'` audience vocabulary so the file format will not need to change when the v2 reclassification feature
|
|
169
|
+
The on-disk format declares the full `'all' | 'dev' | 'skip'` audience vocabulary so that the file format will not need to change when the v2 reclassification feature is released. In the current release, only `'skip'` is supported at runtime; `'all'` and `'dev'` are rejected with an explicit "not yet supported" error.
|
|
170
170
|
|
|
171
|
-
The eventual v2 behavior will let an override move a single item to a different audience section (e.g., reclassifying a `Documentation` entry as `Internal features` to keep it out of public-facing release notes). v1 deliberately leaves that as a separate change so the override mechanism can
|
|
171
|
+
The eventual v2 behavior will let an override move a single item to a different audience section (e.g., reclassifying a `Documentation` entry as `Internal features` to keep it out of public-facing release notes). v1 deliberately leaves that as a separate change so that the override mechanism can be released now and the section-split logic can be added later.
|
|
172
172
|
|
|
173
173
|
## Worked example 1: cleaning up scaffolded historical commits (root file)
|
|
174
174
|
|
|
175
|
-
Suppose a year-old commit `82962311` was authored from a PR template that left `## What` / `## Why` headings in the body, and that commit now appears in
|
|
175
|
+
Suppose a year-old commit `82962311` was authored from a PR template that left `## What` / `## Why` headings in the body, and that commit now appears in the project's in-app release notes as literal Markdown headings. Add an override at the project tier:
|
|
176
176
|
|
|
177
177
|
```json
|
|
178
178
|
// .meta/changelog-overrides.json
|
|
@@ -187,9 +187,9 @@ On the next `release-kit prepare` run, the matched item's body is replaced befor
|
|
|
187
187
|
|
|
188
188
|
## Worked example 2: suppressing a cross-attribution spillover (workspace file)
|
|
189
189
|
|
|
190
|
-
Release-kit attributes commits to workspaces by file path, so a commit that primarily belongs to one workspace can
|
|
190
|
+
Release-kit attributes commits to workspaces by file path, so a commit that primarily belongs to one workspace can appear in another's changelog if it touched files there. Suppose commit `1ce3d2f` renamed the `audit-deps` package to `v11y-check` (scope `v11y-check`) but also edited `packages/nmr/src/default-scripts.ts` and `packages/nmr/README.md`. The commit correctly appears in `packages/v11y-check/CHANGELOG.md`, but it also appears in `packages/nmr/CHANGELOG.md`, where it isn't the right editorial framing.
|
|
191
191
|
|
|
192
|
-
|
|
192
|
+
Add a workspace-tier override at `packages/nmr/.meta/changelog-overrides.json`:
|
|
193
193
|
|
|
194
194
|
```json
|
|
195
195
|
// packages/nmr/.meta/changelog-overrides.json
|
|
@@ -200,4 +200,4 @@ Drop a workspace-tier override at `packages/nmr/.meta/changelog-overrides.json`:
|
|
|
200
200
|
}
|
|
201
201
|
```
|
|
202
202
|
|
|
203
|
-
The commit is now suppressed in nmr's changelog only
|
|
203
|
+
The commit is now suppressed in nmr's changelog only; it still appears in v11y-check's, where it belongs. A root-tier `'skip'` would have removed it from both, which is the wrong outcome.
|
package/docs/labels.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# Labels
|
|
2
2
|
|
|
3
|
-
How to declare the repository's labels in `.config/release-kit.config.ts`, how the scaffolded workflow applies them, and the
|
|
3
|
+
How to declare the repository's labels in `.config/release-kit.config.ts`, how the scaffolded workflow applies them, and where the schema for `.meta/label-map.json` is published.
|
|
4
4
|
|
|
5
5
|
## `release-kit sync-labels`
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Manages GitHub label definitions via the `repoLabels` block of `.config/release-kit.config.ts`.
|
|
8
8
|
|
|
9
|
-
`init` scaffolds the `.github/workflows/sync-labels.yaml` caller workflow and seeds a `repoLabels` block with scope labels discovered from workspaces and declared `retiredPackages`. When `.config/release-kit.config.ts` does not exist, `init` writes it; when it does, `init` prints the block for manual paste
|
|
9
|
+
`init` scaffolds the `.github/workflows/sync-labels.yaml` caller workflow and seeds a `repoLabels` block with scope labels discovered from workspaces and declared `retiredPackages`. When `.config/release-kit.config.ts` does not exist, `init` writes it; when it does, `init` prints the block for manual paste; a hand-authored config is never rewritten. `generate` resolves the block and writes `.github/labels.yaml`; with `--check` it regenerates in memory and exits non-zero if the committed file is stale or missing, writing nothing. `sync` triggers the workflow remotely; it requires the `gh` CLI and an existing workflow file.
|
|
10
10
|
|
|
11
11
|
`init` and `generate` accept `--config <path>` to read a config elsewhere; `sync` reads none and rejects the flag. Under `--config`, `init` reads the named file and prints the block for manual paste, and fails when that file does not exist rather than scaffolding one, so its write target stays `.config/release-kit.config.ts`. See [Config file location](configuration.md#config-file-location).
|
|
12
12
|
|
|
13
|
-
Every `sync-labels` subcommand refuses to run while the retired `.config/sync-labels.config.ts` is present, so custom labels cannot be silently dropped mid-migration, and the refusal names what to move and where.
|
|
13
|
+
Every `sync-labels` subcommand refuses to run while the retired `.config/sync-labels.config.ts` is present, so that custom labels cannot be silently dropped mid-migration, and the refusal names what to move and where.
|
|
14
14
|
|
|
15
15
|
### Label configuration
|
|
16
16
|
|
|
@@ -29,20 +29,36 @@ export default defineConfig({
|
|
|
29
29
|
});
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
The block declares the repository's label registry
|
|
32
|
+
The block declares the repository's label registry: the set of labels defined on the GitHub repo, distinct from labels applied to PRs and issues. Resolution is an ordered fold with last-writer-wins:
|
|
33
33
|
|
|
34
|
-
1. Presets, in `extends` order
|
|
35
|
-
2. The `labels` record
|
|
34
|
+
1. Presets, in `extends` order: A later preset wins on a shared name.
|
|
35
|
+
2. The `labels` record: An entry adds a label, replaces one that an earlier layer defined, or removes it (`null`). Replacement is wholesale: An entry omitting `description` resolves to a label without a description rather than inheriting the one that an earlier layer supplied.
|
|
36
|
+
|
|
37
|
+
The `common` preset defines a label for every work type in change-grammar's taxonomy, named by the type's `trackerLabel`, in addition to the labels in its bundled YAML file.
|
|
36
38
|
|
|
37
39
|
Names match case-insensitively, as GitHub matches them: `Bug` in the `labels` record replaces a preset's `bug`, and `Bug: null` removes it. A label takes the spelling of the last layer to write it.
|
|
38
40
|
|
|
39
41
|
`description` is optional throughout, in a preset as in the `labels` record, and `sync-labels init` generates none for a scope label. The generated file spells an absent description `''` because `github-label-sync` reads an omitted description as "leave the label's current one alone"; the empty form clears it.
|
|
40
42
|
|
|
41
|
-
Overlaps between layers are never errors; order resolves them, and the committed `.github/labels.yaml` diff
|
|
43
|
+
Overlaps between layers are never errors; order resolves them, and the committed `.github/labels.yaml` diff shows any unexpected change at review. Two misstatements are config errors, because neither is visible in the output diff: a dangling `null`, which removes a name not defined by any preset, and `labels` keys that differ only in case, all but one of which the fold would discard.
|
|
44
|
+
|
|
45
|
+
### Retiring a label
|
|
46
|
+
|
|
47
|
+
Mark a label `archived: true` to retire it without losing its history:
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
labels: {
|
|
51
|
+
'scope:basic': { color: '00ff96', archived: true }, // retire the scope of a removed package
|
|
52
|
+
},
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The sync workflow archives a marked label rather than deleting it. An archived label stays on the issues and pull requests that have it, but it cannot be added to new ones and does not appear in the label picker. Removing the mark unarchives the label on the next sync. Removing the entry instead deletes the label, as the sync deletes every label that `.github/labels.yaml` does not declare, and the label disappears from every issue and pull request that had it.
|
|
56
|
+
|
|
57
|
+
The mark is set only in the `labels` record, not in a preset. To retire a preset's label, replace it with an entry that restates its color and adds the mark.
|
|
42
58
|
|
|
43
59
|
### When labels are applied
|
|
44
60
|
|
|
45
|
-
The scaffolded workflow
|
|
61
|
+
The scaffolded workflow declares three triggers:
|
|
46
62
|
|
|
47
63
|
| Trigger | Job | Token | Effect |
|
|
48
64
|
| --------------------------------------------------------- | ------- | --------------- | --------------------------------- |
|
|
@@ -50,36 +66,38 @@ The scaffolded workflow carries three triggers:
|
|
|
50
66
|
| Manual dispatch (`release-kit sync-labels sync`) | `sync` | `issues: write` | Applies the labels |
|
|
51
67
|
| Pull request touching `.github/labels.yaml` | `check` | `issues: read` | Logs the diff without applying it |
|
|
52
68
|
|
|
53
|
-
Applying on merge closes the window in which a regenerated `.github/labels.yaml`
|
|
69
|
+
Applying on merge closes the window in which a regenerated `.github/labels.yaml` remains unapplied. In that window, a later manual dispatch would apply an unreviewed label set.
|
|
70
|
+
|
|
71
|
+
The `check` job runs the same sync in dry-run. Its **Label diff** log group lists every create, edit, rename, and deletion that the sync would perform, including deletions of labels that the file does not declare: the destructive edits that a diff of `.github/labels.yaml` alone cannot show, because a label created by hand or by another workflow is absent from the file both before and after. Read that log; the check reports success whether or not the diff is destructive, so a green check is not evidence that nothing will be deleted.
|
|
54
72
|
|
|
55
|
-
|
|
73
|
+
Its **Archive state** log group lists each label that the sync would archive or unarchive. Archiving runs after the rest of the sync, so a label that the file both adds and marks is created and then archived.
|
|
56
74
|
|
|
57
|
-
The two jobs are split because a job's permissions are fixed when the run is created and cannot vary by trigger. The split
|
|
75
|
+
The two jobs are split because a job's permissions are fixed when the run is created and cannot vary by trigger. The split keeps a write-scoped token out of pull-request runs.
|
|
58
76
|
|
|
59
|
-
The push trigger filters on the path alone; the `sync` job compares `github.ref_name` against the repository's default branch. The workflow therefore
|
|
77
|
+
The push trigger filters on the path alone; the `sync` job compares `github.ref_name` against the repository's default branch. The workflow therefore doesn't need a per-repo edit, whatever that branch is named, and a push touching `.github/labels.yaml` on any other branch produces a run whose jobs all skip.
|
|
60
78
|
|
|
61
79
|
Manual dispatch is not a preview. It matches the `sync` job, so it applies the labels, deletions included; only the pull-request path runs in dry-run.
|
|
62
80
|
|
|
63
81
|
### Dry-run checks on fork pull requests
|
|
64
82
|
|
|
65
|
-
GitHub issues a read-only `GITHUB_TOKEN` to pull requests from forks, and by default
|
|
83
|
+
GitHub issues a read-only `GITHUB_TOKEN` to pull requests from forks, and by default pauses runs from first-time contributors until a maintainer approves them. Because the dry-run reads labels and writes nothing, the check normally runs once approved. A repo that disables workflows on fork pull requests doesn't get a check at all; to preview such a change, push the branch to the base repo and open the pull request from there.
|
|
66
84
|
|
|
67
|
-
###
|
|
85
|
+
### JSON Schema for `.meta/label-map.json`
|
|
68
86
|
|
|
69
|
-
|
|
87
|
+
`.meta/label-map.json` is a separate, generic data file that maps commit-prefix scopes and types to GitHub label names. `@williamthorsen/change-grammar` publishes its JSON Schema, reachable via the stable raw URL:
|
|
70
88
|
|
|
71
89
|
```
|
|
72
|
-
https://github.com/williamthorsen/node-monorepo-tools/raw/
|
|
90
|
+
https://github.com/williamthorsen/node-monorepo-tools/raw/change-grammar-v<version>/packages/change-grammar/schemas/label-map.json
|
|
73
91
|
```
|
|
74
92
|
|
|
75
93
|
Consumers reference it from the top of their `.meta/label-map.json`:
|
|
76
94
|
|
|
77
95
|
```json
|
|
78
96
|
{
|
|
79
|
-
"$schema": "https://github.com/williamthorsen/node-monorepo-tools/raw/
|
|
97
|
+
"$schema": "https://github.com/williamthorsen/node-monorepo-tools/raw/change-grammar-v<version>/packages/change-grammar/schemas/label-map.json",
|
|
80
98
|
"types": { "feat": "feature", "fix": "fix" },
|
|
81
99
|
"scopes": { "audit": "scope:audit" }
|
|
82
100
|
}
|
|
83
101
|
```
|
|
84
102
|
|
|
85
|
-
release-kit
|
|
103
|
+
Earlier releases published the same schema from release-kit, and URLs under existing `release-kit-v*` tags keep resolving. release-kit does not generate `.meta/label-map.json`; change-grammar's `deriveLabelMap` derives one from the taxonomy and the workspace scopes.
|
package/docs/project-releases.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
How to add a project-level release to a monorepo, what the `project` block accepts, and how that release interacts with `prepare`'s flags.
|
|
4
4
|
|
|
5
|
-
Some monorepos
|
|
5
|
+
Some monorepos release a single combined deliverable, such as a Chrome extension, a CLI binary, or a packaged desktop app, for which the per-workspace tags and changelogs alone do not describe what the user actually receives. Declare the optional `project` block to add a project-level release stage that runs alongside the per-workspace pipeline.
|
|
6
6
|
|
|
7
7
|
```typescript
|
|
8
8
|
import type { ReleaseKitConfig } from '@williamthorsen/release-kit/config';
|
|
@@ -19,12 +19,12 @@ When configured, each `release-kit prepare` run additionally:
|
|
|
19
19
|
|
|
20
20
|
- Computes commits since the last project tag (`<tagPrefix><version>`), filtered to `paths` (by default, the union of every contributing workspace's paths).
|
|
21
21
|
- Bumps the root `package.json`'s `version` field using the same bump-derivation rules as workspaces (or the `--bump=...` override).
|
|
22
|
-
- Regenerates the root `./CHANGELOG.md` from the structured `ChangelogEntry[]` built from the project's release history (scoped to the project's `tagPrefix` and the same `paths`) and any matching editorial overrides.
|
|
22
|
+
- Regenerates the root `./CHANGELOG.md` from the structured `ChangelogEntry[]` built from the project's release history (scoped to the project's `tagPrefix` and the same `paths`) and any matching editorial overrides, keeping the [existing sections](changelogs.md#existing-changelogmd-sections) whose versions those entries lack.
|
|
23
23
|
- Emits `./.meta/changelog.json` (when `changelogJson.enabled`).
|
|
24
24
|
- With `--with-release-notes`, additionally emits `./docs/RELEASE_NOTES.v<version>.md`.
|
|
25
|
-
- Appends the project tag to `tmp/.release-tags` so `release-kit commit` and `release-kit tag` pick it up alongside per-workspace tags.
|
|
25
|
+
- Appends the project tag to `tmp/.release-tags` so that `release-kit commit` and `release-kit tag` pick it up alongside per-workspace tags.
|
|
26
26
|
|
|
27
|
-
If
|
|
27
|
+
If the history since the last project tag doesn't contain any commit under `paths`, the project release is silently skipped, as a per-workspace release is.
|
|
28
28
|
|
|
29
29
|
## `ProjectConfig`
|
|
30
30
|
|
|
@@ -37,14 +37,14 @@ interface ProjectConfig {
|
|
|
37
37
|
|
|
38
38
|
| Field | Default | Description |
|
|
39
39
|
| ----------- | ----------------------- | -------------------------------------------------------------------- |
|
|
40
|
-
| `paths` | Contributing-path union | Patterns selecting the commits the project release considers
|
|
40
|
+
| `paths` | Contributing-path union | Patterns selecting the commits that the project release considers |
|
|
41
41
|
| `tagPrefix` | `'v'` | Prefix for project tags. The full tag is `${tagPrefix}${newVersion}` |
|
|
42
42
|
|
|
43
|
-
By default the contributing workspaces are implicit:
|
|
43
|
+
By default the contributing workspaces are implicit: Every non-excluded discovered workspace contributes its `<dir>/**` glob, and the project release considers commits under their union.
|
|
44
44
|
|
|
45
|
-
Declare `paths` to choose the window
|
|
45
|
+
Declare `paths` to choose the window explicitly. Each entry is a git pathspec, which both the bump and the changelog read. A declared value **replaces** the workspace union rather than extending it: `paths: ['docs/**']` drops every workspace commit from the project release.
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
In a repo whose content lives at the root, commits don't match any `<dir>/**` glob, so the project release would skip every run. Such a repo declares the whole tree:
|
|
48
48
|
|
|
49
49
|
```typescript
|
|
50
50
|
const config: ReleaseKitConfig = {
|
|
@@ -60,15 +60,15 @@ Validation rules:
|
|
|
60
60
|
|
|
61
61
|
- The root `package.json` must exist and declare a `version` field. release-kit reports an error at config-load time if either is missing.
|
|
62
62
|
- The `project` block is rejected in single-package mode (the package's own release already covers the whole repo, so a project tier would only duplicate it).
|
|
63
|
-
- `paths`, when declared, must
|
|
63
|
+
- `paths`, when declared, must contain at least one non-empty string. An empty array is rejected, because git would read it as the absence of a filter: the inverse of how the array reads.
|
|
64
64
|
- Unknown fields inside `project` are rejected.
|
|
65
65
|
|
|
66
66
|
CLI flag interactions:
|
|
67
67
|
|
|
68
|
-
- `--dry-run` previews project artifacts alongside workspace artifacts;
|
|
69
|
-
- `--bump=major|minor|patch` propagates to the project release as a level chooser. It does not trigger a release on its own when
|
|
70
|
-
- `--force` runs the project release even when
|
|
71
|
-
- `--only` narrows the run to the named workspaces and skips the project release, which is reported as a warning. The project release rolls up every contributing workspace, and `--only` changes which workspaces those are, so rolling up a narrowed set would release a project version covering work the run excluded. Run a full `prepare` (
|
|
68
|
+
- `--dry-run` previews project artifacts alongside workspace artifacts; it doesn't write any files.
|
|
69
|
+
- `--bump=major|minor|patch` propagates to the project release as a level chooser. It does not trigger a release on its own when the window doesn't have any commits or any bump-worthy commits.
|
|
70
|
+
- `--force` runs the project release even when the history since the last project tag doesn't have any commits or any bump-worthy commits. Defaults to patch when `--bump` is not given; combine with `--bump=X` to release at a different level.
|
|
71
|
+
- `--only` narrows the run to the named workspaces and skips the project release, which is reported as a warning. The project release rolls up every contributing workspace, and `--only` changes which workspaces those are, so rolling up a narrowed set would release a project version covering work that the run excluded. Run a full `prepare` (without `--only`) to include the project release.
|
|
72
72
|
- `--set-version` is rejected with an error when `project` is configured. `--set-version` operates on a single workspace, but a project release rolls up every contributing workspace; the two semantics don't compose. To use `--set-version`, run on a config without a `project` block.
|
|
73
73
|
|
|
74
74
|
How `--bump` and `--force` combine for every target is in [Releasing](releasing.md#release-kit-prepare).
|
package/docs/publishing.md
CHANGED
|
@@ -4,16 +4,16 @@ How `release-kit publish` and `release-kit create-github-release` choose which p
|
|
|
4
4
|
|
|
5
5
|
## `release-kit publish`
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Publishes packages that have release tags on HEAD. The publish workflow's reusable workflow `publish.reusable.yaml` invokes this command in CI.
|
|
8
8
|
|
|
9
9
|
### Publishability filter
|
|
10
10
|
|
|
11
|
-
`publish` and `create-github-release` operate only on workspaces
|
|
11
|
+
`publish` and `create-github-release` operate only on workspaces whose `package.json#private` is absent or `false`. A workspace marked `private: true` is "versioned but not published": It can still be tagged by `release-kit tag` and get a `CHANGELOG.md` entry, but it is skipped by both `release-kit publish` (no registry publish) and `release-kit create-github-release` (no GitHub Release). `private: true` alone excludes a workspace from publish and announce; it doesn't require any extra release config. Other commands ignore this filter and operate on private workspaces unchanged.
|
|
12
12
|
|
|
13
13
|
An unpublishable tag is always skipped cleanly, never fatal. For `release-kit publish`, whether the skip is announced depends on how the tag was resolved:
|
|
14
14
|
|
|
15
|
-
- **Without `--tags`** (implicit resolution):
|
|
16
|
-
- **With `--tags`** (explicit naming):
|
|
15
|
+
- **Without `--tags`** (implicit resolution): Unpublishable tags on HEAD are silently filtered. The pre-publish listing shows only the publishable subset. If the filter empties the set, `release-kit publish` prints `Nothing to publish.` and exits 0.
|
|
16
|
+
- **With `--tags`** (explicit naming): Each named tag pointing at an unpublishable workspace is skipped with a warning, and any publishable tags named in the same command are still published.
|
|
17
17
|
|
|
18
18
|
`release-kit create-github-release` skips unpublishable workspaces with a warning regardless of `--tags`; an all-private tag set is a clean no-op.
|
|
19
19
|
|
|
@@ -25,6 +25,6 @@ Skipping basic-v1.0.0 (packages/basic): package.json#private is true.
|
|
|
25
25
|
|
|
26
26
|
## `release-kit create-github-release`
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
Creates GitHub Releases from `changelog.json` for tags on HEAD. Independent of `npm publish`: Invoking this command creates Releases for publishable packages whether or not they were published to a registry. Private workspaces are skipped (see [Publishability filter](#publishability-filter)).
|
|
29
29
|
|
|
30
30
|
When `--tags` is omitted, every release tag pointing at HEAD is processed. The CLI requires the `gh` CLI on `PATH` and `contents: write` permission. The bundled `create-github-release.reusable.yaml` GitHub Actions workflow runs this command in CI.
|
package/docs/readiness-checks.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
What release-kit's two readyup kits check, how to run each, and what `npm-auto-publish` needs from the npm session.
|
|
4
4
|
|
|
5
|
-
release-kit publishes two [readyup](https://www.npmjs.com/package/readyup) kits that check a consuming repo against the release it has installed:
|
|
5
|
+
release-kit publishes two [readyup](https://www.npmjs.com/package/readyup) kits that check a consuming repo against the release that it has installed: The `default` kit covers release-kit's own setup (workflows matching the current templates, config free of removed fields, sync-labels wiring), and `npm-auto-publish` covers a repo's OIDC-based npm publishing setup. Both are included in the package, so they check against the installed version rather than whatever a repository ref happens to point at, and a check added in a release becomes available to a repo when it upgrades.
|
|
6
6
|
|
|
7
7
|
The [README](../README.md#readiness-checks) shows how to name release-kit in the readyup config.
|
|
8
8
|
|
|
@@ -13,6 +13,6 @@ rdy run --from npm:@williamthorsen/release-kit npm-auto-publish # the npm-auto-
|
|
|
13
13
|
rdy list --from npm:@williamthorsen/release-kit # what release-kit publishes
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
`--packages` is the form that
|
|
16
|
+
`--packages` is the form that keeps working when release-kit publishes further kits.
|
|
17
17
|
|
|
18
|
-
`npm-auto-publish` queries the npm registry for each package's trusted publisher,
|
|
18
|
+
Because `npm-auto-publish` queries the npm registry for each package's trusted publisher, it needs an npm session elevated by two-factor authentication, and is meant to be invoked deliberately rather than included in an unattended run. A session that cannot answer those queries, whether it is missing a login, missing the elevation, or facing an unreachable registry, is reported once by the `npm session can answer trust queries` gate. The rows that would repeat the failed query are then skipped: the trusted-publisher rows in every case, and `published to npm` when the registry itself is unreachable. Each package's `package.json` checks report throughout, since they don't read a registry.
|
package/docs/releasing.md
CHANGED
|
@@ -1,31 +1,41 @@
|
|
|
1
1
|
# Releasing
|
|
2
2
|
|
|
3
|
-
How to scaffold the release workflows, what `release-kit prepare` does with its flags, and how the release workflow runs a release.
|
|
3
|
+
How to scaffold the release workflows and keep them up to date, what `release-kit prepare` does with its flags, and how the release workflow runs a release.
|
|
4
4
|
|
|
5
5
|
The [README](../README.md#quick-start) shows the first run.
|
|
6
6
|
|
|
7
7
|
## `release-kit init`
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Initializes release-kit in the current repository. By default, scaffolds only the GitHub Actions workflow files. Use `--with-config` to also scaffold configuration files.
|
|
10
10
|
|
|
11
11
|
Scaffolded files:
|
|
12
12
|
|
|
13
|
-
- `.github/workflows/create-github-release.yaml
|
|
14
|
-
- `.github/workflows/publish.yaml
|
|
15
|
-
- `.github/workflows/release.yaml
|
|
16
|
-
- `.config/release-kit.config.ts
|
|
13
|
+
- `.github/workflows/create-github-release.yaml`: Workflow that creates a GitHub Release on tag push, independent of npm publish
|
|
14
|
+
- `.github/workflows/publish.yaml`: Workflow that delegates to a reusable publish workflow
|
|
15
|
+
- `.github/workflows/release.yaml`: Workflow that delegates to a reusable release workflow
|
|
16
|
+
- `.config/release-kit.config.ts`: Starter config with commented-out customization examples (with `--with-config`)
|
|
17
|
+
|
|
18
|
+
## `release-kit update-templates`
|
|
19
|
+
|
|
20
|
+
Updates the scaffolded workflows to the templates of the installed release-kit version, and prints what changed in each file. Run it after upgrading release-kit; `--dry-run` previews the changes without writing them.
|
|
21
|
+
|
|
22
|
+
The workflows are managed files: release-kit renders them, and a change made by hand is overwritten on the next update. The config files are the repository's own, and the command never reads or writes them.
|
|
23
|
+
|
|
24
|
+
- It creates a missing workflow that `init` would create.
|
|
25
|
+
- It refreshes `.github/workflows/sync-labels.yaml` only when the file exists, because `sync-labels init` scaffolds it on request.
|
|
26
|
+
- It keeps `publish.yaml`'s provenance setting: When the file does not set `provenance: true`, as in a private repository, the updated file does not either.
|
|
17
27
|
|
|
18
28
|
## `release-kit prepare`
|
|
19
29
|
|
|
20
|
-
|
|
30
|
+
Runs release preparation with automatic workspace discovery.
|
|
21
31
|
|
|
22
32
|
Workspace names for `--only` match the package directory name (e.g., `arrays`, `release-kit`).
|
|
23
33
|
|
|
24
34
|
`prepare` reads each target's history once and builds the changelog items of its unreleased commits. The bump is the highest level that those items call for, under [`versionPatterns`](configuration.md#versionpatterns), so the bump and the changelog describe the same release: A `feat` entry in a [change-record block](changelogs.md#change-record-blocks) bumps minor under a `docs:` title, and a breaking item bumps major.
|
|
25
35
|
|
|
26
|
-
- A commit that
|
|
27
|
-
- A `BREAKING CHANGE:` footer
|
|
28
|
-
- A target whose commits yield
|
|
36
|
+
- A commit that doesn't yield an item doesn't bump anything: one without a ticket-ID prefix, one of a type excluded from the changelog (such as `fmt`), and one whose change-record entries are all undeclared or excluded.
|
|
37
|
+
- A `BREAKING CHANGE:` footer doesn't raise a major bump. Only a subject's `!` and an entry's `breaking: true` mark an item breaking; on a type whose policy forbids `!`, the footer is reported as a [policy violation](work-types.md#policy-enforcement).
|
|
38
|
+
- A target whose commits don't yield an item is skipped. The prepare report lists the commits that could not be parsed and the change-record diagnostics, skipped targets included.
|
|
29
39
|
|
|
30
40
|
`--bump` and `--force` are orthogonal in every mode, single-package included: `--bump` is purely a level chooser; `--force` is purely a release trigger. Examples:
|
|
31
41
|
|
|
@@ -33,16 +43,17 @@ Workspace names for `--only` match the package directory name (e.g., `arrays`, `
|
|
|
33
43
|
# Release every target at its natural bump level (no flags).
|
|
34
44
|
release-kit prepare
|
|
35
45
|
|
|
36
|
-
# Force a release even when
|
|
37
|
-
# patch per target, with each target keeping its natural bump
|
|
46
|
+
# Force a release even when the commits don't yield any changelog item;
|
|
47
|
+
# defaults to patch per target, with each target keeping its natural bump
|
|
48
|
+
# if it has one.
|
|
38
49
|
release-kit prepare --force
|
|
39
50
|
|
|
40
51
|
# Force a release at a uniform level across every releasing target.
|
|
41
52
|
release-kit prepare --force --bump=minor
|
|
42
53
|
|
|
43
|
-
# --bump=X alone is a level chooser, NOT a trigger. If
|
|
44
|
-
#
|
|
45
|
-
# the override applies.
|
|
54
|
+
# --bump=X alone is a level chooser, NOT a trigger. If a target's commits
|
|
55
|
+
# don't yield any changelog item, it skips with a "Pass --force..." reason.
|
|
56
|
+
# Otherwise the override applies.
|
|
46
57
|
release-kit prepare --bump=minor
|
|
47
58
|
```
|
|
48
59
|
|
|
@@ -50,10 +61,10 @@ release-kit prepare --bump=minor
|
|
|
50
61
|
|
|
51
62
|
`--with-release-notes` writes two versioned files per workspace after each workspace's `changelog.json` is produced:
|
|
52
63
|
|
|
53
|
-
- `<workspacePath>/docs/README.v<version>.md
|
|
54
|
-
- `<workspacePath>/docs/RELEASE_NOTES.v<version>.md
|
|
64
|
+
- `<workspacePath>/docs/README.v<version>.md`: The workspace `README.md` with release notes injected at the `<!-- section:release-notes -->` marker.
|
|
65
|
+
- `<workspacePath>/docs/RELEASE_NOTES.v<version>.md`: The standalone release notes for this version.
|
|
55
66
|
|
|
56
|
-
The publish-time inject-and-revert lifecycle is unchanged; previews are additive, deterministic, and safe to regenerate. When `changelogJson.enabled` is `false`, prepare reports a warning and skips preview generation. In dry-run mode, planned writes
|
|
67
|
+
The publish-time inject-and-revert lifecycle is unchanged; previews are additive, deterministic, and safe to regenerate. When `changelogJson.enabled` is `false`, prepare reports a warning and skips preview generation. In dry-run mode, prepare logs the planned writes and doesn't create any files.
|
|
57
68
|
|
|
58
69
|
Because preview filenames are versioned, committing them will accumulate files over time. The recommended `.gitignore` entry for monorepos is:
|
|
59
70
|
|
|
@@ -69,7 +80,7 @@ docs/*.v*.md
|
|
|
69
80
|
|
|
70
81
|
### Setting an explicit version with `--set-version`
|
|
71
82
|
|
|
72
|
-
The `--set-version` flag is a first-class escape hatch for the cases
|
|
83
|
+
The `--set-version` flag is a first-class escape hatch for the cases in which the derived bump produces the wrong version, most notably when promoting a pre-1.0 package to 1.0.0. Pre-1.0 packages collapse a `feat!` breaking change to a minor bump (matching semantic-release's `initialMajor: false` and release-please's `bump-minor-pre-major`), so a deliberate promotion to 1.0.0 must be requested explicitly.
|
|
73
84
|
|
|
74
85
|
The flag validates that:
|
|
75
86
|
|
|
@@ -85,17 +96,31 @@ Promoting a pre-1.0 package to 1.0.0 in a monorepo:
|
|
|
85
96
|
release-kit prepare --only arrays --set-version 1.0.0
|
|
86
97
|
```
|
|
87
98
|
|
|
88
|
-
An empty changelog section is expected for a bare promotion, because the changelog is generated from commits since the last tag. To include a narrative entry,
|
|
99
|
+
An empty changelog section is expected for a bare promotion, because the changelog is generated from commits since the last tag. To include a narrative entry, merge a descriptive release commit (e.g., a `feat!` describing the stable API) before running `prepare`.
|
|
100
|
+
|
|
101
|
+
### Adopting release-kit in a repo with untagged releases
|
|
102
|
+
|
|
103
|
+
`prepare` finds a target's previous release by its tag. When a target's current version was released and recorded in its `CHANGELOG.md` or `changelog.json` but never tagged, the unreleased window would extend back to the start of history: The new version would absorb every earlier commit, and its bump would be derived from all of them. `prepare` stops before writing anything instead, under `--force` and `--set-version` too, and names each target, its version, and the tag to create:
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
The current version is recorded in the changelog, but its tag is not the previous tag reachable from HEAD:
|
|
107
|
+
- workspace 'api': 1.2.0 (create tag api-v1.2.0)
|
|
108
|
+
Tag the commit that released each version, then run prepare again.
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Tag each named version at the commit that released it, then run `prepare` again. In a monorepo, `prepare` checks the project only after every workspace passes, so a second run can name the project's tag. The check skips a first release, whose version isn't recorded in any changelog, and a workspace that releases only through propagation.
|
|
112
|
+
|
|
113
|
+
Each new tag closes a release window. When that window's commits yield items, `prepare` renders the tagged version from them, in place of its hand-written section; it keeps every other hand-written version as [Existing `CHANGELOG.md` sections](changelogs.md#existing-changelogmd-sections) describes.
|
|
89
114
|
|
|
90
115
|
## GitHub Actions workflow
|
|
91
116
|
|
|
92
117
|
The `init` command scaffolds a release workflow at `.github/workflows/release.yaml` that delegates to a reusable release workflow. The scaffolded workflow accepts these inputs:
|
|
93
118
|
|
|
94
|
-
| Input | Type | Description
|
|
95
|
-
| ------- | ------- |
|
|
96
|
-
| `only` | string | Workspaces to release (comma-separated, leave empty for all)
|
|
97
|
-
| `bump` | choice |
|
|
98
|
-
| `force` | boolean | Release even when
|
|
119
|
+
| Input | Type | Description |
|
|
120
|
+
| ------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
121
|
+
| `only` | string | Workspaces to release (comma-separated, leave empty for all) |
|
|
122
|
+
| `bump` | choice | Bump type: `auto` (default, detects it from commits), `patch`, `minor`, or `major` |
|
|
123
|
+
| `force` | boolean | Release even when the window doesn't have any commits or any bump-worthy commits (defaults to patch; combine with `bump` for a different level) |
|
|
99
124
|
|
|
100
125
|
For repos that need a self-contained workflow instead of the reusable one, the scaffolded file can be expanded. The key steps are: checkout with full history (`fetch-depth: 0`), run `release-kit prepare` with optional `--only`, `--bump`, and `--force` flags, check for changes, read tags from `tmp/.release-tags`, then commit, tag, and push.
|
|
101
126
|
|