@williamthorsen/release-kit 5.1.0 → 5.2.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 (50) hide show
  1. package/CHANGELOG.md +105 -65
  2. package/README.md +160 -57
  3. package/cliff.toml.template +26 -17
  4. package/dist/esm/.cache +1 -1
  5. package/dist/esm/bin/release-kit.js +96 -3
  6. package/dist/esm/buildChangelogEntries.d.ts +1 -0
  7. package/dist/esm/buildChangelogEntries.js +39 -25
  8. package/dist/esm/checkWorkTypesDrift.d.ts +11 -0
  9. package/dist/esm/checkWorkTypesDrift.js +110 -0
  10. package/dist/esm/collectPolicyViolations.d.ts +6 -0
  11. package/dist/esm/collectPolicyViolations.js +15 -0
  12. package/dist/esm/createGithubRelease.d.ts +12 -2
  13. package/dist/esm/createGithubRelease.js +12 -8
  14. package/dist/esm/createGithubReleaseCommand.js +10 -6
  15. package/dist/esm/decideRelease.d.ts +3 -0
  16. package/dist/esm/decideRelease.js +19 -3
  17. package/dist/esm/defaults.d.ts +7 -0
  18. package/dist/esm/defaults.js +41 -20
  19. package/dist/esm/deriveWorkspaceConfig.js +3 -0
  20. package/dist/esm/determineBumpFromCommits.d.ts +6 -1
  21. package/dist/esm/determineBumpFromCommits.js +9 -3
  22. package/dist/esm/generateChangelogs.js +14 -29
  23. package/dist/esm/loadConfig.js +14 -22
  24. package/dist/esm/parseCommitMessage.d.ts +8 -2
  25. package/dist/esm/parseCommitMessage.js +32 -3
  26. package/dist/esm/publishCommand.js +21 -2
  27. package/dist/esm/releasePrepare.js +39 -15
  28. package/dist/esm/releasePrepareMono.js +26 -3
  29. package/dist/esm/releasePrepareProject.js +13 -1
  30. package/dist/esm/renderReleaseNotes.js +2 -1
  31. package/dist/esm/reportPrepare.js +18 -0
  32. package/dist/esm/resolveCommandTags.js +16 -6
  33. package/dist/esm/resolveReleaseTags.d.ts +8 -1
  34. package/dist/esm/resolveReleaseTags.js +11 -7
  35. package/dist/esm/runGitCliff.d.ts +2 -0
  36. package/dist/esm/runGitCliff.js +27 -0
  37. package/dist/esm/stripEmojiPrefix.d.ts +1 -0
  38. package/dist/esm/stripEmojiPrefix.js +7 -0
  39. package/dist/esm/syncWorkTypes.d.ts +10 -0
  40. package/dist/esm/syncWorkTypes.js +90 -0
  41. package/dist/esm/types.d.ts +15 -0
  42. package/dist/esm/work-types.json +127 -0
  43. package/dist/esm/work-types.schema.json +73 -0
  44. package/dist/esm/workTypesData.d.ts +14 -0
  45. package/dist/esm/workTypesData.js +59 -0
  46. package/dist/esm/workTypesUtils.d.ts +5 -0
  47. package/dist/esm/workTypesUtils.js +16 -0
  48. package/package.json +6 -3
  49. package/dist/esm/version.d.ts +0 -1
  50. package/dist/esm/version.js +0 -4
@@ -3,6 +3,7 @@ export type ChangelogAudience = 'all' | 'dev';
3
3
  export interface ChangelogItem {
4
4
  description: string;
5
5
  body?: string;
6
+ breaking?: boolean;
6
7
  }
7
8
  export interface ChangelogSection {
8
9
  title: string;
@@ -37,6 +38,12 @@ export interface BumpResult {
37
38
  newVersion: string;
38
39
  files: string[];
39
40
  }
41
+ export interface PolicyViolation {
42
+ commitHash: string;
43
+ commitSubject: string;
44
+ type: string;
45
+ surface: 'prefix' | 'body';
46
+ }
40
47
  export interface ReleasedWorkspaceResult {
41
48
  status: 'released';
42
49
  name?: string;
@@ -44,6 +51,7 @@ export interface ReleasedWorkspaceResult {
44
51
  commitCount: number;
45
52
  parsedCommitCount?: number;
46
53
  unparseableCommits?: Commit[];
54
+ policyViolations?: PolicyViolation[];
47
55
  releaseType?: ReleaseType;
48
56
  currentVersion: string;
49
57
  newVersion: string;
@@ -62,6 +70,7 @@ export interface SkippedWorkspaceResult {
62
70
  commitCount: number;
63
71
  parsedCommitCount?: number;
64
72
  unparseableCommits?: Commit[];
73
+ policyViolations?: PolicyViolation[];
65
74
  skipReason: string;
66
75
  }
67
76
  export type WorkspacePrepareResult = ReleasedWorkspaceResult | SkippedWorkspaceResult;
@@ -71,6 +80,7 @@ export interface ReleasedProjectResult {
71
80
  commitCount: number;
72
81
  parsedCommitCount: number;
73
82
  unparseableCommits?: Commit[];
83
+ policyViolations?: PolicyViolation[];
74
84
  releaseType: ReleaseType;
75
85
  currentVersion: string;
76
86
  newVersion: string;
@@ -86,6 +96,7 @@ export interface SkippedProjectResult {
86
96
  commitCount: number;
87
97
  parsedCommitCount: number;
88
98
  unparseableCommits?: Commit[];
99
+ policyViolations?: PolicyViolation[];
89
100
  skipReason: string;
90
101
  }
91
102
  export type ProjectPrepareResult = ReleasedProjectResult | SkippedProjectResult;
@@ -113,6 +124,7 @@ export interface ReleaseKitConfig {
113
124
  workspaces?: WorkspaceOverride[];
114
125
  versionPatterns?: VersionPatterns;
115
126
  workTypes?: Record<string, WorkTypeConfig>;
127
+ breakingPolicies?: Record<string, 'forbidden' | 'optional' | 'required'>;
116
128
  formatCommand?: string;
117
129
  cliffConfigPath?: string;
118
130
  scopeAliases?: Record<string, string>;
@@ -152,6 +164,7 @@ export interface WorkspaceConfig {
152
164
  name: string;
153
165
  tagPrefix: string;
154
166
  workspacePath: string;
167
+ isPublishable: boolean;
155
168
  packageFiles: string[];
156
169
  changelogPaths: string[];
157
170
  paths: string[];
@@ -161,6 +174,7 @@ export interface MonorepoReleaseConfig {
161
174
  workspaces: WorkspaceConfig[];
162
175
  workTypes?: Record<string, WorkTypeConfig>;
163
176
  versionPatterns?: VersionPatterns;
177
+ breakingPolicies?: Record<string, 'forbidden' | 'optional' | 'required'>;
164
178
  formatCommand?: string;
165
179
  cliffConfigPath?: string;
166
180
  scopeAliases?: Record<string, string>;
@@ -174,6 +188,7 @@ export interface ReleaseConfig {
174
188
  changelogPaths: string[];
175
189
  workTypes?: Record<string, WorkTypeConfig>;
176
190
  versionPatterns?: VersionPatterns;
191
+ breakingPolicies?: Record<string, 'forbidden' | 'optional' | 'required'>;
177
192
  formatCommand?: string;
178
193
  cliffConfigPath?: string;
179
194
  scopeAliases?: Record<string, string>;
@@ -0,0 +1,127 @@
1
+ {
2
+ "$schema": "./work-types.schema.json",
3
+ "tiers": ["Public", "Internal", "Process"],
4
+ "types": [
5
+ {
6
+ "tier": "Public",
7
+ "key": "feat",
8
+ "aliases": ["feature"],
9
+ "emoji": "🎉",
10
+ "label": "Features",
11
+ "breakingPolicy": "optional"
12
+ },
13
+ {
14
+ "tier": "Public",
15
+ "key": "drop",
16
+ "aliases": [],
17
+ "emoji": "🪦",
18
+ "label": "Removed",
19
+ "breakingPolicy": "required"
20
+ },
21
+ {
22
+ "tier": "Public",
23
+ "key": "deprecate",
24
+ "aliases": [],
25
+ "emoji": "🗑️",
26
+ "label": "Deprecated",
27
+ "breakingPolicy": "forbidden"
28
+ },
29
+ {
30
+ "tier": "Public",
31
+ "key": "fix",
32
+ "aliases": ["bugfix"],
33
+ "emoji": "🐛",
34
+ "label": "Bug fixes",
35
+ "breakingPolicy": "forbidden"
36
+ },
37
+ {
38
+ "tier": "Public",
39
+ "key": "sec",
40
+ "aliases": ["security"],
41
+ "emoji": "🔒",
42
+ "label": "Security",
43
+ "breakingPolicy": "optional"
44
+ },
45
+ {
46
+ "tier": "Public",
47
+ "key": "perf",
48
+ "aliases": ["performance"],
49
+ "emoji": "⚡",
50
+ "label": "Performance",
51
+ "breakingPolicy": "forbidden"
52
+ },
53
+ {
54
+ "tier": "Internal",
55
+ "key": "internal",
56
+ "aliases": ["utility"],
57
+ "emoji": "🏗️",
58
+ "label": "Internal features",
59
+ "breakingPolicy": "forbidden"
60
+ },
61
+ {
62
+ "tier": "Internal",
63
+ "key": "refactor",
64
+ "aliases": [],
65
+ "emoji": "♻️",
66
+ "label": "Refactoring",
67
+ "breakingPolicy": "forbidden"
68
+ },
69
+ {
70
+ "tier": "Internal",
71
+ "key": "tests",
72
+ "aliases": ["test"],
73
+ "emoji": "🧪",
74
+ "label": "Tests",
75
+ "breakingPolicy": "forbidden"
76
+ },
77
+ {
78
+ "tier": "Process",
79
+ "key": "tooling",
80
+ "aliases": [],
81
+ "emoji": "⚙️",
82
+ "label": "Tooling",
83
+ "breakingPolicy": "forbidden"
84
+ },
85
+ {
86
+ "tier": "Process",
87
+ "key": "ci",
88
+ "aliases": [],
89
+ "emoji": "👷",
90
+ "label": "CI",
91
+ "breakingPolicy": "forbidden"
92
+ },
93
+ {
94
+ "tier": "Process",
95
+ "key": "deps",
96
+ "aliases": ["dep"],
97
+ "emoji": "📦",
98
+ "label": "Dependencies",
99
+ "breakingPolicy": "forbidden"
100
+ },
101
+ {
102
+ "tier": "Process",
103
+ "key": "ai",
104
+ "aliases": [],
105
+ "emoji": "🤖",
106
+ "label": "Agentic support",
107
+ "breakingPolicy": "forbidden"
108
+ },
109
+ {
110
+ "tier": "Process",
111
+ "key": "docs",
112
+ "aliases": ["doc"],
113
+ "emoji": "📚",
114
+ "label": "Documentation",
115
+ "breakingPolicy": "forbidden"
116
+ },
117
+ {
118
+ "tier": "Process",
119
+ "key": "fmt",
120
+ "aliases": [],
121
+ "emoji": "🎨",
122
+ "label": "Formatting",
123
+ "breakingPolicy": "forbidden",
124
+ "excludedFromChangelog": true
125
+ }
126
+ ]
127
+ }
@@ -0,0 +1,73 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://github.com/williamthorsen/node-monorepo-tools/raw/main/packages/release-kit/src/work-types.schema.json",
4
+ "title": "Work types",
5
+ "description": "Canonical taxonomy of commit work types used by release-kit. Drives section ordering, audience classification, and the `!` (breaking) policy. The structured single-source-of-truth for everything that previously lived in `DEFAULT_WORK_TYPES` and `cliff.toml.template` group definitions.",
6
+ "type": "object",
7
+ "required": ["tiers", "types"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "$schema": {
11
+ "type": "string",
12
+ "description": "Optional reference to this schema for IDE validation."
13
+ },
14
+ "tiers": {
15
+ "type": "array",
16
+ "description": "Render tiers in canonical order. Each entry's `tier` field must reference one of these names.",
17
+ "items": { "type": "string", "minLength": 1 },
18
+ "minItems": 1,
19
+ "uniqueItems": true
20
+ },
21
+ "types": {
22
+ "type": "array",
23
+ "description": "Work-type entries in canonical render order (tier order, then row order within tier).",
24
+ "items": { "$ref": "#/definitions/workType" },
25
+ "minItems": 1
26
+ }
27
+ },
28
+ "definitions": {
29
+ "workType": {
30
+ "type": "object",
31
+ "required": ["tier", "key", "aliases", "emoji", "label", "breakingPolicy"],
32
+ "additionalProperties": false,
33
+ "properties": {
34
+ "tier": {
35
+ "type": "string",
36
+ "description": "Render tier this entry belongs to. Must match one of the names in the top-level `tiers` array."
37
+ },
38
+ "key": {
39
+ "type": "string",
40
+ "description": "Canonical work-type identifier (e.g. `feat`, `fix`). Must be globally unique across all entries.",
41
+ "minLength": 1,
42
+ "pattern": "^[a-z][a-z0-9]*$"
43
+ },
44
+ "aliases": {
45
+ "type": "array",
46
+ "description": "Alternate identifiers that resolve to this work type. Must be globally unique and not collide with any `key`.",
47
+ "items": { "type": "string", "minLength": 1, "pattern": "^[a-z][a-z0-9]*$" },
48
+ "uniqueItems": true
49
+ },
50
+ "emoji": {
51
+ "type": "string",
52
+ "description": "Decorative emoji rendered as the prefix of the section heading.",
53
+ "minLength": 1
54
+ },
55
+ "label": {
56
+ "type": "string",
57
+ "description": "Human-readable section label (rendered as `${emoji} ${label}` in changelogs and release notes).",
58
+ "minLength": 1
59
+ },
60
+ "breakingPolicy": {
61
+ "type": "string",
62
+ "description": "Policy governing the `!` (breaking) marker for this type. `forbidden`: `!` is a policy violation. `optional`: `!` is allowed. `required`: bare type is a policy violation; only the `!` form is accepted.",
63
+ "enum": ["forbidden", "optional", "required"]
64
+ },
65
+ "excludedFromChangelog": {
66
+ "type": "boolean",
67
+ "description": "When `true`, this type's commits never appear in any changelog or release note. Currently only `fmt` sets this. Default: `false`.",
68
+ "default": false
69
+ }
70
+ }
71
+ }
72
+ }
73
+ }
@@ -0,0 +1,14 @@
1
+ export interface WorkTypeEntry {
2
+ tier: string;
3
+ key: string;
4
+ aliases: string[];
5
+ emoji: string;
6
+ label: string;
7
+ breakingPolicy: 'forbidden' | 'optional' | 'required';
8
+ excludedFromChangelog?: boolean;
9
+ }
10
+ export interface WorkTypesData {
11
+ tiers: string[];
12
+ types: WorkTypeEntry[];
13
+ }
14
+ export declare const WORK_TYPES_DATA: WorkTypesData;
@@ -0,0 +1,59 @@
1
+ const WORK_TYPES_DATA = {
2
+ tiers: ["Public", "Internal", "Process"],
3
+ types: [
4
+ { tier: "Public", key: "feat", aliases: ["feature"], emoji: "\u{1F389}", label: "Features", breakingPolicy: "optional" },
5
+ { tier: "Public", key: "drop", aliases: [], emoji: "\u{1FAA6}", label: "Removed", breakingPolicy: "required" },
6
+ { tier: "Public", key: "deprecate", aliases: [], emoji: "\u{1F5D1}\uFE0F", label: "Deprecated", breakingPolicy: "forbidden" },
7
+ { tier: "Public", key: "fix", aliases: ["bugfix"], emoji: "\u{1F41B}", label: "Bug fixes", breakingPolicy: "forbidden" },
8
+ { tier: "Public", key: "sec", aliases: ["security"], emoji: "\u{1F512}", label: "Security", breakingPolicy: "optional" },
9
+ {
10
+ tier: "Public",
11
+ key: "perf",
12
+ aliases: ["performance"],
13
+ emoji: "\u26A1",
14
+ label: "Performance",
15
+ breakingPolicy: "forbidden"
16
+ },
17
+ {
18
+ tier: "Internal",
19
+ key: "internal",
20
+ aliases: ["utility"],
21
+ emoji: "\u{1F3D7}\uFE0F",
22
+ label: "Internal features",
23
+ breakingPolicy: "forbidden"
24
+ },
25
+ {
26
+ tier: "Internal",
27
+ key: "refactor",
28
+ aliases: [],
29
+ emoji: "\u267B\uFE0F",
30
+ label: "Refactoring",
31
+ breakingPolicy: "forbidden"
32
+ },
33
+ { tier: "Internal", key: "tests", aliases: ["test"], emoji: "\u{1F9EA}", label: "Tests", breakingPolicy: "forbidden" },
34
+ { tier: "Process", key: "tooling", aliases: [], emoji: "\u2699\uFE0F", label: "Tooling", breakingPolicy: "forbidden" },
35
+ { tier: "Process", key: "ci", aliases: [], emoji: "\u{1F477}", label: "CI", breakingPolicy: "forbidden" },
36
+ { tier: "Process", key: "deps", aliases: ["dep"], emoji: "\u{1F4E6}", label: "Dependencies", breakingPolicy: "forbidden" },
37
+ { tier: "Process", key: "ai", aliases: [], emoji: "\u{1F916}", label: "Agentic support", breakingPolicy: "forbidden" },
38
+ {
39
+ tier: "Process",
40
+ key: "docs",
41
+ aliases: ["doc"],
42
+ emoji: "\u{1F4DA}",
43
+ label: "Documentation",
44
+ breakingPolicy: "forbidden"
45
+ },
46
+ {
47
+ tier: "Process",
48
+ key: "fmt",
49
+ aliases: [],
50
+ emoji: "\u{1F3A8}",
51
+ label: "Formatting",
52
+ breakingPolicy: "forbidden",
53
+ excludedFromChangelog: true
54
+ }
55
+ ]
56
+ };
57
+ export {
58
+ WORK_TYPES_DATA
59
+ };
@@ -0,0 +1,5 @@
1
+ export declare function hasExpectedTopLevelShape(value: unknown): value is {
2
+ tiers: unknown[];
3
+ types: unknown[];
4
+ };
5
+ export declare function errorMessage(error: unknown): string;
@@ -0,0 +1,16 @@
1
+ function hasExpectedTopLevelShape(value) {
2
+ if (typeof value !== "object" || value === null) {
3
+ return false;
4
+ }
5
+ if (!("tiers" in value) || !("types" in value)) {
6
+ return false;
7
+ }
8
+ return Array.isArray(value.tiers) && Array.isArray(value.types);
9
+ }
10
+ function errorMessage(error) {
11
+ return error instanceof Error ? error.message : String(error);
12
+ }
13
+ export {
14
+ errorMessage,
15
+ hasExpectedTopLevelShape
16
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@williamthorsen/release-kit",
3
- "version": "5.1.0",
3
+ "version": "5.2.0",
4
4
  "description": "Version-bumping and changelog-generation toolkit for release workflows",
5
5
  "keywords": [],
6
6
  "homepage": "https://github.com/williamthorsen/node-monorepo-tools/tree/main/packages/release-kit#readme",
@@ -37,7 +37,7 @@
37
37
  "js-yaml": "4.1.1",
38
38
  "json-stringify-pretty-compact": "4.0.0",
39
39
  "semver": "7.7.4",
40
- "@williamthorsen/nmr-core": "0.3.0"
40
+ "@williamthorsen/nmr-core": "0.3.1"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/js-yaml": "4.0.9",
@@ -52,9 +52,12 @@
52
52
  "registry": "https://registry.npmjs.org"
53
53
  },
54
54
  "scripts": {
55
+ "build:post": "node scripts/copy-work-types.js",
55
56
  "test": "pnpm exec vitest --config=vitest.standalone.config.ts",
56
57
  "test:coverage": "pnpm exec vitest --config=vitest.standalone.config.ts --coverage",
57
58
  "test:integration": "pnpm exec vitest --config=vitest.integration.config.ts",
58
- "test:watch": "pnpm exec vitest --config=vitest.standalone.config.ts --watch"
59
+ "test:watch": "pnpm exec vitest --config=vitest.standalone.config.ts --watch",
60
+ "work-types:check": "pnpm exec release-kit work-types check",
61
+ "work-types:sync": "pnpm exec release-kit work-types sync"
59
62
  }
60
63
  }
@@ -1 +0,0 @@
1
- export declare const VERSION = "5.1.0";
@@ -1,4 +0,0 @@
1
- const VERSION = "5.1.0";
2
- export {
3
- VERSION
4
- };