@williamthorsen/release-kit 10.6.0 โ†’ 10.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/.meta/changelog.json +96 -0
  2. package/.readyup/kits/default.js +17 -3
  3. package/.readyup/kits/npm-auto-publish.js +87 -23
  4. package/.readyup/manifest.json +9 -9
  5. package/CHANGELOG.md +61 -0
  6. package/README.md +53 -1010
  7. package/dist/esm/bin/release-kit.js +7 -6
  8. package/dist/esm/buildChangelogEntries.d.ts +1 -1
  9. package/dist/esm/buildChangelogEntries.js +14 -5
  10. package/dist/esm/buildDependencyGraph.d.ts +6 -5
  11. package/dist/esm/buildDependencyGraph.js +5 -1
  12. package/dist/esm/checkWorkTypesDrift.d.ts +2 -3
  13. package/dist/esm/checkWorkTypesDrift.js +1 -1
  14. package/dist/esm/init/scaffold.js +14 -6
  15. package/dist/esm/parseCommitMessage.d.ts +4 -5
  16. package/dist/esm/planVersionBump.d.ts +2 -1
  17. package/dist/esm/planVersionBump.js +4 -0
  18. package/dist/esm/propagateBumps.d.ts +1 -3
  19. package/dist/esm/propagateBumps.js +2 -2
  20. package/dist/esm/releasePrepare.js +0 -13
  21. package/dist/esm/releasePrepareMono.js +3 -20
  22. package/dist/esm/sync-labels/resolveLabels.d.ts +5 -3
  23. package/dist/esm/sync-labels/resolveLabels.js +21 -6
  24. package/dist/esm/types.d.ts +12 -9
  25. package/dist/esm/validateConfig.js +1 -1
  26. package/dist/esm/work-types.json +68 -52
  27. package/dist/esm/work-types.schema.json +12 -2
  28. package/dist/esm/workTypesData.d.ts +10 -9
  29. package/dist/esm/workTypesData.js +97 -11
  30. package/docs/api.md +73 -0
  31. package/docs/changelogs.md +70 -0
  32. package/docs/configuration.md +105 -0
  33. package/docs/editorial-overrides.md +144 -0
  34. package/docs/labels.md +83 -0
  35. package/docs/project-releases.md +74 -0
  36. package/docs/publishing.md +30 -0
  37. package/docs/readiness-checks.md +18 -0
  38. package/docs/releasing.md +108 -0
  39. package/docs/work-types.md +116 -0
  40. package/package.json +7 -4
  41. package/dist/esm/readCurrentVersion.d.ts +0 -2
  42. package/dist/esm/readCurrentVersion.js +0 -18
@@ -0,0 +1,116 @@
1
+ # Work types and tiers
2
+
3
+ The taxonomy against which release-kit parses commits: its tiers, the breaking-change policy, section markers, customization, and the commands that compare it with its upstream.
4
+
5
+ release-kit bundles a copy of the codeassembly canonical taxonomy in `packages/release-kit/src/work-types.json`, kept level by `release-kit work-types sync`. The taxonomy is split into three tiers that drive section rendering and audience classification.
6
+
7
+ | Tier | Key | Header | Aliases | `!` policy |
8
+ | -------- | ----------- | ------------------------- | ------------- | ------------ |
9
+ | public | `feat` | ๐ŸŽ‰ Features | `feature` | optional |
10
+ | public | `drop` | ๐Ÿชฆ Removed | | **required** |
11
+ | public | `deprecate` | ๐Ÿ—‘๏ธ Deprecated | | forbidden |
12
+ | public | `fix` | ๐Ÿ› Bug fixes | `bugfix` | optional |
13
+ | public | `sec` | ๐Ÿ”’ Security | `security` | optional |
14
+ | public | `perf` | โšก Performance | `performance` | optional |
15
+ | internal | `internal` | ๐Ÿ—๏ธ Internal features | `utility` | forbidden |
16
+ | internal | `refactor` | โ™ป๏ธ Refactoring | | forbidden |
17
+ | internal | `tests` | ๐Ÿงช Tests | `test` | forbidden |
18
+ | process | `tooling` | โš™๏ธ Tooling | | forbidden |
19
+ | process | `ci` | ๐Ÿ‘ท CI | | forbidden |
20
+ | process | `deps` | ๐Ÿ“ฆ Dependencies | `dep` | forbidden |
21
+ | process | `ai` | ๐Ÿค– Agentic support | | forbidden |
22
+ | process | `docs` | ๐Ÿ“š Documentation | `doc` | forbidden |
23
+ | process | `fmt` | (excluded from changelog) | | forbidden |
24
+
25
+ ## Tier semantics
26
+
27
+ - **`public`** โ€” visible to all audiences. `public`-tier sections appear in both public release notes and dev changelogs.
28
+ - **`internal`** โ€” dev-only. `internal`-tier sections appear in dev changelogs but not in public-facing release notes.
29
+ - **`process`** โ€” dev-only. Same audience treatment as `internal`.
30
+
31
+ Section render order is **tier order (`public` โ†’ `internal` โ†’ `process`), then row order within tier**. The bundled `cliff.toml.template` encodes this order via hidden `<!-- NN -->` HTML-comment prefixes on each parser's `group` value; tera's `group_by` filter sorts groups lexicographically (now monotonic by row number), and the body template's `striptags` filter erases the prefix from rendered headings.
32
+
33
+ ## `utility` alias
34
+
35
+ `utility:` is a backward-compat alias for `internal:`. Both forms parse to the same canonical type, route to the same `๐Ÿ—๏ธ Internal features` section, and are subject to the same `!` policy.
36
+
37
+ ## `!` (breaking change) policy
38
+
39
+ Each work-type carries a `breakingPolicy` value:
40
+
41
+ - `optional` (`feat`, `fix`, `sec`, `perf`): `!` is allowed; both `type:` and `type!:` parse cleanly. Any of these can break consumers, and the marker records when one does: A fix can break consumers who relied on the defective behavior, and a performance change can break a contract to achieve its gain.
42
+ - `forbidden` (`deprecate` and every `internal`- and `process`-tier type): `!` is a policy violation. Deprecating a surface keeps it working, and removing it is a `drop`. Internal- and process-tier work does not face consumers; a change that breaks consumers faces them and therefore takes a public-tier type.
43
+ - `required` (`drop`): Bare `drop:` is a policy violation; only `drop!:` is accepted. Removing a public surface always breaks consumers, and the `!` form makes that explicit.
44
+
45
+ ### Policy enforcement
46
+
47
+ `parseCommitMessage` enforces the `!` policy at release time and treats a violation as a warning. Commits already in the log cannot be rewritten, so a policy-violating commit is parsed using its canonical type with `breaking: false` (the `!` is dropped from the parse) and an `onPolicyViolation` callback fires. Callers (`decideRelease` etc.) can collect these warnings and surface them in the release report. A single legacy `internal!` in a year-old log does not block releases.
48
+
49
+ A `BREAKING CHANGE:` body footer on a `forbidden`-policy type triggers the same warning path as the prefix `!` does: A type that cannot be breaking is parsed as non-breaking whichever surface carries the signal.
50
+
51
+ The release-prepare orchestrators (`releasePrepare`, `releasePrepareMono`, `releasePrepareProject`) apply `DEFAULT_BREAKING_POLICIES` automatically. Violations encountered while parsing each workspace's or project's commit window are collected onto the corresponding result's `policyViolations` field and rendered under the section in the prepare report:
52
+
53
+ ```
54
+ arrays
55
+ Found 1 commits since arrays-v1.0.0
56
+ โš ๏ธ 1 policy violation:
57
+ ยท def5678 'internal!: refactor cache' โ€” type 'internal' at prefix surface
58
+ Bumping versions (patch)...
59
+ ๐Ÿ“ฆ 1.0.0 โ†’ 1.0.1 (patch)
60
+ ```
61
+
62
+ To customize, set `breakingPolicies` in `release-kit.config.ts`. The map replaces the default policies rather than merging with them, and the parser treats any type that the map omits as `'optional'`: A config that changes one type lists every policy that it keeps, and `{}` disables enforcement entirely. Violations remain warnings, never failures.
63
+
64
+ ## `๐Ÿšจ **Breaking:**` bullet marker
65
+
66
+ Items whose commit subject carries the `!` prefix (e.g. `feat!`, `drop!`, `feat(api)!`) on a type whose policy permits it are rendered with a `๐Ÿšจ **Breaking:** ` prefix on the bullet:
67
+
68
+ ```markdown
69
+ - ๐Ÿšจ **Breaking:** Drop legacy /v1 endpoint
70
+ ```
71
+
72
+ The marker agrees with the version bump:
73
+
74
+ - A `forbidden`-policy type carrying `!`, such as `refactor!`, gets no marker, just as its `!` raises no bump; the prepare report lists it as a policy violation. An [editorial override](editorial-overrides.md) that sets `breaking: true` restores the marker for one entry.
75
+ - The configured `breakingPolicies` map, `{}` included, decides which types permit the marker.
76
+ - A commit whose type the parser cannot resolve has no policy, so its `!` prefix alone decides.
77
+
78
+ A `BREAKING CHANGE:` body footer on its own does **not** retroactively mark a changelog item as breaking, even on a type whose policy permits `!`; the changelog signal is tied to the commit prefix. This avoids surprise breaking-marker appearances for older commits written under earlier conventions.
79
+
80
+ The emoji and label of this marker are sourced from the `markers.breaking` entry in `work-types.json` (see [Section markers](#section-markers)) so consumers that render their own breaking-changes section draw from the same SSOT.
81
+
82
+ ## Section markers
83
+
84
+ Alongside `tiers` and `types`, `work-types.json` exposes a top-level `markers` object for cross-cutting section markers โ€” visual indicators that aren't tied to a specific work type. Today the canonical entry is `breaking`; additional keys (e.g., security advisories, migration notices) can be added without a schema change.
85
+
86
+ ```jsonc
87
+ {
88
+ "markers": {
89
+ "breaking": { "emoji": "๐Ÿšจ", "label": "Breaking" },
90
+ },
91
+ }
92
+ ```
93
+
94
+ Entries store plain text only โ€” the SSOT is format-agnostic, so consumers apply their own emphasis (Markdown bold, ANSI escape, HTML `<strong>`) when constructing the rendered form. release-kit's own renderer constructs the per-bullet prefix as `${emoji} **${label}:** ` from this entry.
95
+
96
+ ## `fmt`
97
+
98
+ `fmt:` commits are recognized by `parseCommitMessage` (they contribute to a patch bump) but `fmt` carries `excludedFromChangelog: true`. The bundled `cliff.toml.template` skips `fmt:` commits at the parser level, so they never appear in `CHANGELOG.md`, `changelog.json`, or release notes. The label and emoji are present in `work-types.json` for schema parity with the codeassembly upstream but never render.
99
+
100
+ ## Custom work types
101
+
102
+ Work types from your config are merged with these defaults by key โ€” your entries override or extend, they don't replace the full set. Release-notes sections are rendered in the declaration order of the merged work-types record, with any unknown titles trailing the known ones.
103
+
104
+ The default `devOnlySections` (excluded from public release notes but still written to `CHANGELOG.md`) are derived from the `internal` and `process` tiers (excluding `fmt`). Override via `changelogJson.devOnlySections` in your config; matching is decorator-tolerant, so a bare-name override like `['Internal features']` keeps working against the emoji-prefixed and prefix-decorated default titles.
105
+
106
+ ## `release-kit work-types`
107
+
108
+ Manage the canonical work-types taxonomy used by changelog and release-notes generation.
109
+
110
+ `check` exits 0 on a match, 1 on drift, 2 when the upstream fetch fails, and 3 when either file is not valid JSON or the upstream fails the shape check. When the upstream URL returns 404, `check` exits 0 with a warning.
111
+
112
+ These commands are also exposed as `nmr work-types:check` / `nmr work-types:sync` from any package directory.
113
+
114
+ ### Authenticated fetches
115
+
116
+ The upstream codeassembly repo is public, so `check` and `sync` need no token. When `GITHUB_TOKEN` is set in the environment, both commands send it as `Authorization: Bearer <token>`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@williamthorsen/release-kit",
3
- "version": "10.6.0",
3
+ "version": "10.8.0",
4
4
  "description": "Version-bumping and changelog-generation toolkit for release workflows",
5
5
  "keywords": [
6
6
  "changelog",
@@ -45,11 +45,13 @@
45
45
  "bin",
46
46
  "cliff.toml.template",
47
47
  "dist/*",
48
+ "docs",
49
+ "!docs/*.v*.md",
48
50
  "presets/**",
49
51
  "schemas/**"
50
52
  ],
51
53
  "dependencies": {
52
- "@williamthorsen/nmr-core": "0.11.0",
54
+ "@williamthorsen/nmr-core": "0.11.1",
53
55
  "@williamthorsen/toolbelt.errors": "0.7.0",
54
56
  "glob": "13.0.6",
55
57
  "json-stringify-pretty-compact": "4.0.0",
@@ -62,8 +64,9 @@
62
64
  "@williamthorsen/toolbelt.filesystem": "0.8.3",
63
65
  "@williamthorsen/toolbelt.testing": "0.5.1",
64
66
  "@williamthorsen/toolbelt.vitest": "0.9.0",
65
- "readyup": "0.35.0",
66
- "smol-toml": "1.8.0"
67
+ "readyup": "0.36.0",
68
+ "smol-toml": "1.8.0",
69
+ "vitest": "4.1.11"
67
70
  },
68
71
  "engines": {
69
72
  "node": ">=24"
@@ -1,2 +0,0 @@
1
- /** Read the `version` field from a package.json file. Returns undefined if the file can't be read or parsed. */
2
- export declare function readCurrentVersion(filePath: string): string | undefined;
@@ -1,18 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- import { describeError } from '@williamthorsen/toolbelt.errors';
3
- function hasVersionField(value) {
4
- return typeof value === 'object' && value !== null && 'version' in value && typeof value.version === 'string';
5
- }
6
- export function readCurrentVersion(filePath) {
7
- try {
8
- const content = readFileSync(filePath, 'utf8');
9
- const parsed = JSON.parse(content);
10
- if (hasVersionField(parsed)) {
11
- return parsed.version;
12
- }
13
- }
14
- catch (error) {
15
- console.warn(`Failed to read current version from ${filePath}: ${describeError(error)}`);
16
- }
17
- return undefined;
18
- }