@williamthorsen/release-kit 10.9.0 → 12.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.meta/changelog.json +119 -2
- package/.readyup/kits/default.js +1 -17
- package/.readyup/kits/npm-auto-publish.js +42 -22
- package/.readyup/manifest.json +7 -7
- package/CHANGELOG.md +88 -0
- package/README.md +32 -32
- package/dist/esm/attachChangelogDiagnostics.d.ts +4 -0
- package/dist/esm/attachChangelogDiagnostics.js +11 -0
- package/dist/esm/bin/release-kit.js +34 -25
- package/dist/esm/buildChangelogEntries.d.ts +59 -17
- package/dist/esm/buildChangelogEntries.js +195 -111
- package/dist/esm/buildReleaseSummary.js +2 -2
- package/dist/esm/changelogOverrides.d.ts +31 -13
- package/dist/esm/changelogOverrides.js +138 -58
- package/dist/esm/classifyChangelogCommit.d.ts +38 -0
- package/dist/esm/classifyChangelogCommit.js +33 -0
- package/dist/esm/configFlagSchema.d.ts +12 -0
- package/dist/esm/configFlagSchema.js +3 -0
- package/dist/esm/createGithubReleaseCommand.js +6 -2
- package/dist/esm/decideRelease.d.ts +11 -37
- package/dist/esm/decideRelease.js +5 -27
- package/dist/esm/defaults.d.ts +1 -1
- package/dist/esm/defaults.js +3 -0
- package/dist/esm/determineBumpType.d.ts +11 -11
- package/dist/esm/determineBumpType.js +6 -7
- package/dist/esm/discoverWorkspaces.d.ts +53 -8
- package/dist/esm/discoverWorkspaces.js +57 -37
- package/dist/esm/enumerateReleaseWindows.d.ts +50 -0
- package/dist/esm/enumerateReleaseWindows.js +124 -0
- package/dist/esm/generateChangelogs.d.ts +5 -23
- package/dist/esm/generateChangelogs.js +0 -14
- package/dist/esm/glyphs.d.ts +1 -1
- package/dist/esm/help/prepareHelp.d.ts +1 -1
- package/dist/esm/help/prepareHelp.js +5 -6
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/init/initCommand.js +1 -1
- package/dist/esm/init/scaffold.d.ts +0 -2
- package/dist/esm/init/scaffold.js +2 -30
- package/dist/esm/loadConfig.d.ts +8 -5
- package/dist/esm/loadConfig.js +7 -7
- package/dist/esm/loadValidatedConfig.d.ts +46 -5
- package/dist/esm/loadValidatedConfig.js +32 -15
- package/dist/esm/parseChangeRecordBlock.d.ts +37 -0
- package/dist/esm/parseChangeRecordBlock.js +134 -0
- package/dist/esm/parseCommitMessage.d.ts +31 -6
- package/dist/esm/parseCommitMessage.js +6 -5
- package/dist/esm/prepareCommand.d.ts +5 -0
- package/dist/esm/prepareCommand.js +30 -47
- package/dist/esm/previewTagPrefixes.d.ts +9 -6
- package/dist/esm/previewTagPrefixes.js +12 -24
- package/dist/esm/publishCommand.d.ts +2 -2
- package/dist/esm/publishCommand.js +8 -2
- package/dist/esm/pushCommand.d.ts +1 -1
- package/dist/esm/pushCommand.js +2 -2
- package/dist/esm/releasePrepare.d.ts +7 -8
- package/dist/esm/releasePrepare.js +53 -73
- package/dist/esm/releasePrepareMono.js +48 -85
- package/dist/esm/releasePrepareProject.d.ts +1 -1
- package/dist/esm/releasePrepareProject.js +19 -37
- package/dist/esm/reportPrepare.js +45 -30
- package/dist/esm/resolveCommandTags.d.ts +3 -2
- package/dist/esm/resolveCommandTags.js +10 -6
- package/dist/esm/resolveReleaseNotesConfig.d.ts +9 -11
- package/dist/esm/resolveReleaseNotesConfig.js +9 -28
- package/dist/esm/showTagPrefixesCommand.d.ts +4 -2
- package/dist/esm/showTagPrefixesCommand.js +17 -3
- package/dist/esm/sync-labels/generateCommand.d.ts +16 -8
- package/dist/esm/sync-labels/generateCommand.js +12 -11
- package/dist/esm/sync-labels/initCommand.d.ts +9 -4
- package/dist/esm/sync-labels/initCommand.js +21 -15
- package/dist/esm/sync-labels/retiredConfig.d.ts +4 -2
- package/dist/esm/sync-labels/retiredConfig.js +2 -2
- package/dist/esm/types.d.ts +99 -55
- package/dist/esm/types.js +1 -1
- package/dist/esm/validateConfig.js +4 -0
- package/dist/esm/validateOverridesCommand.d.ts +16 -9
- package/dist/esm/validateOverridesCommand.js +39 -54
- package/docs/changelogs.md +64 -25
- package/docs/configuration.md +14 -3
- package/docs/editorial-overrides.md +75 -16
- package/docs/labels.md +2 -0
- package/docs/project-releases.md +4 -4
- package/docs/releasing.md +13 -8
- package/docs/work-types.md +13 -9
- package/package.json +5 -7
- package/schemas/changelog-overrides.json +39 -0
- package/cliff.toml.template +0 -65
- package/dist/esm/collectPolicyViolations.d.ts +0 -15
- package/dist/esm/collectPolicyViolations.js +0 -12
- package/dist/esm/determineBumpFromCommits.d.ts +0 -17
- package/dist/esm/determineBumpFromCommits.js +0 -28
- package/dist/esm/getCommitsSinceTarget.d.ts +0 -21
- package/dist/esm/getCommitsSinceTarget.js +0 -66
- package/dist/esm/resolveCliffConfigPath.d.ts +0 -11
- package/dist/esm/resolveCliffConfigPath.js +0 -20
- package/dist/esm/runGitCliff.d.ts +0 -38
- package/dist/esm/runGitCliff.js +0 -25
package/docs/work-types.md
CHANGED
|
@@ -28,7 +28,11 @@ release-kit bundles a copy of the codeassembly canonical taxonomy in `packages/r
|
|
|
28
28
|
- **`internal`** — dev-only. `internal`-tier sections appear in dev changelogs but not in public-facing release notes.
|
|
29
29
|
- **`process`** — dev-only. Same audience treatment as `internal`.
|
|
30
30
|
|
|
31
|
-
Section render order is **tier order (`public` → `internal` → `process`), then row order within tier**.
|
|
31
|
+
Section render order is **tier order (`public` → `internal` → `process`), then row order within tier**. It comes from the declaration order of `work-types.json`: `CANONICAL_SECTION_ORDER` in `buildChangelogEntries.ts` indexes each header by its row, and `transformReleases` sorts a release's sections by that index whatever order the commits arrived in.
|
|
32
|
+
|
|
33
|
+
## Subject forms
|
|
34
|
+
|
|
35
|
+
`classifyChangelogCommit` resolves a commit's type through `parseCommitMessage`, so a subject reaches its section under any form that parser accepts: `type:`, `scope|type:`, and the conventional-commit `type(scope):`. The type is matched case-insensitively, so `Feat:` and `FEAT:` resolve like `feat:`. The ticket-ID prefix is still required, and an alias resolves before the section is chosen. A commit whose [change-record block](changelogs.md#change-record-blocks) records entries takes its sections from the entries' types instead of from its subject.
|
|
32
36
|
|
|
33
37
|
## `utility` alias
|
|
34
38
|
|
|
@@ -44,11 +48,11 @@ Each work-type carries a `breakingPolicy` value:
|
|
|
44
48
|
|
|
45
49
|
### Policy enforcement
|
|
46
50
|
|
|
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.
|
|
51
|
+
`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. `readReleaseHistory` collects these warnings while it builds the items of the unreleased window, and the release report lists them. A single legacy `internal!` in a year-old log does not block releases.
|
|
48
52
|
|
|
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.
|
|
53
|
+
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. The warning is all that a footer triggers; it raises no bump (see [`🚨 **Breaking:**` bullet marker](#-breaking-bullet-marker)).
|
|
50
54
|
|
|
51
|
-
The release-prepare orchestrators (`releasePrepare`, `releasePrepareMono`, `releasePrepareProject`) apply `DEFAULT_BREAKING_POLICIES` automatically. Violations
|
|
55
|
+
The release-prepare orchestrators (`releasePrepare`, `releasePrepareMono`, `releasePrepareProject`) apply `DEFAULT_BREAKING_POLICIES` automatically. Violations in the titles and change-record entries of each workspace's or project's unreleased window are collected onto the corresponding result's `policyViolations` field, on a skipped result as on a released one, and rendered under the section in the prepare report:
|
|
52
56
|
|
|
53
57
|
```
|
|
54
58
|
arrays
|
|
@@ -73,9 +77,9 @@ The marker agrees with the version bump:
|
|
|
73
77
|
|
|
74
78
|
- 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
79
|
- The configured `breakingPolicies` map, `{}` included, decides which types permit the marker.
|
|
76
|
-
- A commit whose type the parser cannot resolve
|
|
80
|
+
- A commit whose type the parser cannot resolve reaches no changelog at all, so no marker question arises.
|
|
77
81
|
|
|
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.
|
|
82
|
+
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. The bump follows the items, so a footer raises no major bump either: A consumer that marks breaking changes with the footer alone gets the bump of the commit's type.
|
|
79
83
|
|
|
80
84
|
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
85
|
|
|
@@ -95,13 +99,13 @@ Entries store plain text only — the SSOT is format-agnostic, so consumers appl
|
|
|
95
99
|
|
|
96
100
|
## `fmt`
|
|
97
101
|
|
|
98
|
-
`fmt:` commits are recognized by `parseCommitMessage
|
|
102
|
+
`fmt:` commits are recognized by `parseCommitMessage`, but `fmt` carries `excludedFromChangelog: true`, which `DEFAULT_WORK_TYPES` carries onto its `WorkTypeConfig`. `classifyChangelogCommit` excludes a commit whose type sets the flag, so a `fmt:` commit never appears in `CHANGELOG.md`, `changelog.json`, or release notes. It yields no item, so it raises no bump, and the release report does not list it as unparseable. The label and emoji are present in `work-types.json` for schema parity with the codeassembly upstream but never render.
|
|
99
103
|
|
|
100
104
|
## Custom work types
|
|
101
105
|
|
|
102
|
-
Work types from
|
|
106
|
+
Work types from a config are merged with these defaults by key: a consumer entry overrides or extends, it does not replace the full set. `classifyChangelogCommit` reads the merged record, so an added type reaches the changelog under the `header` it declares, and an entry setting `excludedFromChangelog: true` keeps its commits out of the changelog and the bump. Release-notes sections are rendered in the declaration order of the merged work-types record, with any unknown titles trailing the known ones.
|
|
103
107
|
|
|
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
|
|
108
|
+
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`; matching is decorator-tolerant, so a bare-name override like `['Internal features']` keeps working against the emoji-prefixed default titles.
|
|
105
109
|
|
|
106
110
|
## Maintaining the bundled taxonomy
|
|
107
111
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@williamthorsen/release-kit",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "12.0.0",
|
|
4
4
|
"description": "Version-bumping and changelog-generation toolkit for release workflows",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"changelog",
|
|
@@ -43,7 +43,6 @@
|
|
|
43
43
|
".readyup/manifest.json",
|
|
44
44
|
"CHANGELOG.md",
|
|
45
45
|
"bin",
|
|
46
|
-
"cliff.toml.template",
|
|
47
46
|
"dist/*",
|
|
48
47
|
"docs",
|
|
49
48
|
"!docs/*.v*.md",
|
|
@@ -51,13 +50,12 @@
|
|
|
51
50
|
"schemas/**"
|
|
52
51
|
],
|
|
53
52
|
"dependencies": {
|
|
54
|
-
"@williamthorsen/nmr-core": "0.
|
|
53
|
+
"@williamthorsen/nmr-core": "0.13.0",
|
|
55
54
|
"@williamthorsen/toolbelt.errors": "0.8.1",
|
|
56
|
-
"glob": "13.0.6",
|
|
57
55
|
"json-stringify-pretty-compact": "4.0.0",
|
|
58
56
|
"semver": "7.8.5",
|
|
59
|
-
"yaml": "2.9.
|
|
60
|
-
"zod": "4.6.
|
|
57
|
+
"yaml": "2.9.1",
|
|
58
|
+
"zod": "4.6.5"
|
|
61
59
|
},
|
|
62
60
|
"devDependencies": {
|
|
63
61
|
"@types/semver": "7.8.0",
|
|
@@ -69,7 +67,7 @@
|
|
|
69
67
|
"vitest": "4.1.11"
|
|
70
68
|
},
|
|
71
69
|
"engines": {
|
|
72
|
-
"node": ">=24"
|
|
70
|
+
"node": ">=24.16.0"
|
|
73
71
|
},
|
|
74
72
|
"publishConfig": {
|
|
75
73
|
"access": "public",
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "changelog-overrides",
|
|
4
|
+
"description": "Editorial overrides that release-kit applies to generated changelog items. Each key is a lowercase hex commit hash or prefix, which targets every item of the commit, optionally followed by `:<n>`, which targets the item derived from the commit's `n`th change-record entry.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"properties": {
|
|
8
|
+
"$schema": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "JSON Schema reference for editor support."
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"patternProperties": {
|
|
14
|
+
"^[0-9a-f]+(:[1-9][0-9]*)?$": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"description": "Override for the items that the key targets. At least one field must be set.",
|
|
17
|
+
"additionalProperties": false,
|
|
18
|
+
"minProperties": 1,
|
|
19
|
+
"properties": {
|
|
20
|
+
"audience": {
|
|
21
|
+
"enum": ["all", "dev", "skip"],
|
|
22
|
+
"description": "`skip` removes the items. `all` and `dev` are reserved and not yet supported."
|
|
23
|
+
},
|
|
24
|
+
"description": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"description": "Replaces the item's headline."
|
|
27
|
+
},
|
|
28
|
+
"body": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"description": "Replaces the item's body."
|
|
31
|
+
},
|
|
32
|
+
"breaking": {
|
|
33
|
+
"type": "boolean",
|
|
34
|
+
"description": "Sets whether the item is marked as breaking."
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
package/cliff.toml.template
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# git-cliff configuration
|
|
2
|
-
# Generates changelogs from conventional-ish commit messages.
|
|
3
|
-
#
|
|
4
|
-
# Commit format: [ticket-prefix ]scope|type[!]: description [#PR]
|
|
5
|
-
# Examples:
|
|
6
|
-
# #19 rdy|feat: Add utility functions for common check patterns (#26)
|
|
7
|
-
# AFG-42 panel|fix: Fix button layout (#73)
|
|
8
|
-
# ## feat: Quick utility added during interactive session
|
|
9
|
-
#
|
|
10
|
-
# Only ticketed commits (leading #NN, PROJ-NN, or ##) are included.
|
|
11
|
-
# Unticketed maintenance commits (deps upgrades, tooling tweaks) are skipped.
|
|
12
|
-
# Use ## as a synthetic ticket prefix for ad-hoc commits that belong in the changelog.
|
|
13
|
-
#
|
|
14
|
-
# Section order: each `group` value carries a hidden `<!-- NN -->` HTML-comment
|
|
15
|
-
# prefix encoding the canonical row position. tera's `group_by` filter sorts
|
|
16
|
-
# groups lexicographically by string, and the body template's `striptags`
|
|
17
|
-
# filter erases the comment from the rendered heading. Numbering is per
|
|
18
|
-
# unique group (not per parser entry) — all parsers routing to the same group
|
|
19
|
-
# share the same prefix.
|
|
20
|
-
|
|
21
|
-
# Markdown rendering is handled in-process by `renderChangelogMarkdown.ts`. cliff is invoked
|
|
22
|
-
# only for `--context` JSON output (see `buildChangelogEntries.ts`), so no `[changelog]` block
|
|
23
|
-
# is needed. The `[git].commit_parsers` section below remains load-bearing for group
|
|
24
|
-
# assignment in the `--context` payload.
|
|
25
|
-
|
|
26
|
-
[git]
|
|
27
|
-
conventional_commits = false
|
|
28
|
-
filter_unconventional = false
|
|
29
|
-
split_commits = false
|
|
30
|
-
commit_preprocessors = []
|
|
31
|
-
# Require a ticket-ID prefix for inclusion.
|
|
32
|
-
# Supported prefixes: "#123 ", "#123-1 ", "#123.1 ", "TOOL-123 ", "## "
|
|
33
|
-
commit_parsers = [
|
|
34
|
-
{ message = "^release:", skip = true },
|
|
35
|
-
{ message = "^Merge", skip = true },
|
|
36
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?feat(!)?:", group = "<!-- 01 -->🎉 Features" },
|
|
37
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?feature(!)?:", group = "<!-- 01 -->🎉 Features" },
|
|
38
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?drop(!)?:", group = "<!-- 02 -->🪦 Removed" },
|
|
39
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?deprecate(!)?:", group = "<!-- 03 -->🗑️ Deprecated" },
|
|
40
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?fix(!)?:", group = "<!-- 04 -->🐛 Bug fixes" },
|
|
41
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?bugfix(!)?:", group = "<!-- 04 -->🐛 Bug fixes" },
|
|
42
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?sec(!)?:", group = "<!-- 05 -->🔒 Security" },
|
|
43
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?security(!)?:", group = "<!-- 05 -->🔒 Security" },
|
|
44
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?perf(!)?:", group = "<!-- 06 -->⚡ Performance" },
|
|
45
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?performance(!)?:", group = "<!-- 06 -->⚡ Performance" },
|
|
46
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?internal(!)?:", group = "<!-- 07 -->🏗️ Internal features" },
|
|
47
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?utility(!)?:", group = "<!-- 07 -->🏗️ Internal features" },
|
|
48
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?refactor(!)?:", group = "<!-- 08 -->♻️ Refactoring" },
|
|
49
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?tests?(!)?:", group = "<!-- 09 -->🧪 Tests" },
|
|
50
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?tooling(!)?:", group = "<!-- 10 -->⚙️ Tooling" },
|
|
51
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?ci(!)?:", group = "<!-- 11 -->👷 CI" },
|
|
52
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?deps?(!)?:", group = "<!-- 12 -->📦 Dependencies" },
|
|
53
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?ai(!)?:", group = "<!-- 13 -->🤖 Agentic support" },
|
|
54
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?docs?(!)?:", group = "<!-- 14 -->📚 Documentation" },
|
|
55
|
-
{ message = "^(\\#\\d+([.\\-]\\d+)?|\\#\\#|[A-Z]+-\\d+)\\s+([^|]+\\|)?fmt(!)?:", skip = true },
|
|
56
|
-
# Skip unticketed commits (maintenance, deps, initial scaffolding, etc.)
|
|
57
|
-
{ message = ".*", skip = true },
|
|
58
|
-
]
|
|
59
|
-
protect_breaking_commits = false
|
|
60
|
-
filter_commits = true
|
|
61
|
-
tag_pattern = "v[0-9].*"
|
|
62
|
-
skip_tags = ""
|
|
63
|
-
ignore_tags = ""
|
|
64
|
-
topo_order = false
|
|
65
|
-
sort_commits = "oldest"
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { PolicyViolationHandler } from './parseCommitMessage.js';
|
|
2
|
-
import type { PolicyViolation } from './types.js';
|
|
3
|
-
/**
|
|
4
|
-
* Build a fresh `policyViolations` accumulator paired with the `onPolicyViolation` callback
|
|
5
|
-
* that pushes structured entries into it.
|
|
6
|
-
*
|
|
7
|
-
* Used by all three release-prepare orchestrators (`releasePrepare`, `releasePrepareMono`,
|
|
8
|
-
* `releasePrepareProject`) to collect parser-side `!`-policy violations into a result-attachable
|
|
9
|
-
* array. Centralizing the callback shape keeps the `commitSubject` extraction rule (`firstLine
|
|
10
|
-
* post-split`) consistent across orchestrators.
|
|
11
|
-
*/
|
|
12
|
-
export declare function createPolicyViolationCollector(): {
|
|
13
|
-
violations: PolicyViolation[];
|
|
14
|
-
onPolicyViolation: PolicyViolationHandler;
|
|
15
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export function createPolicyViolationCollector() {
|
|
2
|
-
const violations = [];
|
|
3
|
-
const onPolicyViolation = (commit, type, surface) => {
|
|
4
|
-
violations.push({
|
|
5
|
-
commitHash: commit.hash,
|
|
6
|
-
commitSubject: commit.message.split('\n', 1)[0] ?? '',
|
|
7
|
-
type,
|
|
8
|
-
surface,
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
return { violations, onPolicyViolation };
|
|
12
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { type PolicyViolationHandler } from './parseCommitMessage.js';
|
|
2
|
-
import type { Commit, ReleaseType, VersionPatterns, WorkTypeConfig } from './types.js';
|
|
3
|
-
/** Aggregate result of parsing commits and determining the bump type. */
|
|
4
|
-
export interface BumpDetermination {
|
|
5
|
-
releaseType: ReleaseType | undefined;
|
|
6
|
-
parsedCommitCount: number;
|
|
7
|
-
unparseableCommits: Commit[] | undefined;
|
|
8
|
-
}
|
|
9
|
-
/** Optional configuration for parser-policy plumbing. */
|
|
10
|
-
export interface DetermineBumpOptions {
|
|
11
|
-
/** Per-canonical-type breaking-policy lookup (drives `!` policy enforcement). */
|
|
12
|
-
breakingPolicies?: Record<string, 'forbidden' | 'optional' | 'required'>;
|
|
13
|
-
/** Receives policy-violation notifications from `parseCommitMessage`. */
|
|
14
|
-
onPolicyViolation?: PolicyViolationHandler;
|
|
15
|
-
}
|
|
16
|
-
/** Parse commits, determine bump type, and apply patch floor when commits exist but none parsed. */
|
|
17
|
-
export declare function determineBumpFromCommits(commits: Commit[], workTypes: Record<string, WorkTypeConfig>, versionPatterns: VersionPatterns, scopeAliases: Record<string, string> | undefined, options?: DetermineBumpOptions): BumpDetermination;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { determineBumpType } from "./determineBumpType.js";
|
|
2
|
-
import { parseCommitMessage, } from "./parseCommitMessage.js";
|
|
3
|
-
export function determineBumpFromCommits(commits, workTypes, versionPatterns, scopeAliases, options) {
|
|
4
|
-
const parseOptions = {
|
|
5
|
-
...(options?.breakingPolicies !== undefined && { breakingPolicies: options.breakingPolicies }),
|
|
6
|
-
...(options?.onPolicyViolation !== undefined && { onPolicyViolation: options.onPolicyViolation }),
|
|
7
|
-
};
|
|
8
|
-
const parsedCommits = [];
|
|
9
|
-
const unparseable = [];
|
|
10
|
-
for (const commit of commits) {
|
|
11
|
-
const parsed = parseCommitMessage(commit.message, commit.hash, workTypes, scopeAliases, parseOptions);
|
|
12
|
-
if (parsed === undefined) {
|
|
13
|
-
unparseable.push(commit);
|
|
14
|
-
}
|
|
15
|
-
else {
|
|
16
|
-
parsedCommits.push(parsed);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
let releaseType = determineBumpType(parsedCommits, workTypes, versionPatterns);
|
|
20
|
-
if (releaseType === undefined && commits.length > 0) {
|
|
21
|
-
releaseType = 'patch';
|
|
22
|
-
}
|
|
23
|
-
return {
|
|
24
|
-
releaseType,
|
|
25
|
-
parsedCommitCount: parsedCommits.length,
|
|
26
|
-
unparseableCommits: unparseable.length > 0 ? unparseable : undefined,
|
|
27
|
-
};
|
|
28
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { Commit } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Gets commits since the latest baseline tag matching any of the given prefixes.
|
|
4
|
-
*
|
|
5
|
-
* Uses `git log` to retrieve commit messages and hashes between the closest reachable
|
|
6
|
-
* baseline tag and HEAD. When no tag matches any prefix, all commits reachable from HEAD
|
|
7
|
-
* are returned.
|
|
8
|
-
*
|
|
9
|
-
* Callers must pass at least one prefix; the single-prefix case is the common one (the
|
|
10
|
-
* workspace's derived prefix). Multiple prefixes are used to include historical tag prefixes
|
|
11
|
-
* from `legacyIdentities`.
|
|
12
|
-
*
|
|
13
|
-
* @param tagPrefixes - Tag prefixes to search as a union (e.g., `['core-v', 'old-core-v']`).
|
|
14
|
-
* @param paths - Optional glob patterns to filter commits by path (appended after `--` in `git log`).
|
|
15
|
-
* Path patterns use POSIX-style forward slashes; Windows compatibility is not guaranteed.
|
|
16
|
-
* @returns An object with the found tag (if any) and the list of commits.
|
|
17
|
-
*/
|
|
18
|
-
export declare function getCommitsSinceTarget(tagPrefixes: readonly string[], paths?: string[]): {
|
|
19
|
-
tag: string | undefined;
|
|
20
|
-
commits: Commit[];
|
|
21
|
-
};
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from 'node:child_process';
|
|
2
|
-
import { GIT_OUTPUT_LIMIT } from '@williamthorsen/nmr-core';
|
|
3
|
-
import { chainError } from '@williamthorsen/toolbelt.errors/candidate';
|
|
4
|
-
const FIELD_SEPARATOR = '\u{1F}';
|
|
5
|
-
function isNoTagError(err) {
|
|
6
|
-
return typeof err === 'object' && err !== null && 'status' in err && err.status === 128;
|
|
7
|
-
}
|
|
8
|
-
function findLatestTag(tagPrefixes) {
|
|
9
|
-
if (tagPrefixes.length === 0) {
|
|
10
|
-
throw new Error('findLatestTag: tagPrefixes must contain at least one entry');
|
|
11
|
-
}
|
|
12
|
-
const matchArgs = tagPrefixes.map((prefix) => `--match=${prefix}*`);
|
|
13
|
-
try {
|
|
14
|
-
const tagResult = execFileSync('git', ['describe', '--tags', '--abbrev=0', ...matchArgs], {
|
|
15
|
-
encoding: 'utf8',
|
|
16
|
-
maxBuffer: GIT_OUTPUT_LIMIT,
|
|
17
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
18
|
-
}).trim();
|
|
19
|
-
return tagResult || undefined;
|
|
20
|
-
}
|
|
21
|
-
catch (error) {
|
|
22
|
-
if (isNoTagError(error)) {
|
|
23
|
-
return undefined;
|
|
24
|
-
}
|
|
25
|
-
throw chainError(`Failed to run 'git describe'`, error);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
const RELEASE_COMMIT_PREFIX = 'release:';
|
|
29
|
-
function parseLogOutput(logOutput) {
|
|
30
|
-
const commits = [];
|
|
31
|
-
for (const line of logOutput.split('\n')) {
|
|
32
|
-
const trimmedLine = line.trim();
|
|
33
|
-
if (trimmedLine === '') {
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
const [message, hash] = trimmedLine.split(FIELD_SEPARATOR);
|
|
37
|
-
if (message !== undefined && hash !== undefined && !message.startsWith(RELEASE_COMMIT_PREFIX)) {
|
|
38
|
-
commits.push({ message, hash });
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return commits;
|
|
42
|
-
}
|
|
43
|
-
export function getCommitsSinceTarget(tagPrefixes, paths) {
|
|
44
|
-
const tag = findLatestTag(tagPrefixes);
|
|
45
|
-
const range = tag === undefined ? 'HEAD' : `${tag}..HEAD`;
|
|
46
|
-
const format = `%s${FIELD_SEPARATOR}%H`;
|
|
47
|
-
const args = ['log', range, `--pretty=format:${format}`];
|
|
48
|
-
if (paths !== undefined && paths.length > 0) {
|
|
49
|
-
args.push('--', ...paths);
|
|
50
|
-
}
|
|
51
|
-
let logOutput;
|
|
52
|
-
try {
|
|
53
|
-
logOutput = execFileSync('git', args, {
|
|
54
|
-
encoding: 'utf8',
|
|
55
|
-
maxBuffer: GIT_OUTPUT_LIMIT,
|
|
56
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
57
|
-
}).trim();
|
|
58
|
-
}
|
|
59
|
-
catch (error) {
|
|
60
|
-
throw chainError(`Failed to run 'git log' for range '${range}'`, error);
|
|
61
|
-
}
|
|
62
|
-
if (logOutput === '') {
|
|
63
|
-
return { tag, commits: [] };
|
|
64
|
-
}
|
|
65
|
-
return { tag, commits: parseLogOutput(logOutput) };
|
|
66
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Resolve the git-cliff configuration file path.
|
|
3
|
-
*
|
|
4
|
-
* Checks candidates in order: explicit `cliffConfigPath` -> `.config/git-cliff.toml` ->
|
|
5
|
-
* `cliff.toml` -> bundled `cliff.toml.template`. Returns the first path that exists,
|
|
6
|
-
* or throws if even the bundled template cannot be found.
|
|
7
|
-
*
|
|
8
|
-
* When an explicit `cliffConfigPath` is provided, it is returned as-is without checking
|
|
9
|
-
* existence, preserving current behavior (git-cliff reports the error if the file is missing).
|
|
10
|
-
*/
|
|
11
|
-
export declare function resolveCliffConfigPath(cliffConfigPath: string | undefined, metaUrl: string): string;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
3
|
-
import { findPackageRoot } from '@williamthorsen/nmr-core';
|
|
4
|
-
export function resolveCliffConfigPath(cliffConfigPath, metaUrl) {
|
|
5
|
-
if (cliffConfigPath !== undefined) {
|
|
6
|
-
return cliffConfigPath;
|
|
7
|
-
}
|
|
8
|
-
const candidates = ['.config/git-cliff.toml', 'cliff.toml'];
|
|
9
|
-
for (const candidate of candidates) {
|
|
10
|
-
if (existsSync(candidate)) {
|
|
11
|
-
return candidate;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
const root = findPackageRoot(metaUrl);
|
|
15
|
-
const bundledPath = resolve(root, 'cliff.toml.template');
|
|
16
|
-
if (existsSync(bundledPath)) {
|
|
17
|
-
return bundledPath;
|
|
18
|
-
}
|
|
19
|
-
throw new Error(`Could not resolve a git-cliff config file. Searched: ${candidates.join(', ')}, and bundled template at ${bundledPath}`);
|
|
20
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The exact `git-cliff` version every invocation resolves.
|
|
3
|
-
*
|
|
4
|
-
* npm's `git-cliff` trails the upstream release, so this pin normally sits behind the newest version cliff
|
|
5
|
-
* itself reports. Bumping it is an edit to this line, once npm publishes the version you want.
|
|
6
|
-
*/
|
|
7
|
-
export declare const GIT_CLIFF_VERSION = "2.13.1";
|
|
8
|
-
/** The npx arguments that precede the cliff args at every invocation, and that the dry-run report renders. */
|
|
9
|
-
export declare const GIT_CLIFF_NPX_ARGS: readonly string[];
|
|
10
|
-
/**
|
|
11
|
-
* Invokes `git-cliff` via `npx` and returns the output it produced.
|
|
12
|
-
*
|
|
13
|
-
* Single entry point for `git-cliff` invocations from `release-kit`. Owns three pieces of shared lifecycle
|
|
14
|
-
* that would otherwise duplicate (and silently drift) across call sites: the npx flags, the spawned-process
|
|
15
|
-
* environment, and the temp dir holding both the `.template`→`.toml` config copy and cliff's output file.
|
|
16
|
-
*
|
|
17
|
-
* Output is routed through `--output` to a temp file and read back. `--context` emits a workspace's
|
|
18
|
-
* entire matching tag history on every run, so its size grows without bound with the repo;
|
|
19
|
-
* a file accommodates that, while a pipe is bounded by `maxBuffer`.
|
|
20
|
-
*
|
|
21
|
-
* The npx spec names an exact version, which leaves npm no staleness to check, so `--prefer-offline` skips the
|
|
22
|
-
* per-call registry revalidation round-trip (~2.5 s per invocation on a warm cache) without stranding the run
|
|
23
|
-
* on whatever the cache happens to hold.
|
|
24
|
-
*
|
|
25
|
-
* Two env entries are set for the child. `npm_config_progress=false` suppresses npx's animated stderr spinner,
|
|
26
|
-
* which otherwise renders as a transient flicker. `RUST_LOG=warn` drops cliff's INFO lines, among them the
|
|
27
|
-
* crates.io update notice it emits on every invocation while npm trails upstream, and leaves warnings and errors
|
|
28
|
-
* in place; an inherited `RUST_LOG` wins, so raising the level for debugging still works.
|
|
29
|
-
*
|
|
30
|
-
* The helper injects `--config <path>` and `--output <path>` itself — callers must NOT include either in `cliffArgs`.
|
|
31
|
-
* `--output` is appended last so a caller that passes one anyway cannot redirect the output the helper then reads.
|
|
32
|
-
* The caller is responsible for resolving the cliff config path (via `resolveCliffConfigPath`) before calling,
|
|
33
|
-
* since the resolution depends on the caller's `import.meta.url`.
|
|
34
|
-
*
|
|
35
|
-
* Errors from `execFileSync` are not caught: callers wrap with site-specific messages.
|
|
36
|
-
* The temp-dir cleanup runs in a `finally` so it still happens on throw.
|
|
37
|
-
*/
|
|
38
|
-
export declare function runGitCliff(cliffConfigPath: string, cliffArgs: readonly string[]): string;
|
package/dist/esm/runGitCliff.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from 'node:child_process';
|
|
2
|
-
import { copyFileSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
export const GIT_CLIFF_VERSION = '2.13.1';
|
|
6
|
-
export const GIT_CLIFF_NPX_ARGS = ['--prefer-offline', '--yes', `git-cliff@${GIT_CLIFF_VERSION}`];
|
|
7
|
-
export function runGitCliff(cliffConfigPath, cliffArgs) {
|
|
8
|
-
const tempDir = mkdtempSync(join(tmpdir(), 'cliff-'));
|
|
9
|
-
try {
|
|
10
|
-
let configPath = cliffConfigPath;
|
|
11
|
-
if (cliffConfigPath.endsWith('.template')) {
|
|
12
|
-
configPath = join(tempDir, 'cliff.toml');
|
|
13
|
-
copyFileSync(cliffConfigPath, configPath);
|
|
14
|
-
}
|
|
15
|
-
const outputPath = join(tempDir, 'output.json');
|
|
16
|
-
execFileSync('npx', [...GIT_CLIFF_NPX_ARGS, '--config', configPath, ...cliffArgs, '--output', outputPath], {
|
|
17
|
-
stdio: ['ignore', 'ignore', 'inherit'],
|
|
18
|
-
env: { ...process.env, npm_config_progress: 'false', RUST_LOG: process.env['RUST_LOG'] ?? 'warn' },
|
|
19
|
-
});
|
|
20
|
-
return readFileSync(outputPath, 'utf8');
|
|
21
|
-
}
|
|
22
|
-
finally {
|
|
23
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
24
|
-
}
|
|
25
|
-
}
|