@releasekit/release 0.3.0 → 0.4.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/README.md +22 -1
- package/dist/chunk-I5CGC253.js +438 -0
- package/dist/chunk-WNKYXS62.js +46 -0
- package/dist/chunk-YZHGXRG6.js +651 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +58 -0
- package/dist/dispatcher.d.ts +6 -0
- package/dist/dispatcher.js +92 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +10 -0
- package/docs/ci-setup.md +266 -0
- package/package.json +7 -6
package/dist/cli.js
CHANGED
|
@@ -1 +1,59 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
createReleaseCommand
|
|
4
|
+
} from "./chunk-WNKYXS62.js";
|
|
5
|
+
import {
|
|
6
|
+
runPreview
|
|
7
|
+
} from "./chunk-I5CGC253.js";
|
|
8
|
+
import {
|
|
9
|
+
EXIT_CODES,
|
|
10
|
+
readPackageVersion
|
|
11
|
+
} from "./chunk-YZHGXRG6.js";
|
|
12
|
+
|
|
13
|
+
// src/cli.ts
|
|
14
|
+
import { realpathSync } from "fs";
|
|
15
|
+
import { fileURLToPath } from "url";
|
|
16
|
+
import { Command as Command2 } from "commander";
|
|
17
|
+
|
|
18
|
+
// src/preview-command.ts
|
|
19
|
+
import { Command } from "commander";
|
|
20
|
+
function createPreviewCommand() {
|
|
21
|
+
return new Command("preview").description("Post a release preview comment on the current pull request").option("-c, --config <path>", "Path to config file").option("--project-dir <path>", "Project directory", process.cwd()).option("--pr <number>", "PR number (auto-detected from GitHub Actions)").option("--repo <owner/repo>", "Repository (auto-detected from GITHUB_REPOSITORY)").option("-p, --prerelease [identifier]", "Force prerelease preview (auto-detected by default)").option("--stable", "Force stable release preview (graduation from prerelease)", false).option(
|
|
22
|
+
"-d, --dry-run",
|
|
23
|
+
"Print the comment to stdout without posting (GitHub context not available in dry-run mode)",
|
|
24
|
+
false
|
|
25
|
+
).action(async (opts) => {
|
|
26
|
+
try {
|
|
27
|
+
await runPreview({
|
|
28
|
+
config: opts.config,
|
|
29
|
+
projectDir: opts.projectDir,
|
|
30
|
+
pr: opts.pr,
|
|
31
|
+
repo: opts.repo,
|
|
32
|
+
prerelease: opts.prerelease,
|
|
33
|
+
stable: opts.stable,
|
|
34
|
+
dryRun: opts.dryRun
|
|
35
|
+
});
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
38
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/cli.ts
|
|
44
|
+
function createReleaseProgram() {
|
|
45
|
+
return new Command2().name("releasekit-release").description("Unified release pipeline: version, changelog, and publish").version(readPackageVersion(import.meta.url)).addCommand(createReleaseCommand(), { isDefault: true }).addCommand(createPreviewCommand());
|
|
46
|
+
}
|
|
47
|
+
var isMain = (() => {
|
|
48
|
+
try {
|
|
49
|
+
return process.argv[1] ? realpathSync(process.argv[1]) === fileURLToPath(import.meta.url) : false;
|
|
50
|
+
} catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
})();
|
|
54
|
+
if (isMain) {
|
|
55
|
+
createReleaseProgram().parse();
|
|
56
|
+
}
|
|
57
|
+
export {
|
|
58
|
+
createReleaseProgram
|
|
59
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
createReleaseCommand
|
|
4
|
+
} from "./chunk-WNKYXS62.js";
|
|
5
|
+
import {
|
|
6
|
+
EXIT_CODES,
|
|
7
|
+
error,
|
|
8
|
+
info,
|
|
9
|
+
readPackageVersion,
|
|
10
|
+
success
|
|
11
|
+
} from "./chunk-YZHGXRG6.js";
|
|
12
|
+
|
|
13
|
+
// src/dispatcher.ts
|
|
14
|
+
import { realpathSync } from "fs";
|
|
15
|
+
import { fileURLToPath } from "url";
|
|
16
|
+
import { createNotesCommand } from "@releasekit/notes/cli";
|
|
17
|
+
import { createPublishCommand } from "@releasekit/publish/cli";
|
|
18
|
+
import { createVersionCommand } from "@releasekit/version/cli";
|
|
19
|
+
import { Command as Command2 } from "commander";
|
|
20
|
+
|
|
21
|
+
// src/init-command.ts
|
|
22
|
+
import * as fs from "fs";
|
|
23
|
+
import { detectMonorepo } from "@releasekit/notes";
|
|
24
|
+
import { Command } from "commander";
|
|
25
|
+
function createInitCommand() {
|
|
26
|
+
return new Command("init").description("Create a default releasekit.config.json").option("-f, --force", "Overwrite existing config").action((options) => {
|
|
27
|
+
const configPath = "releasekit.config.json";
|
|
28
|
+
if (fs.existsSync(configPath) && !options.force) {
|
|
29
|
+
error(`Config file already exists at ${configPath}. Use --force to overwrite.`);
|
|
30
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
31
|
+
} else {
|
|
32
|
+
let changelogMode;
|
|
33
|
+
try {
|
|
34
|
+
const detected = detectMonorepo(process.cwd());
|
|
35
|
+
changelogMode = detected.isMonorepo ? "packages" : "root";
|
|
36
|
+
info(
|
|
37
|
+
detected.isMonorepo ? "Monorepo detected \u2014 using mode: packages" : "Single-package repo detected \u2014 using mode: root"
|
|
38
|
+
);
|
|
39
|
+
} catch {
|
|
40
|
+
changelogMode = "root";
|
|
41
|
+
info("Could not detect project type \u2014 using mode: root");
|
|
42
|
+
}
|
|
43
|
+
let packageName;
|
|
44
|
+
try {
|
|
45
|
+
const pkg = JSON.parse(fs.readFileSync("package.json", "utf-8"));
|
|
46
|
+
packageName = pkg.name;
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
const isScoped = packageName?.startsWith("@") ?? false;
|
|
50
|
+
const defaultConfig = {
|
|
51
|
+
$schema: "https://goosewobbler.github.io/releasekit/schema.json",
|
|
52
|
+
notes: {
|
|
53
|
+
changelog: {
|
|
54
|
+
mode: changelogMode
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
publish: {
|
|
58
|
+
npm: {
|
|
59
|
+
enabled: true,
|
|
60
|
+
...isScoped ? { access: "public" } : {}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2), "utf-8");
|
|
65
|
+
success(`Created ${configPath}`);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/dispatcher.ts
|
|
71
|
+
function createDispatcherProgram() {
|
|
72
|
+
const program = new Command2().name("releasekit").description("Unified release pipeline: version, changelog, and publish").version(readPackageVersion(import.meta.url));
|
|
73
|
+
program.addCommand(createReleaseCommand(), { isDefault: true });
|
|
74
|
+
program.addCommand(createInitCommand());
|
|
75
|
+
program.addCommand(createVersionCommand());
|
|
76
|
+
program.addCommand(createNotesCommand());
|
|
77
|
+
program.addCommand(createPublishCommand());
|
|
78
|
+
return program;
|
|
79
|
+
}
|
|
80
|
+
var isMain = (() => {
|
|
81
|
+
try {
|
|
82
|
+
return process.argv[1] ? realpathSync(process.argv[1]) === fileURLToPath(import.meta.url) : false;
|
|
83
|
+
} catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
})();
|
|
87
|
+
if (isMain) {
|
|
88
|
+
createDispatcherProgram().parse();
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
createDispatcherProgram
|
|
92
|
+
};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/docs/ci-setup.md
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# CI Setup
|
|
2
|
+
|
|
3
|
+
This guide covers common GitHub Actions patterns for automating releases with `@releasekit/release`.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
All workflows require:
|
|
8
|
+
|
|
9
|
+
- `fetch-depth: 0` on checkout — ReleaseKit reads git history to determine version bumps
|
|
10
|
+
- A `GITHUB_TOKEN` with `contents: write` permission for tagging and GitHub Releases
|
|
11
|
+
- Node.js 20+
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Minimal Setup (push to main)
|
|
16
|
+
|
|
17
|
+
Trigger a release on every push to `main`. If there are no releasable commits, the command exits cleanly with code 0 and does nothing.
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
# .github/workflows/release.yml
|
|
21
|
+
name: Release
|
|
22
|
+
|
|
23
|
+
on:
|
|
24
|
+
push:
|
|
25
|
+
branches: [main]
|
|
26
|
+
|
|
27
|
+
permissions:
|
|
28
|
+
contents: write
|
|
29
|
+
id-token: write # for npm OIDC trusted publishing
|
|
30
|
+
|
|
31
|
+
jobs:
|
|
32
|
+
release:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
with:
|
|
37
|
+
fetch-depth: 0
|
|
38
|
+
|
|
39
|
+
- uses: actions/setup-node@v4
|
|
40
|
+
with:
|
|
41
|
+
node-version: '20'
|
|
42
|
+
registry-url: 'https://registry.npmjs.org'
|
|
43
|
+
|
|
44
|
+
- run: npm ci
|
|
45
|
+
|
|
46
|
+
- run: npx releasekit release
|
|
47
|
+
env:
|
|
48
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
49
|
+
# For OIDC trusted publishing (recommended) — no NPM_TOKEN needed.
|
|
50
|
+
# For token-based publishing: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Label-Based Trigger
|
|
56
|
+
|
|
57
|
+
Only release when a PR is merged with a release label. Conventional commits determine the changelog entries; the label controls whether and at what level to bump.
|
|
58
|
+
|
|
59
|
+
**Required labels** (customisable in config):
|
|
60
|
+
|
|
61
|
+
| Label | Effect |
|
|
62
|
+
|-------|--------|
|
|
63
|
+
| `release:patch` | Bump patch version |
|
|
64
|
+
| `release:minor` | Bump minor version |
|
|
65
|
+
| `release:major` | Bump major version |
|
|
66
|
+
| `release:stable` | Graduate a prerelease to stable |
|
|
67
|
+
| `release:prerelease` | Create a prerelease |
|
|
68
|
+
| `release:skip` | Suppress release on this PR |
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
# .github/workflows/release.yml
|
|
72
|
+
name: Release
|
|
73
|
+
|
|
74
|
+
on:
|
|
75
|
+
push:
|
|
76
|
+
branches: [main]
|
|
77
|
+
|
|
78
|
+
permissions:
|
|
79
|
+
contents: write
|
|
80
|
+
id-token: write
|
|
81
|
+
pull-requests: read
|
|
82
|
+
|
|
83
|
+
jobs:
|
|
84
|
+
release:
|
|
85
|
+
runs-on: ubuntu-latest
|
|
86
|
+
steps:
|
|
87
|
+
- uses: actions/checkout@v4
|
|
88
|
+
with:
|
|
89
|
+
fetch-depth: 0
|
|
90
|
+
|
|
91
|
+
- uses: actions/setup-node@v4
|
|
92
|
+
with:
|
|
93
|
+
node-version: '20'
|
|
94
|
+
registry-url: 'https://registry.npmjs.org'
|
|
95
|
+
|
|
96
|
+
- run: npm ci
|
|
97
|
+
|
|
98
|
+
- run: npx releasekit release
|
|
99
|
+
env:
|
|
100
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Configure the trigger in `releasekit.config.json`:
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"ci": {
|
|
108
|
+
"releaseTrigger": "label",
|
|
109
|
+
"labels": {
|
|
110
|
+
"major": "release:major",
|
|
111
|
+
"minor": "release:minor",
|
|
112
|
+
"patch": "release:patch",
|
|
113
|
+
"skip": "release:skip"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Without a `release:patch/minor/major` label on the merged PR, no release is triggered. The `labels` block shown above reflects the defaults — omit it if your repository already uses those label names.
|
|
120
|
+
|
|
121
|
+
See [@releasekit/release — CI Configuration](../README.md#ci-configuration) for all `ci.*` options.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## PR Preview Comments
|
|
126
|
+
|
|
127
|
+
Post a comment on every PR showing what would be released if merged. Requires `pull-requests: write`.
|
|
128
|
+
|
|
129
|
+
```yaml
|
|
130
|
+
# .github/workflows/release-preview.yml
|
|
131
|
+
name: Release Preview
|
|
132
|
+
|
|
133
|
+
on:
|
|
134
|
+
pull_request:
|
|
135
|
+
branches: [main]
|
|
136
|
+
types: [opened, synchronize, labeled, unlabeled]
|
|
137
|
+
|
|
138
|
+
concurrency:
|
|
139
|
+
group: release-preview-${{ github.event.pull_request.number }}
|
|
140
|
+
cancel-in-progress: true
|
|
141
|
+
|
|
142
|
+
permissions:
|
|
143
|
+
pull-requests: write
|
|
144
|
+
contents: read
|
|
145
|
+
|
|
146
|
+
jobs:
|
|
147
|
+
preview:
|
|
148
|
+
runs-on: ubuntu-latest
|
|
149
|
+
steps:
|
|
150
|
+
- uses: actions/checkout@v4
|
|
151
|
+
with:
|
|
152
|
+
fetch-depth: 0
|
|
153
|
+
|
|
154
|
+
- uses: actions/setup-node@v4
|
|
155
|
+
with:
|
|
156
|
+
node-version: '20'
|
|
157
|
+
|
|
158
|
+
- run: npm ci
|
|
159
|
+
|
|
160
|
+
- run: npx releasekit preview
|
|
161
|
+
env:
|
|
162
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
A ready-to-use template is available at [`templates/workflows/release-preview.yml`](../../../templates/workflows/release-preview.yml).
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## npm OIDC Trusted Publishing (Recommended)
|
|
170
|
+
|
|
171
|
+
With OIDC, no `NPM_TOKEN` secret is required. The workflow exchanges a GitHub-issued OIDC token for a short-lived npm token at publish time.
|
|
172
|
+
|
|
173
|
+
**Requirements:**
|
|
174
|
+
- npm `>=9.5.0`
|
|
175
|
+
- Each package must have an **Automation policy** configured at npmjs.com (Settings → Automation policies → add a GitHub Actions OIDC publisher for your repo and workflow)
|
|
176
|
+
|
|
177
|
+
**Important:** `actions/setup-node` with `registry-url` writes a project `.npmrc` that injects `_authToken=${NODE_AUTH_TOKEN}`. When `NODE_AUTH_TOKEN` is unset, npm resolves this to an empty token and fails with `ENEEDAUTH` instead of falling through to the OIDC exchange. Delete the file before publishing:
|
|
178
|
+
|
|
179
|
+
```yaml
|
|
180
|
+
permissions:
|
|
181
|
+
contents: write
|
|
182
|
+
id-token: write # grants the OIDC token
|
|
183
|
+
|
|
184
|
+
steps:
|
|
185
|
+
- uses: actions/setup-node@v4
|
|
186
|
+
with:
|
|
187
|
+
node-version: '20'
|
|
188
|
+
registry-url: 'https://registry.npmjs.org'
|
|
189
|
+
|
|
190
|
+
- run: npx releasekit release
|
|
191
|
+
env:
|
|
192
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
193
|
+
# No NPM_TOKEN needed with OIDC
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
ReleaseKit detects OIDC availability automatically (`npm-auth: auto`). To force it:
|
|
197
|
+
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"publish": {
|
|
201
|
+
"npm": { "auth": "oidc" }
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Prerelease Workflow
|
|
209
|
+
|
|
210
|
+
```yaml
|
|
211
|
+
# Manual dispatch for prereleases
|
|
212
|
+
on:
|
|
213
|
+
workflow_dispatch:
|
|
214
|
+
inputs:
|
|
215
|
+
prerelease:
|
|
216
|
+
description: 'Prerelease identifier (e.g. beta, rc)'
|
|
217
|
+
required: true
|
|
218
|
+
default: 'beta'
|
|
219
|
+
|
|
220
|
+
jobs:
|
|
221
|
+
prerelease:
|
|
222
|
+
runs-on: ubuntu-latest
|
|
223
|
+
steps:
|
|
224
|
+
- uses: actions/checkout@v4
|
|
225
|
+
with:
|
|
226
|
+
fetch-depth: 0
|
|
227
|
+
|
|
228
|
+
- uses: actions/setup-node@v4
|
|
229
|
+
with:
|
|
230
|
+
node-version: '20'
|
|
231
|
+
registry-url: 'https://registry.npmjs.org'
|
|
232
|
+
|
|
233
|
+
- run: npm ci
|
|
234
|
+
|
|
235
|
+
- run: npx releasekit release --prerelease ${{ inputs.prerelease }}
|
|
236
|
+
env:
|
|
237
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Monorepo Targeted Release
|
|
243
|
+
|
|
244
|
+
Release only specific packages:
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
npx releasekit release --target @myorg/core,@myorg/cli
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Or version all packages together:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
npx releasekit release --sync
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Dry Run in CI
|
|
259
|
+
|
|
260
|
+
Useful for verifying pipeline setup before enabling real releases:
|
|
261
|
+
|
|
262
|
+
```yaml
|
|
263
|
+
- run: npx releasekit release --dry-run --json
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
`--dry-run` prints what would happen without modifying any files, creating tags, or publishing packages. `--json` emits structured output for inspection.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@releasekit/release",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Unified release pipeline: version, changelog, and publish in a single command",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"license": "MIT",
|
|
38
38
|
"files": [
|
|
39
39
|
"dist",
|
|
40
|
+
"docs",
|
|
40
41
|
"README.md",
|
|
41
42
|
"LICENSE"
|
|
42
43
|
],
|
|
@@ -49,9 +50,9 @@
|
|
|
49
50
|
"commander": "^14.0.3",
|
|
50
51
|
"smol-toml": "^1.6.1",
|
|
51
52
|
"zod": "^4.3.6",
|
|
52
|
-
"@releasekit/notes": "0.
|
|
53
|
-
"@releasekit/
|
|
54
|
-
"@releasekit/
|
|
53
|
+
"@releasekit/notes": "0.4.0",
|
|
54
|
+
"@releasekit/publish": "0.4.0",
|
|
55
|
+
"@releasekit/version": "0.4.0"
|
|
55
56
|
},
|
|
56
57
|
"devDependencies": {
|
|
57
58
|
"@biomejs/biome": "^2.4.6",
|
|
@@ -61,8 +62,8 @@
|
|
|
61
62
|
"tsup": "^8.5.1",
|
|
62
63
|
"typescript": "^5.9.3",
|
|
63
64
|
"vitest": "^4.1.0",
|
|
64
|
-
"@releasekit/
|
|
65
|
-
"@releasekit/
|
|
65
|
+
"@releasekit/config": "0.0.0",
|
|
66
|
+
"@releasekit/core": "0.0.0"
|
|
66
67
|
},
|
|
67
68
|
"engines": {
|
|
68
69
|
"node": ">=20"
|