@williamthorsen/release-kit 0.2.2 → 1.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 +43 -1
- package/README.md +202 -219
- package/dist/esm/.cache +1 -1
- package/dist/esm/bin/release-kit.d.ts +2 -0
- package/dist/esm/bin/release-kit.js +73 -0
- package/dist/esm/component.d.ts +2 -0
- package/dist/esm/component.js +15 -0
- package/dist/esm/defaults.d.ts +3 -2
- package/dist/esm/defaults.js +17 -12
- package/dist/esm/determineBumpType.d.ts +2 -2
- package/dist/esm/determineBumpType.js +11 -13
- package/dist/esm/discoverWorkspaces.d.ts +1 -0
- package/dist/esm/discoverWorkspaces.js +45 -0
- package/dist/esm/getCommitsSinceTarget.js +2 -1
- package/dist/esm/index.d.ts +5 -2
- package/dist/esm/index.js +11 -2
- package/dist/esm/init/checks.d.ts +9 -0
- package/dist/esm/init/checks.js +56 -0
- package/dist/esm/init/detectRepoType.d.ts +2 -0
- package/dist/esm/init/detectRepoType.js +19 -0
- package/dist/esm/init/initCommand.d.ts +5 -0
- package/dist/esm/init/initCommand.js +65 -0
- package/dist/esm/init/parseJsonRecord.d.ts +1 -0
- package/dist/esm/init/parseJsonRecord.js +15 -0
- package/dist/esm/init/prompt.d.ts +5 -0
- package/dist/esm/init/prompt.js +30 -0
- package/dist/esm/init/scaffold.d.ts +9 -0
- package/dist/esm/init/scaffold.js +65 -0
- package/dist/esm/init/templates.d.ts +3 -0
- package/dist/esm/init/templates.js +105 -0
- package/dist/esm/loadConfig.d.ts +5 -0
- package/dist/esm/loadConfig.js +91 -0
- package/dist/esm/parseCommitMessage.d.ts +1 -1
- package/dist/esm/parseCommitMessage.js +4 -4
- package/dist/esm/prepareCommand.d.ts +1 -0
- package/dist/esm/prepareCommand.js +77 -0
- package/dist/esm/releasePrepare.d.ts +1 -1
- package/dist/esm/releasePrepare.js +7 -3
- package/dist/esm/releasePrepareMono.d.ts +1 -1
- package/dist/esm/releasePrepareMono.js +16 -10
- package/dist/esm/runReleasePrepare.d.ts +9 -0
- package/dist/esm/runReleasePrepare.js +112 -0
- package/dist/esm/types.d.ts +22 -4
- package/dist/esm/validateConfig.d.ts +5 -0
- package/dist/esm/validateConfig.js +143 -0
- package/dist/tsconfig.generate-typings.tsbuildinfo +1 -1
- package/package.json +12 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
-
## [release-kit-
|
|
5
|
+
## [release-kit-v1.0.0] - 2026-03-12
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
- #28 release-kit|feat!: Migrate to CLI-driven release preparation with auto-discovery (#31)
|
|
10
|
+
|
|
11
|
+
Replaces release-kit's script-based release preparation with a self-contained CLI (`npx @williamthorsen/release-kit prepare`) that auto-discovers workspaces from `pnpm-workspace.yaml`. Adds workspace auto-discovery, TypeScript config loading via jiti, config validation, and a `component()` factory that accepts full workspace-relative paths. Refactors the type system: `WorkTypeConfig` becomes a record keyed by type name, version-bump rules move to a separate `VersionPatterns` structure, and `ComponentConfig` gains a `dir` field for canonical directory identity.
|
|
12
|
+
|
|
13
|
+
### Refactoring
|
|
14
|
+
|
|
15
|
+
- #28 release-kit|refactor: Adjust location of config & tags file
|
|
16
|
+
|
|
17
|
+
### Tooling
|
|
18
|
+
|
|
19
|
+
- #28 release-kit|tooling: Remove legacy release-kit scripts
|
|
20
|
+
|
|
21
|
+
## [release-kit-v0.3.0] - 2026-03-11
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
- Release-kit|feat: Extract CLI runner into release-kit and co-locate scripts with workflow
|
|
26
|
+
|
|
27
|
+
Move release script logic (arg parsing, validation, component filtering) into a reusable `runReleasePrepare` function in the release-kit package. Consuming repos now provide only their config and call `runReleasePrepare(config)`.
|
|
28
|
+
|
|
29
|
+
Relocate release-prepare.ts and release.config.ts from scripts/ to .github/scripts/ so they live alongside the workflow they serve.
|
|
30
|
+
|
|
31
|
+
- #20 release-kit|feat: Add release-kit init CLI command for automated repo setup (#22)
|
|
32
|
+
|
|
33
|
+
Add an interactive `npx release-kit init` CLI command that checks repo eligibility, detects monorepo vs single-package layout, scaffolds workflow/scripts/config files, and updates `package.json` with release scripts.
|
|
34
|
+
|
|
35
|
+
Also expand `runReleasePrepare` to polymorphically handle both `MonorepoReleaseConfig` and `ReleaseConfig`, and update the esbuild plugin to preserve shebangs during compilation.
|
|
36
|
+
|
|
37
|
+
- #24 release-kit|feat: Return computed tags from release prepare and write .release-tags (#27)
|
|
38
|
+
|
|
39
|
+
`releasePrepare` and `releasePrepareMono` now return `string[]` of computed tag names instead of `void`. `runReleasePrepare` writes these tags to a `.release-tags` file (one tag per line) so the CI workflow can read them instead of independently deriving tag names from `git diff`. In dry-run mode the file is not written. This makes `tagPrefix` the single source of truth for tag names, eliminating the mismatch between TypeScript-computed tags and workflow-derived tags.
|
|
40
|
+
|
|
41
|
+
## [strings-v3.1.1] - 2026-03-10
|
|
42
|
+
|
|
43
|
+
### Tooling
|
|
44
|
+
|
|
45
|
+
- \*|tooling: Change package registry from github to npmjs
|
|
46
|
+
|
|
47
|
+
## [tools-v3.0.1] - 2026-03-10
|
|
6
48
|
|
|
7
49
|
### Tooling
|
|
8
50
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Version-bumping and changelog-generation toolkit for release workflows.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Provides a self-contained CLI that auto-discovers workspaces from `pnpm-workspace.yaml`, parses conventional commits, determines version bumps, updates `package.json` files, and generates changelogs with `git-cliff`.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -10,254 +10,195 @@ This package extracts the shared release-preparation logic from the `skypilot-si
|
|
|
10
10
|
pnpm add -D @williamthorsen/release-kit git-cliff
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# 1. Set up release-kit in your repo (scaffolds workflow + optional config)
|
|
17
|
+
npx @williamthorsen/release-kit init
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
@williamthorsen
|
|
19
|
+
# 2. Preview what a release would do
|
|
20
|
+
npx @williamthorsen/release-kit prepare --dry-run
|
|
21
|
+
|
|
22
|
+
# 3. Copy cliff.toml.template to your repo root (if init didn't create one)
|
|
23
|
+
cp node_modules/@williamthorsen/release-kit/cliff.toml.template cliff.toml
|
|
17
24
|
```
|
|
18
25
|
|
|
19
|
-
|
|
26
|
+
That's it for most repos. The CLI auto-discovers workspaces and applies sensible defaults. Customize only what you need via `.config/release-kit.config.ts`.
|
|
20
27
|
|
|
21
|
-
|
|
22
|
-
2. Create `scripts/release-prepare.ts` and `scripts/release.config.ts` (see examples below)
|
|
23
|
-
3. Add `release:prepare` scripts to `package.json`
|
|
24
|
-
4. Copy `cliff.toml.template` to your repo root as `cliff.toml`
|
|
25
|
-
5. Add the GitHub Actions release workflow
|
|
28
|
+
## How it works
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
1. **Workspace discovery**: reads `pnpm-workspace.yaml` and resolves its `packages` globs to find workspace directories. Each directory containing a `package.json` becomes a component. If no workspace file is found, the repo is treated as a single-package project.
|
|
31
|
+
2. **Config loading**: loads `.config/release-kit.config.ts` (if present) via [jiti](https://github.com/unjs/jiti) and merges it with discovered defaults.
|
|
32
|
+
3. **Commit analysis**: for each component, finds commits since the last version tag, parses them for type and scope, and determines the appropriate version bump.
|
|
33
|
+
4. **Version bump + changelog**: bumps `package.json` versions and generates changelogs via `git-cliff`.
|
|
34
|
+
5. **Release tags file**: writes computed tags to `/tmp/release-kit/.release-tags` for CI consumption.
|
|
28
35
|
|
|
29
|
-
|
|
36
|
+
## CLI reference
|
|
30
37
|
|
|
31
|
-
|
|
38
|
+
### `release-kit prepare`
|
|
39
|
+
|
|
40
|
+
Run release preparation with automatic workspace discovery.
|
|
32
41
|
|
|
33
|
-
```typescript
|
|
34
|
-
import { DEFAULT_WORK_TYPES } from '@williamthorsen/release-kit';
|
|
35
|
-
import type { ReleaseConfig } from '@williamthorsen/release-kit';
|
|
36
|
-
|
|
37
|
-
export const config: ReleaseConfig = {
|
|
38
|
-
tagPrefix: 'v',
|
|
39
|
-
packageFiles: ['package.json'],
|
|
40
|
-
changelogPaths: ['.'],
|
|
41
|
-
workTypes: [...DEFAULT_WORK_TYPES],
|
|
42
|
-
formatCommand: 'pnpm run fmt',
|
|
43
|
-
};
|
|
44
42
|
```
|
|
43
|
+
Usage: release-kit prepare [options]
|
|
45
44
|
|
|
46
|
-
|
|
45
|
+
Options:
|
|
46
|
+
--dry-run Preview changes without writing files
|
|
47
|
+
--bump=major|minor|patch Override the bump type for all components
|
|
48
|
+
--only=name1,name2 Only process the named components (monorepo only)
|
|
49
|
+
--help, -h Show help
|
|
50
|
+
```
|
|
47
51
|
|
|
48
|
-
|
|
52
|
+
Component names for `--only` match the package directory name (e.g., `arrays`, `release-kit`).
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
import { DEFAULT_WORK_TYPES } from '@williamthorsen/release-kit';
|
|
52
|
-
import type { MonorepoReleaseConfig } from '@williamthorsen/release-kit';
|
|
54
|
+
**Self-hosting note**: in a repo where `release-kit` is a workspace package (e.g., this monorepo), `npx` and `pnpm exec` may not resolve the binary. Run the built entry point directly:
|
|
53
55
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
tagPrefix: `${dir}-v`,
|
|
57
|
-
packageFiles: [`packages/${dir}/package.json`],
|
|
58
|
-
changelogPaths: [`packages/${dir}`],
|
|
59
|
-
paths: [`packages/${dir}/**`],
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export const config: MonorepoReleaseConfig = {
|
|
64
|
-
components: [component('my-lib'), component('my-cli')],
|
|
65
|
-
workTypes: [...DEFAULT_WORK_TYPES],
|
|
66
|
-
formatCommand: 'pnpm run fmt',
|
|
67
|
-
};
|
|
56
|
+
```bash
|
|
57
|
+
node packages/release-kit/dist/esm/bin/release-kit.js prepare --dry-run
|
|
68
58
|
```
|
|
69
59
|
|
|
70
|
-
###
|
|
60
|
+
### `release-kit init`
|
|
61
|
+
|
|
62
|
+
Initialize release-kit in the current repository. Scaffolds a GitHub Actions workflow and an optional config file.
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
Usage: release-kit init [options]
|
|
71
66
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
| `changelogPaths` | `string[]` | Yes | Directories in which to generate changelogs |
|
|
77
|
-
| `workTypes` | `WorkTypeConfig[]` | Yes | Ordered list of work type configurations for commit categorization |
|
|
78
|
-
| `formatCommand` | `string` | No | Shell command to run after changelog generation |
|
|
79
|
-
| `cliffConfigPath` | `string` | No | Path to `cliff.toml` (defaults to `'cliff.toml'`) |
|
|
67
|
+
Options:
|
|
68
|
+
--dry-run Preview changes without writing files
|
|
69
|
+
--help, -h Show help
|
|
70
|
+
```
|
|
80
71
|
|
|
81
|
-
|
|
72
|
+
Scaffolded files:
|
|
82
73
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
| `workTypes` | `WorkTypeConfig[]` | Yes | Shared work type configurations |
|
|
87
|
-
| `formatCommand` | `string` | No | Shell command to run after changelog generation |
|
|
74
|
+
- `.config/release-kit.config.ts` — starter config with commented-out customization examples
|
|
75
|
+
- `.github/workflows/release.yaml` — workflow that delegates to a reusable release workflow
|
|
76
|
+
- `cliff.toml` — copied from the bundled template (prompted if missing)
|
|
88
77
|
|
|
89
|
-
##
|
|
78
|
+
## Configuration
|
|
90
79
|
|
|
91
|
-
Create
|
|
80
|
+
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.
|
|
92
81
|
|
|
93
|
-
###
|
|
82
|
+
### Config file
|
|
94
83
|
|
|
95
84
|
```typescript
|
|
96
|
-
import {
|
|
97
|
-
import type { ReleaseType } from '@williamthorsen/release-kit';
|
|
98
|
-
import { config } from './release.config.ts';
|
|
85
|
+
import type { ReleaseKitConfig } from '@williamthorsen/release-kit';
|
|
99
86
|
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
process.exit(1);
|
|
114
|
-
}
|
|
115
|
-
bumpOverride = value as ReleaseType;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return { dryRun, bumpOverride };
|
|
120
|
-
}
|
|
87
|
+
const config: ReleaseKitConfig = {
|
|
88
|
+
// Exclude a component from release processing
|
|
89
|
+
components: [{ dir: 'internal-tools', shouldExclude: true }],
|
|
90
|
+
|
|
91
|
+
// Run a formatter after changelog generation
|
|
92
|
+
formatCommand: 'pnpm run fmt',
|
|
93
|
+
|
|
94
|
+
// Override the default version patterns
|
|
95
|
+
versionPatterns: { major: ['!'], minor: ['feat', 'feature'] },
|
|
96
|
+
|
|
97
|
+
// Add or override work types (merged with defaults by key)
|
|
98
|
+
workTypes: { perf: { header: 'Performance' } },
|
|
99
|
+
};
|
|
121
100
|
|
|
122
|
-
|
|
123
|
-
releasePrepare(config, { dryRun, ...(bumpOverride ? { bumpOverride } : {}) });
|
|
101
|
+
export default config;
|
|
124
102
|
```
|
|
125
103
|
|
|
126
|
-
|
|
104
|
+
The config file supports both `export default config` and `export const config = { ... }`.
|
|
127
105
|
|
|
128
|
-
|
|
129
|
-
import { releasePrepareMono } from '@williamthorsen/release-kit';
|
|
130
|
-
import type { ReleaseType } from '@williamthorsen/release-kit';
|
|
131
|
-
import { config } from './release.config.ts';
|
|
106
|
+
### `ReleaseKitConfig` reference
|
|
132
107
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
for (const arg of args) {
|
|
142
|
-
if (arg === '--dry-run') dryRun = true;
|
|
143
|
-
else if (arg.startsWith('--bump=')) {
|
|
144
|
-
const value = arg.slice('--bump='.length);
|
|
145
|
-
if (!VALID_BUMP_TYPES.includes(value)) {
|
|
146
|
-
console.error(`Invalid bump type "${value}". Must be: ${VALID_BUMP_TYPES.join(', ')}`);
|
|
147
|
-
process.exit(1);
|
|
148
|
-
}
|
|
149
|
-
bumpOverride = value as ReleaseType;
|
|
150
|
-
} else if (arg.startsWith('--only=')) {
|
|
151
|
-
only = arg.slice('--only='.length).split(',');
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return { dryRun, bumpOverride, only };
|
|
156
|
-
}
|
|
108
|
+
| Field | Type | Description |
|
|
109
|
+
| ------------------ | -------------------------------- | ------------------------------------------------------------ |
|
|
110
|
+
| `cliffConfigPath` | `string` | Path to `cliff.toml` (defaults to `'cliff.toml'`) |
|
|
111
|
+
| `components` | `ComponentOverride[]` | Override or exclude discovered components (matched by `dir`) |
|
|
112
|
+
| `formatCommand` | `string` | Shell command to run after changelog generation |
|
|
113
|
+
| `versionPatterns` | `VersionPatterns` | Rules for which commit types trigger major/minor bumps |
|
|
114
|
+
| `workspaceAliases` | `Record<string, string>` | Maps shorthand workspace names to canonical names in commits |
|
|
115
|
+
| `workTypes` | `Record<string, WorkTypeConfig>` | Work type definitions, merged with defaults by key |
|
|
157
116
|
|
|
158
|
-
|
|
117
|
+
All fields are optional.
|
|
159
118
|
|
|
160
|
-
|
|
161
|
-
if (only) {
|
|
162
|
-
const filtered = config.components.filter((c) => {
|
|
163
|
-
const name = c.tagPrefix.replace(/-v$/, '');
|
|
164
|
-
return only.includes(name);
|
|
165
|
-
});
|
|
166
|
-
effectiveConfig = { ...config, components: filtered };
|
|
167
|
-
}
|
|
119
|
+
### `ComponentOverride`
|
|
168
120
|
|
|
169
|
-
|
|
121
|
+
```typescript
|
|
122
|
+
interface ComponentOverride {
|
|
123
|
+
dir: string; // Package directory name (e.g., 'arrays')
|
|
124
|
+
tagPrefix?: string; // Custom git tag prefix (defaults to '${dir}-v')
|
|
125
|
+
shouldExclude?: boolean; // If true, exclude from release processing
|
|
126
|
+
}
|
|
170
127
|
```
|
|
171
128
|
|
|
172
|
-
###
|
|
129
|
+
### `VersionPatterns`
|
|
173
130
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
131
|
+
Defines which commit types trigger major or minor bumps. Any recognized type not listed defaults to a patch bump.
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
interface VersionPatterns {
|
|
135
|
+
major: string[]; // Patterns triggering a major bump ('!' = any breaking change)
|
|
136
|
+
minor: string[]; // Commit types triggering a minor bump
|
|
180
137
|
}
|
|
181
138
|
```
|
|
182
139
|
|
|
183
|
-
|
|
140
|
+
Default: `{ major: ['!'], minor: ['feat', 'feature'] }`
|
|
184
141
|
|
|
185
|
-
###
|
|
142
|
+
### Default work types
|
|
186
143
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
144
|
+
| Key | Header | Aliases |
|
|
145
|
+
| ---------- | ------------- | --------- |
|
|
146
|
+
| `fix` | Bug fixes | `bugfix` |
|
|
147
|
+
| `feat` | Features | `feature` |
|
|
148
|
+
| `internal` | Internal | |
|
|
149
|
+
| `refactor` | Refactoring | |
|
|
150
|
+
| `tests` | Tests | `test` |
|
|
151
|
+
| `tooling` | Tooling | |
|
|
152
|
+
| `ci` | CI | |
|
|
153
|
+
| `deps` | Dependencies | `dep` |
|
|
154
|
+
| `docs` | Documentation | `doc` |
|
|
155
|
+
| `fmt` | Formatting | |
|
|
190
156
|
|
|
191
|
-
|
|
192
|
-
workflow_dispatch:
|
|
193
|
-
inputs:
|
|
194
|
-
bump:
|
|
195
|
-
description: 'Override bump type (leave empty to auto-detect)'
|
|
196
|
-
required: false
|
|
197
|
-
type: choice
|
|
198
|
-
options:
|
|
199
|
-
- ''
|
|
200
|
-
- patch
|
|
201
|
-
- minor
|
|
202
|
-
- major
|
|
157
|
+
Work types from your config are merged with these defaults by key — your entries override or extend, they don't replace the full set.
|
|
203
158
|
|
|
204
|
-
|
|
205
|
-
contents: write
|
|
159
|
+
## Commit format
|
|
206
160
|
|
|
207
|
-
|
|
208
|
-
release:
|
|
209
|
-
runs-on: ubuntu-latest
|
|
210
|
-
steps:
|
|
211
|
-
- uses: actions/checkout@v4
|
|
212
|
-
with:
|
|
213
|
-
fetch-depth: 0
|
|
214
|
-
token: ${{ secrets.GITHUB_TOKEN }}
|
|
161
|
+
release-kit parses commits in these formats:
|
|
215
162
|
|
|
216
|
-
|
|
163
|
+
```
|
|
164
|
+
type: description # e.g., feat: add utility
|
|
165
|
+
type(scope): description # e.g., fix(parser): handle edge case
|
|
166
|
+
workspace|type: description # e.g., arrays|feat: add compact function
|
|
167
|
+
!type: description # breaking change (triggers major bump)
|
|
168
|
+
```
|
|
217
169
|
|
|
218
|
-
|
|
219
|
-
with:
|
|
220
|
-
node-version: '24'
|
|
221
|
-
cache: 'pnpm'
|
|
170
|
+
The `workspace|type:` format scopes a commit to a specific workspace in a monorepo. Use `workspaceAliases` in your config to map shorthand names to canonical workspace names.
|
|
222
171
|
|
|
223
|
-
|
|
172
|
+
## Using `component()` for manual configuration
|
|
224
173
|
|
|
225
|
-
|
|
226
|
-
id: prepare
|
|
227
|
-
run: |
|
|
228
|
-
ARGS=""
|
|
229
|
-
if [ -n "${{ inputs.bump }}" ]; then
|
|
230
|
-
ARGS="--bump=${{ inputs.bump }}"
|
|
231
|
-
fi
|
|
232
|
-
pnpm run release:prepare $ARGS
|
|
233
|
-
VERSION=$(node -p "require('./package.json').version")
|
|
234
|
-
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
174
|
+
If you need to build a `MonorepoReleaseConfig` manually (e.g., for the legacy script-based approach), the exported `component()` helper creates a `ComponentConfig` from a workspace-relative path:
|
|
235
175
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
git add -A
|
|
252
|
-
git commit -m "release: v${{ steps.prepare.outputs.version }}"
|
|
253
|
-
git tag "v${{ steps.prepare.outputs.version }}"
|
|
254
|
-
git push origin main "v${{ steps.prepare.outputs.version }}"
|
|
176
|
+
```typescript
|
|
177
|
+
import { component } from '@williamthorsen/release-kit';
|
|
178
|
+
|
|
179
|
+
// Accepts the full workspace-relative path
|
|
180
|
+
component('packages/arrays');
|
|
181
|
+
// => {
|
|
182
|
+
// dir: 'arrays',
|
|
183
|
+
// tagPrefix: 'arrays-v',
|
|
184
|
+
// packageFiles: ['packages/arrays/package.json'],
|
|
185
|
+
// changelogPaths: ['packages/arrays'],
|
|
186
|
+
// paths: ['packages/arrays/**'],
|
|
187
|
+
// }
|
|
188
|
+
|
|
189
|
+
// Custom tag prefix
|
|
190
|
+
component('libs/core', 'core-v');
|
|
255
191
|
```
|
|
256
192
|
|
|
193
|
+
The `dir` field is derived from `path.basename()`, so `packages/arrays` and `libs/arrays` both produce `dir: 'arrays'`.
|
|
194
|
+
|
|
195
|
+
## GitHub Actions workflow
|
|
196
|
+
|
|
197
|
+
The `init` command scaffolds a workflow that delegates to a reusable release workflow. For repos that need a self-contained workflow:
|
|
198
|
+
|
|
257
199
|
### Monorepo
|
|
258
200
|
|
|
259
201
|
```yaml
|
|
260
|
-
# .github/workflows/release.yaml
|
|
261
202
|
name: Release
|
|
262
203
|
|
|
263
204
|
on:
|
|
@@ -293,7 +234,7 @@ jobs:
|
|
|
293
234
|
|
|
294
235
|
- uses: actions/setup-node@v4
|
|
295
236
|
with:
|
|
296
|
-
node-version: '
|
|
237
|
+
node-version: '22'
|
|
297
238
|
cache: 'pnpm'
|
|
298
239
|
|
|
299
240
|
- run: pnpm install
|
|
@@ -307,7 +248,7 @@ jobs:
|
|
|
307
248
|
if [ -n "${{ inputs.bump }}" ]; then
|
|
308
249
|
ARGS="$ARGS --bump=${{ inputs.bump }}"
|
|
309
250
|
fi
|
|
310
|
-
|
|
251
|
+
npx @williamthorsen/release-kit prepare $ARGS
|
|
311
252
|
|
|
312
253
|
- name: Check for changes
|
|
313
254
|
id: check
|
|
@@ -319,18 +260,13 @@ jobs:
|
|
|
319
260
|
echo "changed=true" >> "$GITHUB_OUTPUT"
|
|
320
261
|
fi
|
|
321
262
|
|
|
322
|
-
- name:
|
|
263
|
+
- name: Read release tags
|
|
323
264
|
if: steps.check.outputs.changed == 'true'
|
|
324
265
|
id: tags
|
|
325
266
|
run: |
|
|
326
|
-
TAGS
|
|
327
|
-
for pkg in $(git diff --name-only -- 'packages/*/package.json'); do
|
|
328
|
-
DIR=$(echo "$pkg" | cut -d/ -f2)
|
|
329
|
-
VERSION=$(node -p "require('./$pkg').version")
|
|
330
|
-
TAGS="$TAGS ${DIR}-v${VERSION}"
|
|
331
|
-
done
|
|
267
|
+
TAGS=$(cat /tmp/release-kit/.release-tags | tr '\n' ' ')
|
|
332
268
|
echo "tags=$TAGS" >> "$GITHUB_OUTPUT"
|
|
333
|
-
echo "Releasing
|
|
269
|
+
echo "Releasing: $TAGS"
|
|
334
270
|
|
|
335
271
|
- name: Commit, tag, and push
|
|
336
272
|
if: steps.check.outputs.changed == 'true'
|
|
@@ -345,21 +281,44 @@ jobs:
|
|
|
345
281
|
git push origin main ${{ steps.tags.outputs.tags }}
|
|
346
282
|
```
|
|
347
283
|
|
|
284
|
+
### Single-package repo
|
|
285
|
+
|
|
286
|
+
The same workflow without the `only` input. Replace the prepare step with:
|
|
287
|
+
|
|
288
|
+
```yaml
|
|
289
|
+
- name: Run release preparation
|
|
290
|
+
run: |
|
|
291
|
+
ARGS=""
|
|
292
|
+
if [ -n "${{ inputs.bump }}" ]; then
|
|
293
|
+
ARGS="--bump=${{ inputs.bump }}"
|
|
294
|
+
fi
|
|
295
|
+
npx @williamthorsen/release-kit prepare $ARGS
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
And the tag step with:
|
|
299
|
+
|
|
300
|
+
```yaml
|
|
301
|
+
- name: Read release tag
|
|
302
|
+
if: steps.check.outputs.changed == 'true'
|
|
303
|
+
id: tags
|
|
304
|
+
run: |
|
|
305
|
+
TAG=$(cat /tmp/release-kit/.release-tags)
|
|
306
|
+
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
|
307
|
+
```
|
|
308
|
+
|
|
348
309
|
## Triggering a release
|
|
349
310
|
|
|
350
311
|
```sh
|
|
351
|
-
#
|
|
352
|
-
gh workflow run release.yaml
|
|
353
|
-
gh workflow run release.yaml -f bump=minor
|
|
354
|
-
|
|
355
|
-
# Monorepo: all components
|
|
312
|
+
# All components
|
|
356
313
|
gh workflow run release.yaml
|
|
357
314
|
|
|
358
|
-
#
|
|
359
|
-
gh workflow run release.yaml -f only=
|
|
360
|
-
gh workflow run release.yaml -f only=
|
|
315
|
+
# Specific component(s)
|
|
316
|
+
gh workflow run release.yaml -f only=arrays
|
|
317
|
+
gh workflow run release.yaml -f only=arrays,strings -f bump=minor
|
|
361
318
|
```
|
|
362
319
|
|
|
320
|
+
Or use the GitHub UI: Actions > Release > Run workflow.
|
|
321
|
+
|
|
363
322
|
## cliff.toml setup
|
|
364
323
|
|
|
365
324
|
The package includes a `cliff.toml.template` with a generic git-cliff configuration that:
|
|
@@ -383,13 +342,37 @@ This package shells out to two external tools:
|
|
|
383
342
|
- **`git`** — must be available on `PATH`. Used to find tags and retrieve commit history.
|
|
384
343
|
- **`git-cliff`** — must be available on `PATH`. Add `git-cliff` as a dev dependency to make it available in CI.
|
|
385
344
|
|
|
345
|
+
## Legacy script-based approach
|
|
346
|
+
|
|
347
|
+
The CLI-driven approach is recommended for new setups. The script-based approach (using `runReleasePrepare` with a manually maintained config) is still supported for backward compatibility.
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
// .github/scripts/release.config.ts
|
|
351
|
+
import type { MonorepoReleaseConfig } from '@williamthorsen/release-kit';
|
|
352
|
+
import { component } from '@williamthorsen/release-kit';
|
|
353
|
+
|
|
354
|
+
export const config: MonorepoReleaseConfig = {
|
|
355
|
+
components: [component('packages/arrays'), component('packages/strings')],
|
|
356
|
+
formatCommand: 'pnpm run fmt',
|
|
357
|
+
};
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
// .github/scripts/release-prepare.ts
|
|
362
|
+
import { runReleasePrepare } from '@williamthorsen/release-kit';
|
|
363
|
+
import { config } from './release.config.ts';
|
|
364
|
+
|
|
365
|
+
runReleasePrepare(config);
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
The key difference: the script-based approach requires manually listing every component, while the CLI auto-discovers them from `pnpm-workspace.yaml`.
|
|
369
|
+
|
|
386
370
|
## Migration from changesets
|
|
387
371
|
|
|
388
372
|
1. Add `@williamthorsen/release-kit` and `git-cliff` as dev dependencies.
|
|
389
373
|
2. Remove `@changesets/cli` from dev dependencies.
|
|
390
374
|
3. Delete the `.changeset/` directory.
|
|
391
|
-
4.
|
|
392
|
-
5.
|
|
393
|
-
6. Copy `cliff.toml.template` to your repo root as `cliff.toml
|
|
394
|
-
7.
|
|
395
|
-
8. Create an initial version tag for each package (e.g., `git tag v1.0.0` or `git tag my-lib-v1.0.0`).
|
|
375
|
+
4. Run `npx @williamthorsen/release-kit init` to scaffold workflow and config files.
|
|
376
|
+
5. Remove `changeset:*` scripts from `package.json` (no replacement needed — the CLI handles everything).
|
|
377
|
+
6. Copy `cliff.toml.template` to your repo root as `cliff.toml` (if `init` didn't create one).
|
|
378
|
+
7. Create an initial version tag for each package (e.g., `git tag v1.0.0` or `git tag arrays-v1.0.0`).
|
package/dist/esm/.cache
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
f68170895c39861df163752e69beb845e3033a1334b92a564a1dc3b95ff170ca
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { initCommand } from "../init/initCommand.js";
|
|
3
|
+
import { prepareCommand } from "../prepareCommand.js";
|
|
4
|
+
function showUsage() {
|
|
5
|
+
console.info(`
|
|
6
|
+
Usage: release-kit <command> [options]
|
|
7
|
+
|
|
8
|
+
Commands:
|
|
9
|
+
prepare Run release preparation (auto-discovers workspaces)
|
|
10
|
+
init Initialize release-kit in the current repository
|
|
11
|
+
|
|
12
|
+
Options:
|
|
13
|
+
--dry-run Preview changes without writing files
|
|
14
|
+
--help, -h Show this help message
|
|
15
|
+
`);
|
|
16
|
+
}
|
|
17
|
+
function showInitHelp() {
|
|
18
|
+
console.info(`
|
|
19
|
+
Usage: release-kit init [options]
|
|
20
|
+
|
|
21
|
+
Initialize release-kit in the current repository.
|
|
22
|
+
Scaffolds workflow and config files.
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
--dry-run Preview changes without writing files
|
|
26
|
+
--help, -h Show this help message
|
|
27
|
+
`);
|
|
28
|
+
}
|
|
29
|
+
function showPrepareHelp() {
|
|
30
|
+
console.info(`
|
|
31
|
+
Usage: release-kit prepare [options]
|
|
32
|
+
|
|
33
|
+
Run release preparation with automatic workspace discovery.
|
|
34
|
+
|
|
35
|
+
Options:
|
|
36
|
+
--dry-run Run without modifying any files
|
|
37
|
+
--bump=major|minor|patch Override the bump type for all components
|
|
38
|
+
--only=name1,name2 Only process the named components (comma-separated, monorepo only)
|
|
39
|
+
--help, -h Show this help message
|
|
40
|
+
`);
|
|
41
|
+
}
|
|
42
|
+
const args = process.argv.slice(2);
|
|
43
|
+
const command = args[0];
|
|
44
|
+
const flags = args.slice(1);
|
|
45
|
+
if (command === "--help" || command === "-h" || command === void 0) {
|
|
46
|
+
showUsage();
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
if (command === "prepare") {
|
|
50
|
+
if (flags.some((f) => f === "--help" || f === "-h")) {
|
|
51
|
+
showPrepareHelp();
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
await prepareCommand(flags);
|
|
55
|
+
process.exit(0);
|
|
56
|
+
}
|
|
57
|
+
if (command === "init") {
|
|
58
|
+
if (flags.some((f) => f === "--help" || f === "-h")) {
|
|
59
|
+
showInitHelp();
|
|
60
|
+
process.exit(0);
|
|
61
|
+
}
|
|
62
|
+
const unknownFlags = flags.filter((f) => f !== "--dry-run" && f !== "--help" && f !== "-h");
|
|
63
|
+
if (unknownFlags.length > 0) {
|
|
64
|
+
console.error(`Error: Unknown option: ${unknownFlags[0]}`);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
const dryRun = flags.includes("--dry-run");
|
|
68
|
+
const exitCode = await initCommand({ dryRun });
|
|
69
|
+
process.exit(exitCode);
|
|
70
|
+
}
|
|
71
|
+
console.error(`Error: Unknown command: ${command}`);
|
|
72
|
+
showUsage();
|
|
73
|
+
process.exit(1);
|