Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 20 additions & 139 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,21 @@

# @varlock/bumpy 🐸

A modern package versioning, release, and changelog generation tool. Built for monorepos, but works great in simpler projects too.
A modern package versioning, release, and changelog generation tool. Built for monorepos, but works great in simple projects too.

## How It Works

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. Specifically:
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.

- Devs/agents create bump files as part of their PRs (using `bumpy add` or manually)
- A git hook (pre-commit or pre-push) can enforce bump files exist for changed packages
- In CI, a workflow checks PRs for bump files, leaves a comment on the PR detailing changed packages
- As PRs merge to the base branch, a "release PR" is kept up to date
- Shows what packages will be released and their changelogs
- Including packages bumped automatically due to dependency relationships
- Shows what packages will be released and their changelogs (incl. those bumped via dep relationships)
- When release PR is merged, publishing is triggered
- Pending bump files are deleted and packages are published with updated versions and changelogs
- Pending bump files are deleted and packages are published with updated versions and changelogs, github tags+releases created

All of this is automated via two simple GitHub Actions workflows (see [CI setup](#ci--github-actions) below). You can also run everything locally with `bumpy status`, `bumpy version`, and `bumpy publish`.
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.

### Example bump file

Expand All @@ -42,21 +41,23 @@ All of this is automated via two simple GitHub Actions workflows (see [CI setup]
'@myorg/utils': patch
---

Added user language preference to the core config.
Added user lang prefs to core config.
Fixed locale fallback logic in utils.
```

## Features

- **All package managers** - npm, pnpm, yarn, and bun workspaces
- **All package managers** - npm, pnpm, yarn, and bun workspaces. With full `workspace:` and `catalog:` support
- **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))
- **Pack-then-publish** - by default, publishes to npm (resolving `workspace:` and `catalog:` protocols, with OIDC/provenance support). Supports [npm staged publishing](https://docs.npmjs.com/staged-publishing) for 2FA-gated releases. Per-package custom publish commands let you target anything - VSCode extensions, Docker images, JSR, private registries, etc.
- **OIDC + staged publishing** - supports OIDC, provenance, [npm staged publishing](https://docs.npmjs.com/staged-publishing)
- **Custom release targets** - Per-package custom publish commands let you target anything - VSCode extensions, Docker images, JSR, private registries, etc.
- **Flexible package management** - include/exclude any package individually via per-package config, glob patterns, or `privatePackages` setting
- **Non-interactive CLI** - `bumpy add` works fully non-interactively for CI/CD and AI-assisted development
- **Aggregated GitHub releases** - optionally create a single consolidated release instead of one per package
- **Auto-generate from commits** - `bumpy generate` creates bump files from branch commits - works with any commit style, with enhanced detection for conventional commits
- **Pluggable changelog formatters** - built-in `"default"` and `"github"` formatters, or write your own
- **Zero runtime dependencies** - dependencies are minimal and bundled at release time
- **No additional action/app needed** - no external github action or app to audit and trust

## Getting Started

Expand All @@ -67,6 +68,9 @@ bun add -d @varlock/bumpy # or npm/pnpm/yarn
# Initialize (creates .bumpy/ directory and config, migrates from changesets if applicable)
bunx bumpy init

# Interactive guidance setting up CI
bunx bumpy ci setup

# Create a bump file
bunx bumpy add

Expand All @@ -78,138 +82,15 @@ Then set up CI to automate versioning and publishing (see below).

## CI / GitHub Actions

No GitHub App to install, no separate action to rely on - just call `bumpy ci` directly in your workflows. Two commands handle the entire release lifecycle:

- **`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.
- **`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.

_examples use bun, but works with Node.js_

### PR check workflow

```yaml
# .github/workflows/bumpy-check.yaml
#
# ⚠️ Uses `pull_request_target` so fork PR comments work — runs with write
# perms and secrets, so it MUST NOT execute PR code (no `bun install`, no
# PR-defined scripts). Bumpy only reads files; its version is resolved from
# the base branch's package.json. See docs/github-actions.md for details.
name: Bumpy Check
on: pull_request_target

permissions:
pull-requests: write
contents: read

jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
- uses: oven-sh/setup-bun@v2

# Resolve bumpy's version from the base branch (trusted) — not the PR's
# package.json (which a fork PR could swap to a malicious version).
# Change "main" to your base branch if different.
- name: Resolve bumpy version from base
run: |
git fetch origin main --depth=1
VERSION=$(git show "origin/main:package.json" \
| jq -r '.devDependencies["@varlock/bumpy"] // .dependencies["@varlock/bumpy"]' \
| sed 's/[\^~]//')
echo "BUMPY_VERSION=$VERSION" >> "$GITHUB_ENV"

- run: bunx "@varlock/bumpy@$BUMPY_VERSION" ci check
env:
GH_TOKEN: ${{ github.token }}
```

### Release workflow

```yaml
# .github/workflows/bumpy-release.yml - trusted publishing (OIDC, no secret needed)
name: Bumpy Release
on:
push:
branches: [main]

jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
id-token: write # required for npm trusted publishing (OIDC) and provenance
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: oven-sh/setup-bun@v2
- uses: actions/setup-node@v6
with:
node-version: latest
- run: npm install -g npm@latest # ensure npm >= 11.15.0 for OIDC/staged publishing
- run: bun install
- run: bunx @varlock/bumpy ci release
env:
GH_TOKEN: ${{ github.token }}
BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }} # PAT so that version PR triggers CI
```

> **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.

<details>
<summary>Alternative: token-based auth (NPM_TOKEN secret)</summary>

```yaml
# .github/workflows/bumpy-release.yml - token-based auth
name: Bumpy Release
on:
push:
branches: [main]

jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bunx @varlock/bumpy ci release
env:
GH_TOKEN: ${{ github.token }}
BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
```

</details>

### Token setup

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.
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:

Run `bumpy ci setup` for interactive guidance, or set it up manually:
- **`bumpy ci check`** — on every PR, posts/updates a comment showing the release plan and warns if changed packages are missing bump files.
- **`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.
- **`bumpy ci release`** — opens/updates the "Version Packages" PR, or publishes new versions and creates git tags + GitHub releases when that PR is merged.

1. Create a [fine-grained personal access token](https://github.com/settings/personal-access-tokens) with:
- **Repository access:** your repo only
- **Permissions:** Contents (read & write), Pull requests (read & write)
2. Add it as a repository secret named `BUMPY_GH_TOKEN`
3. Add it to your release workflow:
```yaml
- run: bunx @varlock/bumpy ci release
env:
GH_TOKEN: ${{ github.token }}
BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }}
```
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.

### Local versioning and publishing
## Local versioning and publishing

If you prefer to version and publish locally instead of via CI:

Expand Down Expand Up @@ -270,7 +151,7 @@ bunx bumpy --help # invoke built cli
- Better support for versioning non-JS packages and usage without package.json files
- Plugin system for different publish targets, and support multiple targets per package
- Tracking workspace-level / non-publishable changes
- More frogs 🐸
- More frogs 🐸🐸🐸

---

Expand Down