@varlock/bumpy 1.13.1 → 1.14.0-rc.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 +23 -140
- package/config-schema.json +43 -0
- package/dist/{add-5how2kia.mjs → add-C9rU_89s.mjs} +4 -4
- package/dist/{apply-release-plan-DD2R7SL2.mjs → apply-release-plan-DxTsUSqa.mjs} +11 -2
- package/dist/{bump-file-B7hmXZlB.mjs → bump-file-mRJeReRJ.mjs} +43 -8
- package/dist/{changelog-CbaET5V6.mjs → changelog-DuFhnJRO.mjs} +3 -3
- package/dist/{changelog-github-DXDnWkrB.mjs → changelog-github-jLOtwuWj.mjs} +2 -2
- package/dist/channels-CFXZkyGd.mjs +75 -0
- package/dist/{check-CsF0zh8r.mjs → check-DIl9Dz68.mjs} +18 -6
- package/dist/{ci-CIamssoq.mjs → ci-hO7tAbCN.mjs} +391 -23
- package/dist/cli.mjs +32 -17
- package/dist/{config-D_4GYDJi.mjs → config-0we4ISZX.mjs} +5 -1
- package/dist/{generate-CvCvUaRV.mjs → generate-B2OMt_64.mjs} +3 -3
- package/dist/{git-DJJ64SW9.mjs → git-DAWj8LyV.mjs} +25 -4
- package/dist/index.d.mts +46 -4
- package/dist/index.mjs +7 -7
- package/dist/prerelease-Blnk8FE1.mjs +186 -0
- package/dist/{publish-h6rM58Cq.mjs → publish-Cz0e4KYT.mjs} +164 -19
- package/dist/{publish-pipeline-DSj14dW6.mjs → publish-pipeline-BD8mLbL9.mjs} +18 -3
- package/dist/{release-plan-mK7iGeGq.mjs → release-plan-C84pcBi-.mjs} +12 -17
- package/dist/status-CrMvvvNy.mjs +232 -0
- package/dist/{types-Bkh-igOJ.mjs → types-lpiG-Zxh.mjs} +1 -0
- package/dist/version-BUUf8vKC.mjs +192 -0
- package/package.json +1 -1
- package/dist/status-BbsDr6t7.mjs +0 -129
- package/dist/version-Cm0nRAFF.mjs +0 -123
- /package/dist/{commit-message-CSWVKPJ-.mjs → commit-message-BwsowSds.mjs} +0 -0
- /package/dist/{init-BCkm6Nfa.mjs → init-DkAY5hjc.mjs} +0 -0
package/README.md
CHANGED
|
@@ -15,22 +15,21 @@
|
|
|
15
15
|
|
|
16
16
|
# @varlock/bumpy 🐸
|
|
17
17
|
|
|
18
|
-
A modern package versioning, release, and changelog generation tool. Built for monorepos, but works great in
|
|
18
|
+
A modern package versioning, release, and changelog generation tool. Built for monorepos, but works great in simple projects too.
|
|
19
19
|
|
|
20
20
|
## How It Works
|
|
21
21
|
|
|
22
|
-
Bumpy uses **bump files** (you may know them as "changesets" if coming from [that tool 🦋](https://github.com/changesets/changesets)) - small markdown files that declare an
|
|
22
|
+
Bumpy uses **bump files** (you may know them as "changesets" if coming from [that tool 🦋](https://github.com/changesets/changesets)) - small markdown files that declare an _intent to release packages_ with a bump level (patch/minor/major), and a description that ends up in changelogs. Developers create these files as part of their PRs, and these files are then used to consolidate changes, generate changelogs, and trigger publishing.
|
|
23
23
|
|
|
24
24
|
- Devs/agents create bump files as part of their PRs (using `bumpy add` or manually)
|
|
25
25
|
- A git hook (pre-commit or pre-push) can enforce bump files exist for changed packages
|
|
26
26
|
- In CI, a workflow checks PRs for bump files, leaves a comment on the PR detailing changed packages
|
|
27
27
|
- As PRs merge to the base branch, a "release PR" is kept up to date
|
|
28
|
-
- Shows what packages will be released and their changelogs
|
|
29
|
-
- Including packages bumped automatically due to dependency relationships
|
|
28
|
+
- Shows what packages will be released and their changelogs (incl. those bumped via dep relationships)
|
|
30
29
|
- When release PR is merged, publishing is triggered
|
|
31
|
-
- Pending bump files are deleted and packages are published with updated versions and changelogs
|
|
30
|
+
- Pending bump files are deleted and packages are published with updated versions and changelogs, github tags+releases created
|
|
32
31
|
|
|
33
|
-
All of this is automated via two simple GitHub Actions workflows (see [
|
|
32
|
+
All of this is automated via two simple GitHub Actions workflows (see [actions guide](https://github.com/dmno-dev/bumpy/blob/main/docs/github-actions.md)). Or can be triggered locally.
|
|
34
33
|
|
|
35
34
|
### Example bump file
|
|
36
35
|
|
|
@@ -42,21 +41,24 @@ All of this is automated via two simple GitHub Actions workflows (see [CI setup]
|
|
|
42
41
|
'@myorg/utils': patch
|
|
43
42
|
---
|
|
44
43
|
|
|
45
|
-
Added user
|
|
44
|
+
Added user lang prefs to core config.
|
|
46
45
|
Fixed locale fallback logic in utils.
|
|
47
46
|
```
|
|
48
47
|
|
|
49
48
|
## Features
|
|
50
49
|
|
|
51
|
-
- **All package managers** - npm, pnpm, yarn, and bun workspaces
|
|
50
|
+
- **All package managers** - npm, pnpm, yarn, and bun workspaces. With full `workspace:` and `catalog:` support
|
|
52
51
|
- **Smart dependency propagation** - configurable rules for how version bumps cascade through your dependency graph (see [version propagation docs](https://github.com/dmno-dev/bumpy/blob/main/docs/version-propagation.md))
|
|
53
|
-
- **
|
|
52
|
+
- **OIDC + staged publishing** - supports OIDC, provenance, [npm staged publishing](https://docs.npmjs.com/staged-publishing)
|
|
53
|
+
- **Custom release targets** - Per-package custom publish commands let you target anything - VSCode extensions, Docker images, JSR, private registries, etc.
|
|
54
54
|
- **Flexible package management** - include/exclude any package individually via per-package config, glob patterns, or `privatePackages` setting
|
|
55
55
|
- **Non-interactive CLI** - `bumpy add` works fully non-interactively for CI/CD and AI-assisted development
|
|
56
56
|
- **Aggregated GitHub releases** - optionally create a single consolidated release instead of one per package
|
|
57
|
+
- **Prerelease channels** - branch-based `@next` / `@beta` release lines where prerelease versions are derived at publish time, never committed to git (see [prerelease channels docs](https://github.com/dmno-dev/bumpy/blob/main/docs/prereleases.md))
|
|
57
58
|
- **Auto-generate from commits** - `bumpy generate` creates bump files from branch commits - works with any commit style, with enhanced detection for conventional commits
|
|
58
59
|
- **Pluggable changelog formatters** - built-in `"default"` and `"github"` formatters, or write your own
|
|
59
60
|
- **Zero runtime dependencies** - dependencies are minimal and bundled at release time
|
|
61
|
+
- **No additional action/app needed** - no external github action or app to audit and trust
|
|
60
62
|
|
|
61
63
|
## Getting Started
|
|
62
64
|
|
|
@@ -67,6 +69,9 @@ bun add -d @varlock/bumpy # or npm/pnpm/yarn
|
|
|
67
69
|
# Initialize (creates .bumpy/ directory and config, migrates from changesets if applicable)
|
|
68
70
|
bunx bumpy init
|
|
69
71
|
|
|
72
|
+
# Interactive guidance setting up CI
|
|
73
|
+
bunx bumpy ci setup
|
|
74
|
+
|
|
70
75
|
# Create a bump file
|
|
71
76
|
bunx bumpy add
|
|
72
77
|
|
|
@@ -78,138 +83,15 @@ Then set up CI to automate versioning and publishing (see below).
|
|
|
78
83
|
|
|
79
84
|
## CI / GitHub Actions
|
|
80
85
|
|
|
81
|
-
No GitHub App to install, no separate action to rely on
|
|
82
|
-
|
|
83
|
-
- **`bumpy ci check`** - runs on every PR. Computes the release plan from pending bump files and posts/updates a comment on the PR showing what versions would be released. Warns if any changed packages are missing bump files.
|
|
84
|
-
- **`bumpy ci release`** - runs on push to main. If pending bump files exist, it opens (or updates) a "Version Packages" PR that applies all version bumps and changelog updates. If the current push _is_ the Version Packages PR being merged, it publishes the new versions, creates git tags, and creates GitHub releases.
|
|
85
|
-
|
|
86
|
-
_examples use bun, but works with Node.js_
|
|
87
|
-
|
|
88
|
-
### PR check workflow
|
|
89
|
-
|
|
90
|
-
```yaml
|
|
91
|
-
# .github/workflows/bumpy-check.yaml
|
|
92
|
-
#
|
|
93
|
-
# ⚠️ Uses `pull_request_target` so fork PR comments work — runs with write
|
|
94
|
-
# perms and secrets, so it MUST NOT execute PR code (no `bun install`, no
|
|
95
|
-
# PR-defined scripts). Bumpy only reads files; its version is resolved from
|
|
96
|
-
# the base branch's package.json. See docs/github-actions.md for details.
|
|
97
|
-
name: Bumpy Check
|
|
98
|
-
on: pull_request_target
|
|
99
|
-
|
|
100
|
-
permissions:
|
|
101
|
-
pull-requests: write
|
|
102
|
-
contents: read
|
|
103
|
-
|
|
104
|
-
jobs:
|
|
105
|
-
check:
|
|
106
|
-
runs-on: ubuntu-latest
|
|
107
|
-
steps:
|
|
108
|
-
- uses: actions/checkout@v6
|
|
109
|
-
with:
|
|
110
|
-
ref: ${{ github.event.pull_request.head.sha }}
|
|
111
|
-
- uses: oven-sh/setup-bun@v2
|
|
112
|
-
|
|
113
|
-
# Resolve bumpy's version from the base branch (trusted) — not the PR's
|
|
114
|
-
# package.json (which a fork PR could swap to a malicious version).
|
|
115
|
-
# Change "main" to your base branch if different.
|
|
116
|
-
- name: Resolve bumpy version from base
|
|
117
|
-
run: |
|
|
118
|
-
git fetch origin main --depth=1
|
|
119
|
-
VERSION=$(git show "origin/main:package.json" \
|
|
120
|
-
| jq -r '.devDependencies["@varlock/bumpy"] // .dependencies["@varlock/bumpy"]' \
|
|
121
|
-
| sed 's/[\^~]//')
|
|
122
|
-
echo "BUMPY_VERSION=$VERSION" >> "$GITHUB_ENV"
|
|
123
|
-
|
|
124
|
-
- run: bunx "@varlock/bumpy@$BUMPY_VERSION" ci check
|
|
125
|
-
env:
|
|
126
|
-
GH_TOKEN: ${{ github.token }}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### Release workflow
|
|
130
|
-
|
|
131
|
-
```yaml
|
|
132
|
-
# .github/workflows/bumpy-release.yml - trusted publishing (OIDC, no secret needed)
|
|
133
|
-
name: Bumpy Release
|
|
134
|
-
on:
|
|
135
|
-
push:
|
|
136
|
-
branches: [main]
|
|
137
|
-
|
|
138
|
-
jobs:
|
|
139
|
-
release:
|
|
140
|
-
runs-on: ubuntu-latest
|
|
141
|
-
permissions:
|
|
142
|
-
contents: write
|
|
143
|
-
pull-requests: write
|
|
144
|
-
id-token: write # required for npm trusted publishing (OIDC) and provenance
|
|
145
|
-
steps:
|
|
146
|
-
- uses: actions/checkout@v6
|
|
147
|
-
with:
|
|
148
|
-
fetch-depth: 0
|
|
149
|
-
- uses: oven-sh/setup-bun@v2
|
|
150
|
-
- uses: actions/setup-node@v6
|
|
151
|
-
with:
|
|
152
|
-
node-version: latest
|
|
153
|
-
- run: npm install -g npm@latest # ensure npm >= 11.15.0 for OIDC/staged publishing
|
|
154
|
-
- run: bun install
|
|
155
|
-
- run: bunx @varlock/bumpy ci release
|
|
156
|
-
env:
|
|
157
|
-
GH_TOKEN: ${{ github.token }}
|
|
158
|
-
BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }} # PAT so that version PR triggers CI
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
> **Trusted publishing setup:** Configure each package on [npmjs.com](https://docs.npmjs.com/trusted-publishers/) → Package Settings → Trusted Publishers → GitHub Actions. Specify your org/user, repo, and the workflow filename (`bumpy-release.yml`). No `NPM_TOKEN` secret needed. Enable `provenance` and `npmStaged` in your [publish config](https://github.com/dmno-dev/bumpy/blob/main/docs/configuration.md#staged-publishing) for maximum security.
|
|
162
|
-
|
|
163
|
-
<details>
|
|
164
|
-
<summary>Alternative: token-based auth (NPM_TOKEN secret)</summary>
|
|
165
|
-
|
|
166
|
-
```yaml
|
|
167
|
-
# .github/workflows/bumpy-release.yml - token-based auth
|
|
168
|
-
name: Bumpy Release
|
|
169
|
-
on:
|
|
170
|
-
push:
|
|
171
|
-
branches: [main]
|
|
172
|
-
|
|
173
|
-
jobs:
|
|
174
|
-
release:
|
|
175
|
-
runs-on: ubuntu-latest
|
|
176
|
-
permissions:
|
|
177
|
-
contents: write
|
|
178
|
-
pull-requests: write
|
|
179
|
-
steps:
|
|
180
|
-
- uses: actions/checkout@v6
|
|
181
|
-
with:
|
|
182
|
-
fetch-depth: 0
|
|
183
|
-
- uses: oven-sh/setup-bun@v2
|
|
184
|
-
- run: bun install
|
|
185
|
-
- run: bunx @varlock/bumpy ci release
|
|
186
|
-
env:
|
|
187
|
-
GH_TOKEN: ${{ github.token }}
|
|
188
|
-
BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }}
|
|
189
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
</details>
|
|
193
|
-
|
|
194
|
-
### Token setup
|
|
195
|
-
|
|
196
|
-
The default `github.token` works for basic functionality, but GitHub's anti-recursion guard means PRs created by the default token won't trigger other workflows - so your regular CI (tests, linting, etc.) won't run automatically on the Version Packages PR. To fix this, provide a `BUMPY_GH_TOKEN` secret using either a **fine-grained PAT** or a **GitHub App token**. See the [full token setup guide](https://github.com/dmno-dev/bumpy/blob/main/docs/github-actions.md#token-setup) for details.
|
|
86
|
+
No GitHub App to install, no separate action to rely on — just call `bumpy ci` directly in your workflows. Three commands across two workflows handle the entire release lifecycle:
|
|
197
87
|
|
|
198
|
-
|
|
88
|
+
- **`bumpy ci check`** — on every PR, posts/updates a comment showing the release plan and warns if changed packages are missing bump files.
|
|
89
|
+
- **`bumpy ci plan`** — on push to main, detects what should happen next (`version-pr`, `publish`, or nothing) without needing write permissions or publish credentials. Used to gate downstream jobs in split-job workflows.
|
|
90
|
+
- **`bumpy ci release`** — opens/updates the "Version Packages" PR, or publishes new versions and creates git tags + GitHub releases when that PR is merged.
|
|
199
91
|
|
|
200
|
-
|
|
201
|
-
- **Repository access:** your repo only
|
|
202
|
-
- **Permissions:** Contents (read & write), Pull requests (read & write)
|
|
203
|
-
2. Add it as a repository secret named `BUMPY_GH_TOKEN`
|
|
204
|
-
3. Add it to your release workflow:
|
|
205
|
-
```yaml
|
|
206
|
-
- run: bunx @varlock/bumpy ci release
|
|
207
|
-
env:
|
|
208
|
-
GH_TOKEN: ${{ github.token }}
|
|
209
|
-
BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }}
|
|
210
|
-
```
|
|
92
|
+
Run `bumpy ci setup` for interactive guidance, and see the [GitHub Actions setup guide](https://github.com/dmno-dev/bumpy/blob/main/docs/github-actions.md) for ready-to-copy workflows, token setup, and trusted publishing.
|
|
211
93
|
|
|
212
|
-
|
|
94
|
+
## Local versioning and publishing
|
|
213
95
|
|
|
214
96
|
If you prefer to version and publish locally instead of via CI:
|
|
215
97
|
|
|
@@ -238,6 +120,7 @@ The skill teaches the AI to examine git changes, identify affected packages, cho
|
|
|
238
120
|
- [CLI reference](https://github.com/dmno-dev/bumpy/blob/main/docs/cli.md) - every command with flags and examples
|
|
239
121
|
- [GitHub Actions setup](https://github.com/dmno-dev/bumpy/blob/main/docs/github-actions.md) - CI workflows, token setup, trusted publishing
|
|
240
122
|
- [Version propagation](https://github.com/dmno-dev/bumpy/blob/main/docs/version-propagation.md) - how dependency bumps cascade through your graph
|
|
123
|
+
- [Prerelease channels](https://github.com/dmno-dev/bumpy/blob/main/docs/prereleases.md) - branch-based `@next` / `@beta` release lines
|
|
241
124
|
|
|
242
125
|
## Why files instead of conventional commits?
|
|
243
126
|
|
|
@@ -252,6 +135,7 @@ Bumpy is built as a successor to [🦋changesets](https://github.com/changesets/
|
|
|
252
135
|
- **Custom publish commands** - changesets is hardcoded to `npm publish`. Bumpy supports per-package custom publish for VSCode extensions, Docker images, JSR, etc.
|
|
253
136
|
- **Flexible package management** - changesets treats all private packages the same. Bumpy lets you include/exclude any package individually.
|
|
254
137
|
- **CI without a separate action or bot** - changesets requires installing a [GitHub App](https://github.com/apps/changeset-bot) _and_ using a [separate GitHub Action](https://github.com/changesets/action). Bumpy replaces both with two CLI commands (`bumpy ci check` + `bumpy ci release`) that run directly in your workflows - no extra repos to trust, no app installation requiring org admin approval.
|
|
138
|
+
- **Prerelease channels that don't corrupt state** - changesets' prerelease mode is described in [their own docs](https://github.com/changesets/changesets/blob/main/docs/prereleases.md) as "very complicated" with states "very hard to fix." Bumpy uses [branch-based channels](https://github.com/dmno-dev/bumpy/blob/main/docs/prereleases.md) where prerelease versions are never committed - no global mode file to poison unrelated releases.
|
|
255
139
|
- **Automatic migration** - `bumpy init` detects `.changeset/`, renames it to `.bumpy/`, migrates config, keeps pending files, and offers to uninstall `@changesets/cli`.
|
|
256
140
|
|
|
257
141
|
## Development
|
|
@@ -265,12 +149,11 @@ bunx bumpy --help # invoke built cli
|
|
|
265
149
|
|
|
266
150
|
## Roadmap
|
|
267
151
|
|
|
268
|
-
- Prerelease mode (for now, use [pkg.pr.new](https://github.com/stackblitz-labs/pkg.pr.new) for branch preview packages)
|
|
269
152
|
- Standalone binary for use outside of JS projects
|
|
270
153
|
- Better support for versioning non-JS packages and usage without package.json files
|
|
271
154
|
- Plugin system for different publish targets, and support multiple targets per package
|
|
272
155
|
- Tracking workspace-level / non-publishable changes
|
|
273
|
-
- More frogs
|
|
156
|
+
- More frogs 🐸🐸🐸
|
|
274
157
|
|
|
275
158
|
---
|
|
276
159
|
|
package/config-schema.json
CHANGED
|
@@ -202,6 +202,49 @@
|
|
|
202
202
|
}
|
|
203
203
|
},
|
|
204
204
|
"additionalProperties": false
|
|
205
|
+
},
|
|
206
|
+
"channels": {
|
|
207
|
+
"type": "object",
|
|
208
|
+
"description": "Prerelease channels, keyed by channel name. Each maps a long-lived branch to a prerelease line (version suffix + npm dist-tag). Prerelease versions are derived at publish time and never committed.",
|
|
209
|
+
"additionalProperties": {
|
|
210
|
+
"type": "object",
|
|
211
|
+
"properties": {
|
|
212
|
+
"branch": {
|
|
213
|
+
"type": "string",
|
|
214
|
+
"description": "Branch that triggers this channel (required)"
|
|
215
|
+
},
|
|
216
|
+
"preid": {
|
|
217
|
+
"type": "string",
|
|
218
|
+
"description": "Version suffix (preid), e.g. \"rc\" produces 1.2.0-rc.0. Defaults to the channel name."
|
|
219
|
+
},
|
|
220
|
+
"tag": {
|
|
221
|
+
"type": "string",
|
|
222
|
+
"description": "npm dist-tag for publishes. Defaults to the channel name."
|
|
223
|
+
},
|
|
224
|
+
"versionPr": {
|
|
225
|
+
"type": "object",
|
|
226
|
+
"description": "Release PR overrides for this channel",
|
|
227
|
+
"properties": {
|
|
228
|
+
"title": {
|
|
229
|
+
"type": "string",
|
|
230
|
+
"description": "Release PR title. Defaults to \"<base title> (<channel name>)\"."
|
|
231
|
+
},
|
|
232
|
+
"branch": {
|
|
233
|
+
"type": "string",
|
|
234
|
+
"description": "Release PR branch. Defaults to \"<base branch>-<channel name>\"."
|
|
235
|
+
},
|
|
236
|
+
"automerge": {
|
|
237
|
+
"type": "boolean",
|
|
238
|
+
"description": "Enable auto-merge on the release PR",
|
|
239
|
+
"default": false
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
"additionalProperties": false
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
"required": ["branch"],
|
|
246
|
+
"additionalProperties": false
|
|
247
|
+
}
|
|
205
248
|
}
|
|
206
249
|
},
|
|
207
250
|
"additionalProperties": false,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { n as log, r as require_picocolors, s as __toESM } from "./logger-BgksGFuf.mjs";
|
|
2
2
|
import { n as exists, t as ensureDir } from "./fs-CBXKZhoU.mjs";
|
|
3
|
-
import { a as loadConfig, r as getBumpyDir } from "./config-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { a as loadConfig, r as getBumpyDir } from "./config-0we4ISZX.mjs";
|
|
4
|
+
import { c as discoverWorkspace, i as readBumpFiles, o as writeBumpFile, t as filterBranchBumpFiles } from "./bump-file-mRJeReRJ.mjs";
|
|
5
|
+
import { a as getChangedFiles } from "./git-DAWj8LyV.mjs";
|
|
6
6
|
import { l as pt, o as gt, r as Ot, s as mt, t as unwrap, u as wt } from "./clack-W95rXis0.mjs";
|
|
7
7
|
import { n as slugify, t as randomName } from "./names-COooXAFg.mjs";
|
|
8
|
-
import { n as findChangedPackages } from "./check-
|
|
8
|
+
import { n as findChangedPackages } from "./check-DIl9Dz68.mjs";
|
|
9
9
|
import { resolve } from "node:path";
|
|
10
10
|
import * as readline from "node:readline";
|
|
11
11
|
//#region src/prompts/bump-select.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as readJson, c as removeFile, f as writeText, i as listFiles, l as updateJsonFields, n as exists, s as readText, u as updateJsonNestedField } from "./fs-CBXKZhoU.mjs";
|
|
2
|
-
import { r as getBumpyDir } from "./config-
|
|
3
|
-
import { a as prependToChangelog, i as loadFormatter, n as generateChangelogEntry } from "./changelog-
|
|
2
|
+
import { r as getBumpyDir } from "./config-0we4ISZX.mjs";
|
|
3
|
+
import { a as prependToChangelog, i as loadFormatter, n as generateChangelogEntry } from "./changelog-DuFhnJRO.mjs";
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
5
|
//#region src/core/apply-release-plan.ts
|
|
6
6
|
/** Apply the release plan: bump versions, update changelogs, delete bump files */
|
|
@@ -39,6 +39,15 @@ async function applyReleasePlan(releasePlan, packages, rootDir, config) {
|
|
|
39
39
|
if (file === "README.md") continue;
|
|
40
40
|
await removeFile(resolve(bumpyDir, file));
|
|
41
41
|
}
|
|
42
|
+
const { rmdir } = await import("node:fs/promises");
|
|
43
|
+
for (const channel of Object.keys(config.channels || {})) {
|
|
44
|
+
const channelDir = resolve(bumpyDir, channel);
|
|
45
|
+
const channelFiles = await listFiles(channelDir, ".md");
|
|
46
|
+
for (const file of channelFiles) await removeFile(resolve(channelDir, file));
|
|
47
|
+
try {
|
|
48
|
+
await rmdir(channelDir);
|
|
49
|
+
} catch {}
|
|
50
|
+
}
|
|
42
51
|
}
|
|
43
52
|
/** Update a version range to include a new version, preserving the range prefix */
|
|
44
53
|
function updateRange(range, newVersion) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as readJson, f as writeText, i as listFiles, n as exists, s as readText } from "./fs-CBXKZhoU.mjs";
|
|
2
|
-
import { i as isPackageManaged, o as loadPackageConfig, r as getBumpyDir } from "./config-
|
|
2
|
+
import { i as isPackageManaged, o as loadPackageConfig, r as getBumpyDir } from "./config-0we4ISZX.mjs";
|
|
3
3
|
import { c as jsYaml, r as detectWorkspaces } from "./package-manager-Db_vTztt.mjs";
|
|
4
4
|
import { s as tryRunArgs } from "./shell-C8KgKnMQ.mjs";
|
|
5
5
|
import { relative, resolve } from "node:path";
|
|
@@ -128,18 +128,38 @@ function validatePackageName(name) {
|
|
|
128
128
|
if (name.startsWith("-")) return false;
|
|
129
129
|
return true;
|
|
130
130
|
}
|
|
131
|
-
/** Read all bump files from .bumpy/
|
|
132
|
-
async function readBumpFiles(rootDir) {
|
|
131
|
+
/** Read all bump files from .bumpy/ (and optionally channel subdirs), sorted by git creation order */
|
|
132
|
+
async function readBumpFiles(rootDir, opts = {}) {
|
|
133
133
|
const dir = getBumpyDir(rootDir);
|
|
134
|
-
const files = await listFiles(dir, ".md");
|
|
135
134
|
const bumpFiles = [];
|
|
136
135
|
const errors = [];
|
|
136
|
+
const files = await listFiles(dir, ".md");
|
|
137
137
|
for (const file of files) {
|
|
138
138
|
if (file === "README.md") continue;
|
|
139
139
|
const result = await parseBumpFileFromPath(resolve(dir, file));
|
|
140
140
|
if (result.bumpFile) bumpFiles.push(result.bumpFile);
|
|
141
141
|
errors.push(...result.errors);
|
|
142
142
|
}
|
|
143
|
+
for (const channel of opts.channels ?? []) {
|
|
144
|
+
const channelDir = resolve(dir, channel);
|
|
145
|
+
const channelFiles = await listFiles(channelDir, ".md");
|
|
146
|
+
for (const file of channelFiles) {
|
|
147
|
+
if (file === "README.md") continue;
|
|
148
|
+
const result = await parseBumpFileFromPath(resolve(channelDir, file));
|
|
149
|
+
if (result.bumpFile) {
|
|
150
|
+
const duplicate = bumpFiles.find((bf) => bf.id === result.bumpFile.id);
|
|
151
|
+
if (duplicate) {
|
|
152
|
+
errors.push(`Bump file "${result.bumpFile.id}" exists both ${duplicate.channel ? `in .bumpy/${duplicate.channel}/` : "at .bumpy/ root"} and in .bumpy/${channel}/ — remove one copy (the change likely already shipped on one of them).`);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
bumpFiles.push({
|
|
156
|
+
...result.bumpFile,
|
|
157
|
+
channel
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
errors.push(...result.errors);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
143
163
|
const creationOrder = getBumpFileCreationOrder(rootDir);
|
|
144
164
|
if (creationOrder.size > 0) bumpFiles.sort((a, b) => {
|
|
145
165
|
return (creationOrder.get(a.id) ?? Infinity) - (creationOrder.get(b.id) ?? Infinity) || a.id.localeCompare(b.id);
|
|
@@ -171,7 +191,7 @@ function getBumpFileCreationOrder(rootDir) {
|
|
|
171
191
|
if (!trimmed) continue;
|
|
172
192
|
if (/^\d+$/.test(trimmed)) currentTimestamp = parseInt(trimmed, 10);
|
|
173
193
|
else if (trimmed.startsWith(".bumpy/") && trimmed.endsWith(".md")) {
|
|
174
|
-
const id = trimmed
|
|
194
|
+
const id = fileToId(trimmed);
|
|
175
195
|
order.set(id, currentTimestamp);
|
|
176
196
|
}
|
|
177
197
|
}
|
|
@@ -298,11 +318,26 @@ function recoverDeletedBumpFiles(rootDir) {
|
|
|
298
318
|
`HEAD~1:${filePath}`
|
|
299
319
|
], { cwd: rootDir });
|
|
300
320
|
if (!content) continue;
|
|
301
|
-
const { bumpFile } = parseBumpFile(content, filePath
|
|
321
|
+
const { bumpFile } = parseBumpFile(content, fileToId(filePath));
|
|
302
322
|
if (bumpFile) bumpFiles.push(bumpFile);
|
|
303
323
|
}
|
|
304
324
|
return bumpFiles;
|
|
305
325
|
}
|
|
326
|
+
/**
|
|
327
|
+
* Move bump files into a channel's shipped directory (`.bumpy/<channel>/`).
|
|
328
|
+
* This is the only thing a channel "version" does — prerelease versions are
|
|
329
|
+
* never written to git. Files already in the target channel dir are left alone.
|
|
330
|
+
*/
|
|
331
|
+
async function moveBumpFilesToChannel(rootDir, bumpFiles, channel) {
|
|
332
|
+
const { rename, mkdir } = await import("node:fs/promises");
|
|
333
|
+
const dir = getBumpyDir(rootDir);
|
|
334
|
+
const channelDir = resolve(dir, channel);
|
|
335
|
+
await mkdir(channelDir, { recursive: true });
|
|
336
|
+
for (const bf of bumpFiles) {
|
|
337
|
+
if (bf.channel === channel) continue;
|
|
338
|
+
await rename(bf.channel ? resolve(dir, bf.channel, `${bf.id}.md`) : resolve(dir, `${bf.id}.md`), resolve(channelDir, `${bf.id}.md`));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
306
341
|
function fileToId(filePath) {
|
|
307
342
|
return filePath.split("/").pop().replace(/\.md$/, "");
|
|
308
343
|
}
|
|
@@ -311,7 +346,7 @@ function fileToId(filePath) {
|
|
|
311
346
|
* of bump files that were added/modified. Shared by `check` and `ci check`.
|
|
312
347
|
*/
|
|
313
348
|
function extractBumpFileIdsFromChangedFiles(changedFiles) {
|
|
314
|
-
return new Set(changedFiles.filter((f) => /^\.bumpy\/.*\.md$/.test(f) && !f.endsWith("README.md")).map(
|
|
349
|
+
return new Set(changedFiles.filter((f) => /^\.bumpy\/.*\.md$/.test(f) && !f.endsWith("README.md")).map(fileToId));
|
|
315
350
|
}
|
|
316
351
|
/**
|
|
317
352
|
* Filter bump files to only those added/modified on the current branch.
|
|
@@ -340,4 +375,4 @@ function filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir, parseErrors
|
|
|
340
375
|
};
|
|
341
376
|
}
|
|
342
377
|
//#endregion
|
|
343
|
-
export {
|
|
378
|
+
export { recoverDeletedBumpFiles as a, discoverWorkspace as c, readBumpFiles as i, moveBumpFilesToChannel as n, writeBumpFile as o, parseBumpFile as r, discoverPackages as s, filterBranchBumpFiles as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as log } from "./logger-BgksGFuf.mjs";
|
|
2
|
-
import { c as maxBump, t as BUMP_LEVELS } from "./types-
|
|
2
|
+
import { c as maxBump, t as BUMP_LEVELS } from "./types-lpiG-Zxh.mjs";
|
|
3
3
|
import { relative, resolve } from "node:path";
|
|
4
4
|
import { realpathSync } from "node:fs";
|
|
5
5
|
//#region src/core/changelog.ts
|
|
@@ -44,7 +44,7 @@ const defaultFormatter = (ctx) => {
|
|
|
44
44
|
const BUILTIN_FORMATTERS = {
|
|
45
45
|
default: defaultFormatter,
|
|
46
46
|
github: async () => {
|
|
47
|
-
const { createGithubFormatter } = await import("./changelog-github-
|
|
47
|
+
const { createGithubFormatter } = await import("./changelog-github-jLOtwuWj.mjs");
|
|
48
48
|
return createGithubFormatter();
|
|
49
49
|
}
|
|
50
50
|
};
|
|
@@ -55,7 +55,7 @@ const BUILTIN_FORMATTERS = {
|
|
|
55
55
|
async function loadFormatter(changelog, rootDir) {
|
|
56
56
|
const [name, options] = Array.isArray(changelog) ? changelog : [changelog, {}];
|
|
57
57
|
if (name === "github") {
|
|
58
|
-
const { createGithubFormatter } = await import("./changelog-github-
|
|
58
|
+
const { createGithubFormatter } = await import("./changelog-github-jLOtwuWj.mjs");
|
|
59
59
|
return createGithubFormatter(options);
|
|
60
60
|
}
|
|
61
61
|
if (typeof name === "string" && BUILTIN_FORMATTERS[name]) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { c as maxBump } from "./types-
|
|
1
|
+
import { c as maxBump } from "./types-lpiG-Zxh.mjs";
|
|
2
2
|
import { s as tryRunArgs } from "./shell-C8KgKnMQ.mjs";
|
|
3
|
-
import { o as sortBumpFilesByType, r as getBumpTypeForPackage } from "./changelog-
|
|
3
|
+
import { o as sortBumpFilesByType, r as getBumpTypeForPackage } from "./changelog-DuFhnJRO.mjs";
|
|
4
4
|
//#region src/core/changelog-github.ts
|
|
5
5
|
/** Authors filtered from "Thanks" attribution by default (e.g. bots) */
|
|
6
6
|
/** Authors filtered from "Thanks" attribution by default (e.g. AI/automation bots) */
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import "./config-0we4ISZX.mjs";
|
|
2
|
+
import { o as getCurrentBranch } from "./git-DAWj8LyV.mjs";
|
|
3
|
+
import "node:path";
|
|
4
|
+
//#region src/core/channels.ts
|
|
5
|
+
/** Channel names that would collide with reserved `.bumpy/` entries */
|
|
6
|
+
const RESERVED_CHANNEL_NAMES = new Set(["README", "README.md"]);
|
|
7
|
+
/**
|
|
8
|
+
* Resolve all configured channels, applying defaults and validating names.
|
|
9
|
+
* Defaults: preid/tag = channel name; versionPr.title = "<base-title> (<name>)";
|
|
10
|
+
* versionPr.branch = "<base-branch>-<name>".
|
|
11
|
+
*/
|
|
12
|
+
function resolveChannels(config) {
|
|
13
|
+
const channels = /* @__PURE__ */ new Map();
|
|
14
|
+
const seenBranches = /* @__PURE__ */ new Map();
|
|
15
|
+
for (const [name, raw] of Object.entries(config.channels || {})) {
|
|
16
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(name) || name.startsWith("_") || RESERVED_CHANNEL_NAMES.has(name)) throw new Error(`Invalid channel name "${name}" — channel names become .bumpy/ subdirectories and must be alphanumeric (plus ".", "-", "_"), not start with "_", and not collide with reserved entries.`);
|
|
17
|
+
if (!raw.branch || typeof raw.branch !== "string") throw new Error(`Channel "${name}" is missing required "branch" field`);
|
|
18
|
+
if (raw.branch === config.baseBranch) throw new Error(`Channel "${name}" cannot use the base branch ("${config.baseBranch}") as its channel branch`);
|
|
19
|
+
const existing = seenBranches.get(raw.branch);
|
|
20
|
+
if (existing) throw new Error(`Channels "${existing}" and "${name}" both use branch "${raw.branch}"`);
|
|
21
|
+
seenBranches.set(raw.branch, name);
|
|
22
|
+
channels.set(name, {
|
|
23
|
+
name,
|
|
24
|
+
branch: raw.branch,
|
|
25
|
+
preid: raw.preid ?? name,
|
|
26
|
+
tag: raw.tag ?? name,
|
|
27
|
+
versionPr: {
|
|
28
|
+
title: raw.versionPr?.title ?? `${config.versionPr.title} (${name})`,
|
|
29
|
+
branch: raw.versionPr?.branch ?? `${config.versionPr.branch}-${name}`,
|
|
30
|
+
automerge: raw.versionPr?.automerge ?? false
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return channels;
|
|
35
|
+
}
|
|
36
|
+
/** Names of all configured channels (used as `.bumpy/` subdirectory names) */
|
|
37
|
+
function channelNames(config) {
|
|
38
|
+
return Object.keys(config.channels || {});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Detect the branch the release flow is running for.
|
|
42
|
+
* In GitHub Actions push events, HEAD is often detached — prefer GITHUB_REF_NAME.
|
|
43
|
+
*/
|
|
44
|
+
function detectReleaseBranch(rootDir) {
|
|
45
|
+
const refName = process.env.GITHUB_REF_NAME;
|
|
46
|
+
const refType = process.env.GITHUB_REF_TYPE;
|
|
47
|
+
if (refName && refType !== "tag") return refName;
|
|
48
|
+
const branch = getCurrentBranch({ cwd: rootDir });
|
|
49
|
+
if (!branch || branch === "HEAD") return null;
|
|
50
|
+
return branch;
|
|
51
|
+
}
|
|
52
|
+
/** Find the channel matching a branch name, if any */
|
|
53
|
+
function matchChannelByBranch(config, branch) {
|
|
54
|
+
if (!branch) return null;
|
|
55
|
+
for (const channel of resolveChannels(config).values()) if (channel.branch === branch) return channel;
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolve the active channel for a command:
|
|
60
|
+
* an explicit `--channel <name>` override wins, otherwise the current branch is matched.
|
|
61
|
+
* Throws if an explicit override names an unknown channel.
|
|
62
|
+
*/
|
|
63
|
+
function resolveActiveChannel(rootDir, config, override) {
|
|
64
|
+
if (override) {
|
|
65
|
+
const channel = resolveChannels(config).get(override);
|
|
66
|
+
if (!channel) {
|
|
67
|
+
const known = channelNames(config);
|
|
68
|
+
throw new Error(`Unknown channel "${override}"${known.length ? ` — configured channels: ${known.join(", ")}` : " — no channels are configured in .bumpy/_config.json"}`);
|
|
69
|
+
}
|
|
70
|
+
return channel;
|
|
71
|
+
}
|
|
72
|
+
return matchChannelByBranch(config, detectReleaseBranch(rootDir));
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
75
|
+
export { channelNames, detectReleaseBranch, matchChannelByBranch, resolveActiveChannel, resolveChannels };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { a as __exportAll, i as __commonJSMin, n as log, s as __toESM, t as colorize } from "./logger-BgksGFuf.mjs";
|
|
2
2
|
import { n as exists, s as readText } from "./fs-CBXKZhoU.mjs";
|
|
3
|
-
import { a as DEP_TYPES } from "./types-
|
|
4
|
-
import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir } from "./config-
|
|
3
|
+
import { a as DEP_TYPES } from "./types-lpiG-Zxh.mjs";
|
|
4
|
+
import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir } from "./config-0we4ISZX.mjs";
|
|
5
5
|
import { a as isCatalogRefAffected, i as diffCatalogMaps, n as detectPackageManager, o as parseCatalogs, t as CATALOG_FILES } from "./package-manager-Db_vTztt.mjs";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { c as discoverWorkspace, i as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-mRJeReRJ.mjs";
|
|
7
|
+
import { a as getChangedFiles, d as readFileAtRef, r as getBaseCompareRef, s as getFileStatuses } from "./git-DAWj8LyV.mjs";
|
|
8
8
|
import { relative, resolve } from "node:path";
|
|
9
9
|
//#region ../../node_modules/.bun/picomatch@4.0.4/node_modules/picomatch/lib/constants.js
|
|
10
10
|
var require_constants = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
@@ -1894,8 +1894,20 @@ var import_picomatch = /* @__PURE__ */ __toESM(require_picomatch(), 1);
|
|
|
1894
1894
|
async function checkCommand(rootDir, opts = {}) {
|
|
1895
1895
|
const config = await loadConfig(rootDir);
|
|
1896
1896
|
const { packages } = await discoverWorkspace(rootDir, config);
|
|
1897
|
-
const
|
|
1898
|
-
const
|
|
1897
|
+
const { resolveChannels, detectReleaseBranch } = await import("./channels-CFXZkyGd.mjs");
|
|
1898
|
+
const currentBranch = detectReleaseBranch(rootDir);
|
|
1899
|
+
if (currentBranch) {
|
|
1900
|
+
const skipBranches = new Set([config.versionPr.branch]);
|
|
1901
|
+
for (const channel of resolveChannels(config).values()) {
|
|
1902
|
+
skipBranches.add(channel.branch);
|
|
1903
|
+
skipBranches.add(channel.versionPr.branch);
|
|
1904
|
+
}
|
|
1905
|
+
if (skipBranches.has(currentBranch)) {
|
|
1906
|
+
log.dim(` Skipping check — "${currentBranch}" is a channel or release PR branch.`);
|
|
1907
|
+
return;
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
const changedFiles = getChangedFiles(rootDir, opts.base || config.baseBranch);
|
|
1899
1911
|
if (changedFiles.length === 0) {
|
|
1900
1912
|
log.info("No changed files detected.");
|
|
1901
1913
|
return;
|