@williamthorsen/release-kit 2.3.2 → 4.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/CHANGELOG.md +54 -38
- package/README.md +29 -12
- package/cliff.toml.template +13 -12
- package/dist/esm/.cache +1 -1
- package/dist/esm/bin/release-kit.js +28 -0
- package/dist/esm/buildDependencyGraph.d.ts +7 -0
- package/dist/esm/buildDependencyGraph.js +59 -0
- package/dist/esm/buildReleaseSummary.d.ts +2 -0
- package/dist/esm/buildReleaseSummary.js +22 -0
- package/dist/esm/commitCommand.d.ts +1 -0
- package/dist/esm/commitCommand.js +55 -0
- package/dist/esm/createTags.js +12 -1
- package/dist/esm/determineBumpFromCommits.d.ts +1 -1
- package/dist/esm/determineBumpFromCommits.js +2 -2
- package/dist/esm/generateChangelogs.d.ts +2 -0
- package/dist/esm/generateChangelogs.js +9 -1
- package/dist/esm/index.d.ts +4 -1
- package/dist/esm/index.js +8 -1
- package/dist/esm/init/initCommand.js +4 -2
- package/dist/esm/init/scaffold.js +3 -2
- package/dist/esm/init/templates.d.ts +1 -0
- package/dist/esm/init/templates.js +24 -2
- package/dist/esm/loadConfig.js +6 -6
- package/dist/esm/parseCommitMessage.d.ts +1 -1
- package/dist/esm/parseCommitMessage.js +9 -7
- package/dist/esm/prepareCommand.d.ts +1 -0
- package/dist/esm/prepareCommand.js +20 -0
- package/dist/esm/propagateBumps.d.ts +8 -0
- package/dist/esm/propagateBumps.js +54 -0
- package/dist/esm/publish.d.ts +1 -0
- package/dist/esm/publish.js +6 -3
- package/dist/esm/publishCommand.js +3 -2
- package/dist/esm/releasePrepare.js +2 -1
- package/dist/esm/releasePrepareMono.js +237 -48
- package/dist/esm/reportPrepare.js +29 -3
- package/dist/esm/stripScope.d.ts +1 -0
- package/dist/esm/stripScope.js +24 -0
- package/dist/esm/sync-labels/templates.js +1 -1
- package/dist/esm/types.d.ts +11 -4
- package/dist/esm/validateConfig.js +6 -6
- package/dist/esm/writeSyntheticChangelog.d.ts +9 -0
- package/dist/esm/writeSyntheticChangelog.js +27 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [release-kit-v3.0.0] - 2026-03-29
|
|
6
|
+
|
|
7
|
+
### Bug fixes
|
|
8
|
+
|
|
9
|
+
- #68 release-kit|fix: Pass tag pattern to git-cliff based on tagPrefix (#77)
|
|
10
|
+
|
|
11
|
+
Fixes the issue that git-cliff was processing the entire commit history on every run instead of only commits since the last release.
|
|
12
|
+
|
|
13
|
+
Constructs the pattern from `tagPrefix` at invocation time (e.g., `release-kit-v` → `release-kit-v[0-9].*`) and pass it via `--tag-pattern`, which overrides the config file default.
|
|
14
|
+
|
|
15
|
+
- #72 release-kit|fix: Propagate version bumps to workspace dependents (#80)
|
|
16
|
+
|
|
17
|
+
Restructures `releasePrepareMono` from a single-pass loop into a phased pipeline that automatically patch-bumps workspace dependents when a component is released. A reverse dependency graph is built from `workspace:` references in `dependencies` and `peerDependencies`, then BFS propagation walks upward from bumped components to their dependents. Propagated-only components receive synthetic changelog entries instead of git-cliff invocations.
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
- #73 release-kit|feat!: Support conventional-commit format in commit parsing (#85)
|
|
22
|
+
|
|
23
|
+
Adds support for the conventional commits format (`type(scope): description`) alongside the existing pipe-prefixed format (`scope|type: description`) in release-kit's commit parser. Renames `workspace` to `scope` throughout release-kit types, config, validation, and consumers.
|
|
24
|
+
|
|
25
|
+
- #70 release-kit|feat: Add commit command for local release flow (#89)
|
|
26
|
+
|
|
27
|
+
Adds a `release-kit commit` command that centralizes the release commit step between `prepare` and `tag`. The command reads tag names and a per-component commit summary from temporary files written by `prepare`, stages all changes, and creates a formatted commit. Two new utilities — `stripScope` and `buildReleaseSummary` — support building the commit body by stripping redundant scope indicators and formatting commits under their component headings. The CI workflow is simplified to use `release-kit commit` and `release-kit tag` instead of inline shell logic.
|
|
28
|
+
|
|
29
|
+
- #69 release-kit|feat: Add CI publish workflow with OIDC trusted publishing (#90)
|
|
30
|
+
|
|
31
|
+
Adds automated npm publication via a tag-push-triggered GitHub Actions workflow using OIDC trusted publishing. Extends `release-kit publish` with a `--provenance` flag and `release-kit init` with publish workflow scaffolding.
|
|
32
|
+
|
|
33
|
+
- #91 release-kit|feat: Make --provenance opt-in to support private repos (#94)
|
|
34
|
+
|
|
35
|
+
Adds a `provenance` boolean input (default `false`) to the reusable `publish-workflow.yaml` so private repos using OIDC trusted publishing no longer fail at publish time. The `--provenance` flag is only passed to `release-kit publish` when the caller sets `provenance: true`.
|
|
36
|
+
|
|
37
|
+
Updates the scaffolded `publish.yaml` template to include `provenance: false` with an inline comment guiding public repos to opt in. Expand the `release-kit init` next-steps output with hints about the provenance setting and trusted publisher registration. Set `provenance: true` in this repo's own `publish.yaml` since it is public.
|
|
38
|
+
|
|
5
39
|
## [release-kit-v2.3.2] - 2026-03-28
|
|
6
40
|
|
|
7
41
|
### Bug fixes
|
|
@@ -14,10 +48,6 @@ Prevents `releasePrepareMono` and `releasePrepare` from silently skipping compon
|
|
|
14
48
|
|
|
15
49
|
### Features
|
|
16
50
|
|
|
17
|
-
- #8 feat: Add shared writeFileWithCheck utility and overwrite reporting (#66)
|
|
18
|
-
|
|
19
|
-
Extracts three duplicated `writeIfAbsent` implementations and two duplicated terminal helper sets into shared utilities in `@williamthorsen/node-monorepo-core`, then migrates all consumers (`release-kit init`, `preflight init`, `sync-labels`) to use them. All init commands now report which files were created, overwritten, skipped, or failed — including when `--force` replaces existing files.
|
|
20
|
-
|
|
21
51
|
- #11 release-kit|feat: Separate tag-write errors from release preparation errors (#67)
|
|
22
52
|
|
|
23
53
|
When tag-file writing fails, the error message now reads "Error writing release tags:" instead of the misleading "Error preparing release:", which only appeared because both operations shared a single try/catch.
|
|
@@ -40,8 +70,28 @@ Adds three unit tests to `releasePrepare.unit.test.ts` covering previously untes
|
|
|
40
70
|
|
|
41
71
|
## [release-kit-v2.2.0] - 2026-03-27
|
|
42
72
|
|
|
73
|
+
### Dependencies
|
|
74
|
+
|
|
75
|
+
- Root|deps: Add release-kit as root devDependency
|
|
76
|
+
|
|
77
|
+
Make `npx release-kit` and `pnpm exec release-kit` resolve within
|
|
78
|
+
this repo by adding a `workspace:*` dependency that symlinks the bin.
|
|
79
|
+
|
|
43
80
|
### Features
|
|
44
81
|
|
|
82
|
+
- #23 release-kit|feat: Add sync-labels command (#33)
|
|
83
|
+
|
|
84
|
+
Add a `release-kit sync-labels` command group with three subcommands (`init`, `generate`, `sync`) for declarative GitHub label management in monorepos. Bundle a reusable GitHub Actions workflow and composable label presets with the release-kit package. Introduce a `findPackageRoot` utility to replace fragile hardcoded path resolutions across the codebase.
|
|
85
|
+
|
|
86
|
+
- #34 release-kit|feat: Report up-to-date status for unchanged init files (#35)
|
|
87
|
+
|
|
88
|
+
`release-kit init` now compares existing file content against the default before reporting status. When an existing file is identical to the default (after normalizing trailing whitespace), it reports `✅ (up to date)` instead of the misleading `⚠️ (already exists)`.
|
|
89
|
+
|
|
90
|
+
- Release-workflow|feat: Accept force input
|
|
91
|
+
|
|
92
|
+
Pass `--force` to the prepare command so callers can force a version
|
|
93
|
+
bump even when there are no release-worthy changes.
|
|
94
|
+
|
|
45
95
|
- #27 release-kit|feat: Auto-detect Prettier for CHANGELOG formatting (#36)
|
|
46
96
|
|
|
47
97
|
When `formatCommand` is not configured, release-kit now auto-detects whether the repo uses Prettier by checking for config files (`.prettierrc*`, `prettier.config.*`) or a `"prettier"` key in root `package.json`. If found, it defaults to `npx prettier --write` on generated files. If not found, formatting is skipped.
|
|
@@ -62,18 +112,8 @@ Removes the ability to customize `tagPrefix` per component, enforcing the determ
|
|
|
62
112
|
|
|
63
113
|
Adds ANSI formatting and emoji markers to the `release-kit prepare` command output. Progress chatter is dimmed, key results (version bumps, release tags, completion status) are highlighted with bold text and emoji, and monorepo components are separated by box-drawing section headers.
|
|
64
114
|
|
|
65
|
-
- #59 feat: Extract nmr CLI from core package (#61)
|
|
66
|
-
|
|
67
|
-
Extracts all nmr CLI code from `packages/core` into a new `packages/nmr` package (`@williamthorsen/nmr`). Core is reduced to an empty shared-library shell ready for cross-cutting utilities. All internal references are rewired and the full build/test pipeline passes.
|
|
68
|
-
|
|
69
|
-
Scopes: core, nmr
|
|
70
|
-
|
|
71
115
|
### Refactoring
|
|
72
116
|
|
|
73
|
-
- #43 refactor: Replace dist bin targets with thin wrapper scripts (#48)
|
|
74
|
-
|
|
75
|
-
The `bin` entries in `packages/core` and `packages/release-kit` pointed directly into `dist/esm/`, causing `pnpm install` to emit "Failed to create bin" warnings in fresh worktrees where `dist/` does not yet exist. Each bin entry now points to a committed wrapper script in `bin/` that dynamically imports the real entry point. The `files` field in both packages includes `bin` so the wrappers are published.
|
|
76
|
-
|
|
77
117
|
- #53 release-kit|refactor: Separate presentation from logic in prepare workflow (#57)
|
|
78
118
|
|
|
79
119
|
Extracts all `console.info` calls from the prepare workflow's logic functions (`bumpAllVersions`, `generateChangelogs`, `releasePrepare`, `releasePrepareMono`) into a dedicated `reportPrepare` formatter. Logic functions now return structured result types (`BumpResult`, `ComponentPrepareResult`, `PrepareResult`). The legacy `runReleasePrepare` entry point is retired, with its utilities absorbed into `prepareCommand`.
|
|
@@ -96,30 +136,6 @@ Also adds a `findAllCliffOutputPaths()` test helper that collects the `--output`
|
|
|
96
136
|
|
|
97
137
|
Replaces the legacy workspace script runner and ~25 root `package.json` scripts with `nmr`, the monorepo's own context-aware script runner. Root scripts are reduced to 4 (`prepare`, `postinstall`, `ci`, `bootstrap`), packages use direct build commands for bootstrap, and release-kit declares tier-3 test overrides for its integration test configs.
|
|
98
138
|
|
|
99
|
-
## [release-workflow-v1] - 2026-03-19
|
|
100
|
-
|
|
101
|
-
### Dependencies
|
|
102
|
-
|
|
103
|
-
- Root|deps: Add release-kit as root devDependency
|
|
104
|
-
|
|
105
|
-
Make `npx release-kit` and `pnpm exec release-kit` resolve within
|
|
106
|
-
this repo by adding a `workspace:*` dependency that symlinks the bin.
|
|
107
|
-
|
|
108
|
-
### Features
|
|
109
|
-
|
|
110
|
-
- #23 release-kit|feat: Add sync-labels command (#33)
|
|
111
|
-
|
|
112
|
-
Add a `release-kit sync-labels` command group with three subcommands (`init`, `generate`, `sync`) for declarative GitHub label management in monorepos. Bundle a reusable GitHub Actions workflow and composable label presets with the release-kit package. Introduce a `findPackageRoot` utility to replace fragile hardcoded path resolutions across the codebase.
|
|
113
|
-
|
|
114
|
-
- #34 release-kit|feat: Report up-to-date status for unchanged init files (#35)
|
|
115
|
-
|
|
116
|
-
`release-kit init` now compares existing file content against the default before reporting status. When an existing file is identical to the default (after normalizing trailing whitespace), it reports `✅ (up to date)` instead of the misleading `⚠️ (already exists)`.
|
|
117
|
-
|
|
118
|
-
- Release-workflow|feat: Accept force input
|
|
119
|
-
|
|
120
|
-
Pass `--force` to the prepare command so callers can force a version
|
|
121
|
-
bump even when there are no release-worthy changes.
|
|
122
|
-
|
|
123
139
|
## [release-kit-v2.1.0] - 2026-03-17
|
|
124
140
|
|
|
125
141
|
### Features
|
package/README.md
CHANGED
|
@@ -68,6 +68,21 @@ Scaffolded files:
|
|
|
68
68
|
- `.config/release-kit.config.ts` — starter config with commented-out customization examples (with `--with-config`)
|
|
69
69
|
- `.config/git-cliff.toml` — copied from the bundled template (with `--with-config`)
|
|
70
70
|
|
|
71
|
+
### `release-kit sync-labels`
|
|
72
|
+
|
|
73
|
+
Manage GitHub label definitions via config-driven YAML files.
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
Usage: release-kit sync-labels <command> [options]
|
|
77
|
+
|
|
78
|
+
Commands:
|
|
79
|
+
init Scaffold sync-labels config and caller workflow
|
|
80
|
+
generate Generate .github/labels.yaml from config
|
|
81
|
+
sync Generate labels and push to GitHub (runs generate + gh label sync)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`init` scaffolds `.config/sync-labels.config.ts` with auto-detected workspace scope labels and a `.github/workflows/sync-labels.yaml` caller workflow. `generate` reads the config and writes `.github/labels.yaml`. `sync` runs `generate` and then applies labels to the GitHub repo.
|
|
85
|
+
|
|
71
86
|
## Configuration
|
|
72
87
|
|
|
73
88
|
Configuration is optional. The CLI works out of the box by auto-discovering workspaces and applying defaults. Create `.config/release-kit.config.ts` only when you need to customize behavior.
|
|
@@ -98,14 +113,14 @@ The config file supports both `export default config` and `export const config =
|
|
|
98
113
|
|
|
99
114
|
### `ReleaseKitConfig` reference
|
|
100
115
|
|
|
101
|
-
| Field
|
|
102
|
-
|
|
|
103
|
-
| `cliffConfigPath`
|
|
104
|
-
| `components`
|
|
105
|
-
| `formatCommand`
|
|
106
|
-
| `versionPatterns`
|
|
107
|
-
| `
|
|
108
|
-
| `workTypes`
|
|
116
|
+
| Field | Type | Description |
|
|
117
|
+
| ----------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
118
|
+
| `cliffConfigPath` | `string` | Explicit path to cliff config. If omitted, resolved automatically: `.config/git-cliff.toml` → `cliff.toml` → bundled template |
|
|
119
|
+
| `components` | `ComponentOverride[]` | Override or exclude discovered components (matched by `dir`) |
|
|
120
|
+
| `formatCommand` | `string` | Shell command to run after changelog generation; modified file paths are appended as arguments |
|
|
121
|
+
| `versionPatterns` | `VersionPatterns` | Rules for which commit types trigger major/minor bumps |
|
|
122
|
+
| `scopeAliases` | `Record<string, string>` | Maps shorthand scope names to canonical names in commits |
|
|
123
|
+
| `workTypes` | `Record<string, WorkTypeConfig>` | Work type definitions, merged with defaults by key |
|
|
109
124
|
|
|
110
125
|
All fields are optional.
|
|
111
126
|
|
|
@@ -154,12 +169,14 @@ release-kit parses commits in these formats:
|
|
|
154
169
|
|
|
155
170
|
```
|
|
156
171
|
type: description # e.g., feat: add utility
|
|
157
|
-
type
|
|
158
|
-
|
|
159
|
-
|
|
172
|
+
scope|type: description # e.g., arrays|feat: add compact function
|
|
173
|
+
type(scope): description # e.g., feat(arrays): add compact function
|
|
174
|
+
type!: description # breaking change (triggers major bump)
|
|
175
|
+
scope|type!: description # scoped breaking change
|
|
176
|
+
type(scope)!: description # conventional scoped breaking change
|
|
160
177
|
```
|
|
161
178
|
|
|
162
|
-
The `
|
|
179
|
+
The `scope|type:` format scopes a commit to a specific component in a monorepo. Use `scopeAliases` in your config to map shorthand names to canonical scope names.
|
|
163
180
|
|
|
164
181
|
## Using `component()` for manual configuration
|
|
165
182
|
|
package/cliff.toml.template
CHANGED
|
@@ -45,19 +45,20 @@ commit_preprocessors = [
|
|
|
45
45
|
{ pattern = '^[A-Z]+-\d+\s+', replace = "" },
|
|
46
46
|
]
|
|
47
47
|
# regex for parsing and grouping commits
|
|
48
|
-
# Supports
|
|
48
|
+
# Supports "type: desc", "scope|type: desc", and "type(scope): desc" formats
|
|
49
49
|
commit_parsers = [
|
|
50
|
-
{ message = "
|
|
51
|
-
{ message = "
|
|
52
|
-
{ message = "
|
|
53
|
-
{ message = "
|
|
54
|
-
{ message = "
|
|
55
|
-
{ message = "
|
|
56
|
-
{ message = "
|
|
57
|
-
{ message = "
|
|
58
|
-
{ message = "
|
|
59
|
-
{ message = "
|
|
60
|
-
{ message = "
|
|
50
|
+
{ message = "^(.*\\|)?fix(\\(.*\\))?(!)?:", group = "Bug fixes" },
|
|
51
|
+
{ message = "^(.*\\|)?bugfix(\\(.*\\))?(!)?:", group = "Bug fixes" },
|
|
52
|
+
{ message = "^(.*\\|)?feat(\\(.*\\))?(!)?:", group = "Features" },
|
|
53
|
+
{ message = "^(.*\\|)?feature(\\(.*\\))?(!)?:", group = "Features" },
|
|
54
|
+
{ message = "^(.*\\|)?internal(\\(.*\\))?(!)?:", group = "Internal" },
|
|
55
|
+
{ message = "^(.*\\|)?refactor(\\(.*\\))?(!)?:", group = "Refactoring" },
|
|
56
|
+
{ message = "^(.*\\|)?tests?(\\(.*\\))?(!)?:", group = "Tests" },
|
|
57
|
+
{ message = "^(.*\\|)?tooling(\\(.*\\))?(!)?:", group = "Tooling" },
|
|
58
|
+
{ message = "^(.*\\|)?ci(\\(.*\\))?(!)?:", group = "CI" },
|
|
59
|
+
{ message = "^(.*\\|)?deps?(\\(.*\\))?(!)?:", group = "Dependencies" },
|
|
60
|
+
{ message = "^(.*\\|)?docs?(\\(.*\\))?(!)?:", group = "Documentation" },
|
|
61
|
+
{ message = "^(.*\\|)?fmt(\\(.*\\))?(!)?:", group = "Formatting" },
|
|
61
62
|
]
|
|
62
63
|
# protect breaking changes from being skipped due to matching a skipping commit_parser
|
|
63
64
|
protect_breaking_commits = false
|
package/dist/esm/.cache
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
eda8d9c3d3574c46e1afbeccbda04ffac0675bd9d30270ab8644fc48477ace14
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { commitCommand } from "../commitCommand.js";
|
|
2
3
|
import { initCommand } from "../init/initCommand.js";
|
|
3
4
|
import { prepareCommand } from "../prepareCommand.js";
|
|
4
5
|
import { publishCommand } from "../publishCommand.js";
|
|
@@ -12,6 +13,7 @@ Usage: release-kit <command> [options]
|
|
|
12
13
|
|
|
13
14
|
Commands:
|
|
14
15
|
prepare Run release preparation (auto-discovers workspaces)
|
|
16
|
+
commit Stage changes and create the release commit
|
|
15
17
|
tag Create annotated git tags from the tags file
|
|
16
18
|
publish Publish packages with release tags on HEAD
|
|
17
19
|
init Initialize release-kit in the current repository
|
|
@@ -97,6 +99,18 @@ Options:
|
|
|
97
99
|
--help, -h Show this help message
|
|
98
100
|
`);
|
|
99
101
|
}
|
|
102
|
+
function showCommitHelp() {
|
|
103
|
+
console.info(`
|
|
104
|
+
Usage: release-kit commit [options]
|
|
105
|
+
|
|
106
|
+
Stage all changes and create the release commit using tags and summary
|
|
107
|
+
produced by \`prepare\`.
|
|
108
|
+
|
|
109
|
+
Options:
|
|
110
|
+
--dry-run Preview the commit message without creating it
|
|
111
|
+
--help, -h Show this help message
|
|
112
|
+
`);
|
|
113
|
+
}
|
|
100
114
|
function showTagHelp() {
|
|
101
115
|
console.info(`
|
|
102
116
|
Usage: release-kit tag [options]
|
|
@@ -119,6 +133,7 @@ Options:
|
|
|
119
133
|
--dry-run Preview without publishing
|
|
120
134
|
--no-git-checks Skip git checks (pnpm only)
|
|
121
135
|
--only=name1,name2 Only publish the named packages (comma-separated, monorepo only)
|
|
136
|
+
--provenance Generate provenance statement (requires OIDC, not supported by classic yarn)
|
|
122
137
|
--help, -h Show this help message
|
|
123
138
|
`);
|
|
124
139
|
}
|
|
@@ -137,6 +152,19 @@ if (command === "prepare") {
|
|
|
137
152
|
await prepareCommand(flags);
|
|
138
153
|
process.exit(0);
|
|
139
154
|
}
|
|
155
|
+
if (command === "commit") {
|
|
156
|
+
if (flags.some((f) => f === "--help" || f === "-h")) {
|
|
157
|
+
showCommitHelp();
|
|
158
|
+
process.exit(0);
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
commitCommand(flags);
|
|
162
|
+
} catch (error) {
|
|
163
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
process.exit(0);
|
|
167
|
+
}
|
|
140
168
|
if (command === "tag") {
|
|
141
169
|
if (flags.some((f) => f === "--help" || f === "-h")) {
|
|
142
170
|
showTagHelp();
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ComponentConfig } from './types.ts';
|
|
2
|
+
export interface DependencyGraph {
|
|
3
|
+
packageNameToDir: Map<string, string>;
|
|
4
|
+
dirToPackageName: Map<string, string>;
|
|
5
|
+
dependentsOf: Map<string, ComponentConfig[]>;
|
|
6
|
+
}
|
|
7
|
+
export declare function buildDependencyGraph(components: readonly ComponentConfig[]): DependencyGraph;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
function isPackageJsonSubset(value) {
|
|
3
|
+
return typeof value === "object" && value !== null;
|
|
4
|
+
}
|
|
5
|
+
function buildDependencyGraph(components) {
|
|
6
|
+
const packageNameToDir = /* @__PURE__ */ new Map();
|
|
7
|
+
const dirToPackageName = /* @__PURE__ */ new Map();
|
|
8
|
+
const dependentsOf = /* @__PURE__ */ new Map();
|
|
9
|
+
const componentPackages = /* @__PURE__ */ new Map();
|
|
10
|
+
for (const component of components) {
|
|
11
|
+
const primaryPackageFile = component.packageFiles[0];
|
|
12
|
+
if (primaryPackageFile === void 0) {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
const pkg = readPackageJsonSubset(primaryPackageFile);
|
|
16
|
+
componentPackages.set(component, pkg);
|
|
17
|
+
if (pkg.name === void 0) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
packageNameToDir.set(pkg.name, component.dir);
|
|
21
|
+
dirToPackageName.set(component.dir, pkg.name);
|
|
22
|
+
}
|
|
23
|
+
for (const [component, pkg] of componentPackages) {
|
|
24
|
+
const allDeps = { ...pkg.dependencies, ...pkg.peerDependencies };
|
|
25
|
+
for (const [depName, depVersion] of Object.entries(allDeps)) {
|
|
26
|
+
if (typeof depVersion !== "string" || !depVersion.startsWith("workspace:")) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const existing = dependentsOf.get(depName);
|
|
30
|
+
if (existing === void 0) {
|
|
31
|
+
dependentsOf.set(depName, [component]);
|
|
32
|
+
} else {
|
|
33
|
+
existing.push(component);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return { packageNameToDir, dirToPackageName, dependentsOf };
|
|
38
|
+
}
|
|
39
|
+
function readPackageJsonSubset(filePath) {
|
|
40
|
+
let content;
|
|
41
|
+
try {
|
|
42
|
+
content = readFileSync(filePath, "utf8");
|
|
43
|
+
} catch (error) {
|
|
44
|
+
throw new Error(`Failed to read ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
45
|
+
}
|
|
46
|
+
let parsed;
|
|
47
|
+
try {
|
|
48
|
+
parsed = JSON.parse(content);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
throw new Error(`Failed to parse JSON in ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
51
|
+
}
|
|
52
|
+
if (!isPackageJsonSubset(parsed)) {
|
|
53
|
+
throw new Error(`Invalid package.json at ${filePath}`);
|
|
54
|
+
}
|
|
55
|
+
return parsed;
|
|
56
|
+
}
|
|
57
|
+
export {
|
|
58
|
+
buildDependencyGraph
|
|
59
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { stripScope } from "./stripScope.js";
|
|
2
|
+
function buildReleaseSummary(result) {
|
|
3
|
+
const sections = [];
|
|
4
|
+
for (const component of result.components) {
|
|
5
|
+
if (component.status !== "released" || component.tag === void 0) {
|
|
6
|
+
continue;
|
|
7
|
+
}
|
|
8
|
+
const commits = component.commits;
|
|
9
|
+
if (commits === void 0 || commits.length === 0) {
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
const lines = [component.tag];
|
|
13
|
+
for (const commit of commits) {
|
|
14
|
+
lines.push(`- ${stripScope(commit.message)}`);
|
|
15
|
+
}
|
|
16
|
+
sections.push(lines.join("\n"));
|
|
17
|
+
}
|
|
18
|
+
return sections.join("\n\n");
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
buildReleaseSummary
|
|
22
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function commitCommand(argv: string[]): void;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { RELEASE_SUMMARY_FILE, RELEASE_TAGS_FILE } from "./prepareCommand.js";
|
|
4
|
+
function commitCommand(argv) {
|
|
5
|
+
const knownFlags = /* @__PURE__ */ new Set(["--dry-run"]);
|
|
6
|
+
const unknownFlags = argv.filter((f) => !knownFlags.has(f));
|
|
7
|
+
if (unknownFlags.length > 0) {
|
|
8
|
+
console.error(`Error: Unknown option: ${unknownFlags[0]}`);
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
const dryRun = argv.includes("--dry-run");
|
|
12
|
+
let tagsContent;
|
|
13
|
+
try {
|
|
14
|
+
tagsContent = readFileSync(RELEASE_TAGS_FILE, "utf8");
|
|
15
|
+
} catch {
|
|
16
|
+
throw new Error("No tags file found. Run `release-kit prepare` first.");
|
|
17
|
+
}
|
|
18
|
+
const tags = tagsContent.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
19
|
+
if (tags.length === 0) {
|
|
20
|
+
throw new Error("Tags file is empty. Run `release-kit prepare` first.");
|
|
21
|
+
}
|
|
22
|
+
let summary = "";
|
|
23
|
+
try {
|
|
24
|
+
summary = readFileSync(RELEASE_SUMMARY_FILE, "utf8").trim();
|
|
25
|
+
} catch (error) {
|
|
26
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
27
|
+
} else {
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const title = `release: ${tags.join(" ")}`;
|
|
32
|
+
const message = summary.length > 0 ? `${title}
|
|
33
|
+
|
|
34
|
+
${summary}` : title;
|
|
35
|
+
if (dryRun) {
|
|
36
|
+
console.info("[dry-run] Would create commit with message:\n");
|
|
37
|
+
console.info(message);
|
|
38
|
+
try {
|
|
39
|
+
const status = execFileSync("git", ["status", "--porcelain"], { encoding: "utf8" });
|
|
40
|
+
if (status.trim().length > 0) {
|
|
41
|
+
console.info("\nUncommitted changes:");
|
|
42
|
+
console.info(status.trimEnd());
|
|
43
|
+
}
|
|
44
|
+
} catch {
|
|
45
|
+
console.info("(Could not determine uncommitted changes)");
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
execFileSync("git", ["add", "-A"]);
|
|
50
|
+
execFileSync("git", ["commit", "-m", message]);
|
|
51
|
+
console.info(`Created release commit: ${title}`);
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
commitCommand
|
|
55
|
+
};
|
package/dist/esm/createTags.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
2
|
import { readFileSync, unlinkSync } from "node:fs";
|
|
3
|
-
import { RELEASE_TAGS_FILE } from "./prepareCommand.js";
|
|
3
|
+
import { RELEASE_SUMMARY_FILE, RELEASE_TAGS_FILE } from "./prepareCommand.js";
|
|
4
4
|
function createTags(options) {
|
|
5
5
|
const { dryRun, noGitChecks } = options;
|
|
6
6
|
let content;
|
|
@@ -43,6 +43,7 @@ function createTags(options) {
|
|
|
43
43
|
console.info(`\u{1F3F7}\uFE0F ${tag}`);
|
|
44
44
|
}
|
|
45
45
|
deleteTagsFile();
|
|
46
|
+
deleteSummaryFile();
|
|
46
47
|
return tags;
|
|
47
48
|
}
|
|
48
49
|
function deleteTagsFile() {
|
|
@@ -55,6 +56,16 @@ function deleteTagsFile() {
|
|
|
55
56
|
throw error;
|
|
56
57
|
}
|
|
57
58
|
}
|
|
59
|
+
function deleteSummaryFile() {
|
|
60
|
+
try {
|
|
61
|
+
unlinkSync(RELEASE_SUMMARY_FILE);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
58
69
|
function assertCleanWorkingTree() {
|
|
59
70
|
try {
|
|
60
71
|
execFileSync("git", ["diff", "--quiet"]);
|
|
@@ -4,4 +4,4 @@ export interface BumpDetermination {
|
|
|
4
4
|
parsedCommitCount: number;
|
|
5
5
|
unparseableCommits: Commit[] | undefined;
|
|
6
6
|
}
|
|
7
|
-
export declare function determineBumpFromCommits(commits: Commit[], workTypes: Record<string, WorkTypeConfig>, versionPatterns: VersionPatterns,
|
|
7
|
+
export declare function determineBumpFromCommits(commits: Commit[], workTypes: Record<string, WorkTypeConfig>, versionPatterns: VersionPatterns, scopeAliases: Record<string, string> | undefined): BumpDetermination;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { determineBumpType } from "./determineBumpType.js";
|
|
2
2
|
import { parseCommitMessage } from "./parseCommitMessage.js";
|
|
3
|
-
function determineBumpFromCommits(commits, workTypes, versionPatterns,
|
|
3
|
+
function determineBumpFromCommits(commits, workTypes, versionPatterns, scopeAliases) {
|
|
4
4
|
const parsedCommits = [];
|
|
5
5
|
const unparseable = [];
|
|
6
6
|
for (const commit of commits) {
|
|
7
|
-
const parsed = parseCommitMessage(commit.message, commit.hash, workTypes,
|
|
7
|
+
const parsed = parseCommitMessage(commit.message, commit.hash, workTypes, scopeAliases);
|
|
8
8
|
if (parsed === void 0) {
|
|
9
9
|
unparseable.push(commit);
|
|
10
10
|
} else {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ReleaseConfig } from './types.ts';
|
|
2
|
+
export declare function buildTagPattern(tagPrefix: string): string;
|
|
2
3
|
export interface GenerateChangelogOptions {
|
|
4
|
+
tagPattern?: string;
|
|
3
5
|
includePaths?: string[];
|
|
4
6
|
}
|
|
5
7
|
export declare function generateChangelog(config: Pick<ReleaseConfig, 'cliffConfigPath'>, changelogPath: string, tag: string, dryRun: boolean, options?: GenerateChangelogOptions): string[];
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
2
|
import { resolveCliffConfigPath } from "./resolveCliffConfigPath.js";
|
|
3
|
+
function buildTagPattern(tagPrefix) {
|
|
4
|
+
return `${tagPrefix}[0-9].*`;
|
|
5
|
+
}
|
|
3
6
|
function generateChangelog(config, changelogPath, tag, dryRun, options) {
|
|
4
7
|
const cliffConfigPath = resolveCliffConfigPath(config.cliffConfigPath, import.meta.url);
|
|
5
8
|
const outputFile = `${changelogPath}/CHANGELOG.md`;
|
|
6
9
|
const args = ["--config", cliffConfigPath, "--output", outputFile, "--tag", tag];
|
|
10
|
+
if (options?.tagPattern !== void 0) {
|
|
11
|
+
args.push("--tag-pattern", options.tagPattern);
|
|
12
|
+
}
|
|
7
13
|
for (const includePath of options?.includePaths ?? []) {
|
|
8
14
|
args.push("--include-path", includePath);
|
|
9
15
|
}
|
|
@@ -19,13 +25,15 @@ function generateChangelog(config, changelogPath, tag, dryRun, options) {
|
|
|
19
25
|
return [outputFile];
|
|
20
26
|
}
|
|
21
27
|
function generateChangelogs(config, tag, dryRun) {
|
|
28
|
+
const tagPattern = buildTagPattern(config.tagPrefix);
|
|
22
29
|
const results = [];
|
|
23
30
|
for (const changelogPath of config.changelogPaths) {
|
|
24
|
-
results.push(...generateChangelog(config, changelogPath, tag, dryRun));
|
|
31
|
+
results.push(...generateChangelog(config, changelogPath, tag, dryRun, { tagPattern }));
|
|
25
32
|
}
|
|
26
33
|
return results;
|
|
27
34
|
}
|
|
28
35
|
export {
|
|
36
|
+
buildTagPattern,
|
|
29
37
|
generateChangelog,
|
|
30
38
|
generateChangelogs
|
|
31
39
|
};
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -7,8 +7,10 @@ export type { ResolvedTag } from './resolveReleaseTags.ts';
|
|
|
7
7
|
export type { LabelDefinition, SyncLabelsConfig } from './sync-labels/types.ts';
|
|
8
8
|
export type { BumpResult, Commit, ComponentConfig, ComponentOverride, ComponentPrepareResult, MonorepoReleaseConfig, ParsedCommit, PrepareResult, ReleaseConfig, ReleaseKitConfig, ReleaseType, VersionPatterns, WorkTypeConfig, } from './types.ts';
|
|
9
9
|
export { DEFAULT_VERSION_PATTERNS, DEFAULT_WORK_TYPES } from './defaults.ts';
|
|
10
|
+
export { buildReleaseSummary } from './buildReleaseSummary.ts';
|
|
10
11
|
export { bumpAllVersions } from './bumpAllVersions.ts';
|
|
11
12
|
export { bumpVersion } from './bumpVersion.ts';
|
|
13
|
+
export { commitCommand } from './commitCommand.ts';
|
|
12
14
|
export { component } from './component.ts';
|
|
13
15
|
export { createTags } from './createTags.ts';
|
|
14
16
|
export { detectPackageManager } from './detectPackageManager.ts';
|
|
@@ -17,9 +19,10 @@ export { discoverWorkspaces } from './discoverWorkspaces.ts';
|
|
|
17
19
|
export { generateChangelog, generateChangelogs } from './generateChangelogs.ts';
|
|
18
20
|
export { getCommitsSinceTarget } from './getCommitsSinceTarget.ts';
|
|
19
21
|
export { COMMIT_PREPROCESSOR_PATTERNS, parseCommitMessage } from './parseCommitMessage.ts';
|
|
20
|
-
export { RELEASE_TAGS_FILE, writeReleaseTags } from './prepareCommand.ts';
|
|
22
|
+
export { RELEASE_SUMMARY_FILE, RELEASE_TAGS_FILE, writeReleaseTags } from './prepareCommand.ts';
|
|
21
23
|
export { publish } from './publish.ts';
|
|
22
24
|
export { releasePrepare } from './releasePrepare.ts';
|
|
23
25
|
export { releasePrepareMono } from './releasePrepareMono.ts';
|
|
24
26
|
export { reportPrepare } from './reportPrepare.ts';
|
|
25
27
|
export { resolveReleaseTags } from './resolveReleaseTags.ts';
|
|
28
|
+
export { stripScope } from './stripScope.ts';
|
package/dist/esm/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { DEFAULT_VERSION_PATTERNS, DEFAULT_WORK_TYPES } from "./defaults.js";
|
|
2
|
+
import { buildReleaseSummary } from "./buildReleaseSummary.js";
|
|
2
3
|
import { bumpAllVersions } from "./bumpAllVersions.js";
|
|
3
4
|
import { bumpVersion } from "./bumpVersion.js";
|
|
5
|
+
import { commitCommand } from "./commitCommand.js";
|
|
4
6
|
import { component } from "./component.js";
|
|
5
7
|
import { createTags } from "./createTags.js";
|
|
6
8
|
import { detectPackageManager } from "./detectPackageManager.js";
|
|
@@ -9,19 +11,23 @@ import { discoverWorkspaces } from "./discoverWorkspaces.js";
|
|
|
9
11
|
import { generateChangelog, generateChangelogs } from "./generateChangelogs.js";
|
|
10
12
|
import { getCommitsSinceTarget } from "./getCommitsSinceTarget.js";
|
|
11
13
|
import { COMMIT_PREPROCESSOR_PATTERNS, parseCommitMessage } from "./parseCommitMessage.js";
|
|
12
|
-
import { RELEASE_TAGS_FILE, writeReleaseTags } from "./prepareCommand.js";
|
|
14
|
+
import { RELEASE_SUMMARY_FILE, RELEASE_TAGS_FILE, writeReleaseTags } from "./prepareCommand.js";
|
|
13
15
|
import { publish } from "./publish.js";
|
|
14
16
|
import { releasePrepare } from "./releasePrepare.js";
|
|
15
17
|
import { releasePrepareMono } from "./releasePrepareMono.js";
|
|
16
18
|
import { reportPrepare } from "./reportPrepare.js";
|
|
17
19
|
import { resolveReleaseTags } from "./resolveReleaseTags.js";
|
|
20
|
+
import { stripScope } from "./stripScope.js";
|
|
18
21
|
export {
|
|
19
22
|
COMMIT_PREPROCESSOR_PATTERNS,
|
|
20
23
|
DEFAULT_VERSION_PATTERNS,
|
|
21
24
|
DEFAULT_WORK_TYPES,
|
|
25
|
+
RELEASE_SUMMARY_FILE,
|
|
22
26
|
RELEASE_TAGS_FILE,
|
|
27
|
+
buildReleaseSummary,
|
|
23
28
|
bumpAllVersions,
|
|
24
29
|
bumpVersion,
|
|
30
|
+
commitCommand,
|
|
25
31
|
component,
|
|
26
32
|
createTags,
|
|
27
33
|
detectPackageManager,
|
|
@@ -36,5 +42,6 @@ export {
|
|
|
36
42
|
releasePrepareMono,
|
|
37
43
|
reportPrepare,
|
|
38
44
|
resolveReleaseTags,
|
|
45
|
+
stripScope,
|
|
39
46
|
writeReleaseTags
|
|
40
47
|
};
|
|
@@ -56,8 +56,10 @@ function initCommand({ dryRun, force, withConfig }) {
|
|
|
56
56
|
const configHint = withConfig ? "1. (Optional) Customize .config/release-kit.config.ts and .config/git-cliff.toml." : "1. (Optional) Run again with --with-config to scaffold config files.";
|
|
57
57
|
console.info(`
|
|
58
58
|
${configHint}
|
|
59
|
-
2.
|
|
60
|
-
3.
|
|
59
|
+
2. If this is a public repo, set provenance: true in .github/workflows/publish.yaml.
|
|
60
|
+
3. Test by running: npx @williamthorsen/release-kit prepare --dry-run
|
|
61
|
+
4. Commit the generated files.
|
|
62
|
+
5. Register each package as a trusted publisher on npmjs.com.
|
|
61
63
|
`);
|
|
62
64
|
return 0;
|
|
63
65
|
}
|
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { writeFileWithCheck } from "@williamthorsen/node-monorepo-core";
|
|
4
4
|
import { findPackageRoot } from "../findPackageRoot.js";
|
|
5
|
-
import { releaseConfigScript, releaseWorkflow } from "./templates.js";
|
|
5
|
+
import { publishWorkflow, releaseConfigScript, releaseWorkflow } from "./templates.js";
|
|
6
6
|
function copyCliffTemplate(dryRun, overwrite) {
|
|
7
7
|
const destPath = ".config/git-cliff.toml";
|
|
8
8
|
const root = findPackageRoot(import.meta.url);
|
|
@@ -21,7 +21,8 @@ function copyCliffTemplate(dryRun, overwrite) {
|
|
|
21
21
|
}
|
|
22
22
|
function scaffoldFiles({ repoType, dryRun, overwrite, withConfig }) {
|
|
23
23
|
const results = [
|
|
24
|
-
writeFileWithCheck(".github/workflows/release.yaml", releaseWorkflow(repoType), { dryRun, overwrite })
|
|
24
|
+
writeFileWithCheck(".github/workflows/release.yaml", releaseWorkflow(repoType), { dryRun, overwrite }),
|
|
25
|
+
writeFileWithCheck(".github/workflows/publish.yaml", publishWorkflow(repoType), { dryRun, overwrite })
|
|
25
26
|
];
|
|
26
27
|
if (withConfig) {
|
|
27
28
|
results.push(
|