Skip to content
Merged
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions .bumpy/none-semantics-and-check-hooks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@varlock/bumpy': minor
---

Changed `none` bump type to no longer suppress cascading bumps — it now just skips the direct bump while allowing dependency propagation to apply normally. Added `--hook` flag to `bumpy check` for pre-commit/pre-push hook context, with untracked/staged bump file detection. Added `bumpy add --none` shortcut to acknowledge all changed packages without bumping. Empty bump files no longer bypass `--strict` mode.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ A modern package versioning, release, and changelog generation tool. Built for m
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:

- Devs/agents create bump files as part of their PRs (using `bumpy add` or manually)
- A pre-push git hook can enforce bump files exist for changed packages
- 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
Expand Down
23 changes: 15 additions & 8 deletions docs/bump-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ Fixed locale fallback logic in utils.

### Bump levels

| Level | When to use |
| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `major` | Breaking changes |
| `minor` | New features (backwards-compatible) |
| `patch` | Bug fixes, minor improvements |
| `none` | Acknowledges a change without triggering a release — useful for covering packages in `--strict` mode, or in cascades to exclude specific packages from propagation |
| Level | When to use |
| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `major` | Breaking changes |
| `minor` | New features (backwards-compatible) |
| `patch` | Bug fixes, minor improvements |
| `none` | Acknowledges a change without triggering a direct bump — useful for covering packages in `--strict` mode. Cascading bumps from other packages can still apply. |

## File naming

Expand Down Expand Up @@ -66,6 +66,7 @@ Flags:
- `--message <text>` — changelog description
- `--name <name>` — set the filename (auto-slugified). If omitted, a random name is generated.
- `--empty` — create an empty bump file (marks a PR as intentionally having no releases)
- `--none` — create a bump file with all changed packages set to `none` (acknowledge without bumping)

### From branch commits

Expand All @@ -92,15 +93,21 @@ This prevents `bumpy check` and `bumpy ci check` from failing due to missing bum

### `none` bump type

If you're using `--strict` mode (which requires every changed package to be covered), use bump type `none` to acknowledge a package changed without triggering a release:
Use bump type `none` to acknowledge that a package changed without triggering a direct version bump. This is useful when a package has internal-only changes (tests, config, etc.) that don't warrant a release on their own:

```markdown
---
'@myorg/docs-site': none
---
```

This covers the package in strict checks without producing a version bump or changelog entry.
This covers the package in `bumpy check` (including `--strict` mode) without producing a version bump or changelog entry. However, if another package's bump cascades to this package (e.g., via dependency propagation), the cascade will still apply normally.

To quickly set all changed packages to `none`:

```bash
bumpy add --none
```

## Cascade control (advanced)

Expand Down
39 changes: 28 additions & 11 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,16 @@ Create a bump file interactively or non-interactively.
bumpy add # interactive
bumpy add --packages "core:minor,utils:patch" --message "Added features" # non-interactive
bumpy add --empty --name "docs-only-pr" # empty (no releases)
bumpy add --none # all changed packages → none
```

| Flag | Description |
| ------------------- | -------------------------------------------------------------------------- |
| `--packages <list>` | Comma-separated `name:level` pairs |
| `--message <text>` | Changelog description |
| `--name <name>` | Bump file filename (auto-slugified) |
| `--empty` | Create an empty bump file (marks a PR as intentionally having no releases) |
| Flag | Description |
| ------------------- | ------------------------------------------------------------------------------------- |
| `--packages <list>` | Comma-separated `name:level` pairs |
| `--message <text>` | Changelog description |
| `--name <name>` | Bump file filename (auto-slugified) |
| `--empty` | Create an empty bump file (marks a PR as intentionally having no releases) |
| `--none` | Set all changed packages to `none` (acknowledge without bumping, for `--strict` mode) |

## `bumpy status`

Expand Down Expand Up @@ -95,20 +97,35 @@ bumpy publish --filter "@myorg/*"

## `bumpy check`

Verify that changed packages on the current branch have corresponding bump files. Designed for pre-push hooks — compares your branch to the base branch, maps changed files to packages.
Verify that changed packages on the current branch have corresponding bump files. Compares your branch to the base branch, maps changed files to packages, and checks for matching bump files.

By default, exits non-zero only if **no** bump files exist at all (matching changesets behavior). Use `--strict` to require every changed package to be covered.

```bash
bumpy check
bumpy check --strict
bumpy check --no-fail
bumpy check --hook pre-commit
bumpy check --hook pre-push
```

| Flag | Description |
| ----------- | ---------------------------------------------------------- |
| `--strict` | Fail if any changed package is not covered by a bump file |
| `--no-fail` | Warn only, never exit non-zero (useful for advisory hooks) |
| Flag | Description |
| ------------------- | ---------------------------------------------------------- |
| `--strict` | Fail if any changed package is not covered by a bump file |
| `--no-fail` | Warn only, never exit non-zero (useful for advisory hooks) |
| `--hook pre-commit` | Only count staged + committed bump files |
| `--hook pre-push` | Only count committed bump files |

### Hook context

By default (no `--hook` flag), bumpy detects all bump files — including untracked and staged files that haven't been committed yet. This is convenient when running `bumpy check` manually.

When used as a git hook, `--hook` controls which bump files count:

- **`--hook pre-commit`** — staged and committed bump files count. Untracked bump files are warned about (they won't be included in the commit).
- **`--hook pre-push`** — only committed bump files count. Staged and untracked bump files are warned about (they won't be included in the push).

The output also annotates bump files with their git status (`staged`, `untracked`) so you can see at a glance what's been committed.

No GitHub API needed.

Expand Down
2 changes: 1 addition & 1 deletion docs/differences-from-changesets.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ Bumpy replaces all of this with two CLI commands you run directly in standard wo

### Local bump file verification

`bumpy check` verifies that changed packages on the current branch have corresponding bump files. Designed for pre-push hooks — compares your branch to the base branch, maps changed files to packages. By default it only fails if no bump files exist at all (matching changesets behavior). Use `--strict` to require every changed package to be covered, or `--no-fail` for advisory-only mode. No GitHub API needed.
`bumpy check` verifies that changed packages on the current branch have corresponding bump files. Compares your branch to the base branch, maps changed files to packages. By default it only fails if no bump files exist at all (matching changesets behavior). Use `--strict` to require every changed package to be covered, `--no-fail` for advisory-only mode, or `--hook pre-commit`/`--hook pre-push` to control which bump files count based on their git status. No GitHub API needed.

Changesets has no built-in equivalent — users rely on the CI bot comment to catch missing bump files after pushing.

Expand Down
2 changes: 1 addition & 1 deletion docs/version-propagation.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ Unlike dependency bump rules (configured on the _dependent_), `cascadeTo` is con

These are set directly in bump files for one-off control over a specific release.

**`none`** — suppresses a bump on a package that would otherwise be included via propagation. If skipping the bump would leave a dependent's range broken, bumpy throws an error.
**`none`** — acknowledges a change without triggering a direct bump. Unlike a real bump type, `none` doesn't add the package to the release plan on its own. However, cascading bumps from other packages (e.g., out-of-range or proactive propagation) can still bump it normally.

```yaml
---
Expand Down
2 changes: 1 addition & 1 deletion lefthook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ pre-commit:
pre-push:
jobs:
- name: bumpy-check
run: bunx @varlock/bumpy check
run: bunx @varlock/bumpy check --hook pre-push
2 changes: 1 addition & 1 deletion packages/bumpy/skills/add-change/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ For each affected package, choose the appropriate bump level:
| **minor** | New features: added exports, new options, new functionality |
| **patch** | Bug fixes, internal refactors, documentation, dependency updates |

Use `none` in a bump file to suppress a bump on a package that would otherwise be included via propagation. If skipping would leave a broken range, bumpy throws an error.
Use `none` in a bump file to acknowledge a change without triggering a direct bump. Cascading bumps from other packages can still apply normally.

### 4. Write a clear summary

Expand Down
12 changes: 11 additions & 1 deletion packages/bumpy/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ async function main() {
message: flags.message as string | undefined,
name: flags.name as string | undefined,
empty: flags.empty === true,
none: flags.none === true,
});
break;
}
Expand Down Expand Up @@ -86,9 +87,15 @@ async function main() {
case 'check': {
const rootDir = await findRoot();
const { checkCommand } = await import('./commands/check.ts');
const hookValue = flags.hook as string | undefined;
if (hookValue && hookValue !== 'pre-commit' && hookValue !== 'pre-push') {
log.error(`Invalid --hook value "${hookValue}". Expected "pre-commit" or "pre-push".`);
process.exit(1);
}
await checkCommand(rootDir, {
strict: flags.strict === true,
noFail: flags['no-fail'] === true,
hook: hookValue as 'pre-commit' | 'pre-push' | undefined,
});
break;
}
Expand Down Expand Up @@ -184,11 +191,14 @@ function printHelp() {
Commands:
init [--force] Initialize .bumpy/ (migrates from .changeset/ if found)
add Create a new bump file
--none Set all changed packages to "none" (acknowledge without bumping)
--empty Create an empty bump file (no releases needed)
generate Generate bump file from branch commits
status Show pending releases
check Verify changed packages have bump files (for pre-push hooks)
check Verify changed packages have bump files (for git hooks)
--strict Fail if any changed package is uncovered (default: only fail if no bump files at all)
--no-fail Warn only, never exit 1
--hook <context> Hook context: "pre-commit" or "pre-push" (controls which bump files count)
version [--commit] Apply bump files and bump versions
publish Publish versioned packages
ci check PR check — report pending releases, comment on PR
Expand Down
32 changes: 31 additions & 1 deletion packages/bumpy/src/commands/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { randomName, slugify } from '../utils/names.ts';
import { writeBumpFile } from '../core/bump-file.ts';
import picomatch from 'picomatch';
import { getBumpyDir, loadConfig, loadPackageConfig, matchGlob } from '../core/config.ts';
import { discoverPackages } from '../core/workspace.ts';
import { discoverPackages, discoverWorkspace } from '../core/workspace.ts';
import { findChangedPackages } from './check.ts';
import { DependencyGraph } from '../core/dep-graph.ts';
import { getChangedFiles } from '../core/git.ts';
import { bumpSelectPrompt } from '../prompts/bump-select.ts';
Expand All @@ -19,6 +20,7 @@ interface AddOptions {
message?: string;
name?: string;
empty?: boolean;
none?: boolean;
}

const CASCADE_CHOICES: { label: string; value: BumpType }[] = [
Expand All @@ -42,6 +44,34 @@ export async function addCommand(rootDir: string, opts: AddOptions): Promise<voi
return;
}

// Handle --none flag: create bump file with all changed packages set to none
if (opts.none) {
const { packages } = await discoverWorkspace(rootDir, config);
const changedFiles = getChangedFiles(rootDir, config.baseBranch);
const changedPackages = await findChangedPackages(changedFiles, packages, rootDir, config);

if (changedPackages.length === 0) {
log.info('No changed packages detected.');
return;
}

const releases: BumpFileRelease[] = changedPackages.map((name) => ({ name, type: 'none' as const }));
const summary = opts.message || '';
const filename = opts.name ? slugify(opts.name) : randomName();

if (await exists(resolve(bumpyDir, `${filename}.md`))) {
await writeBumpFile(rootDir, `${filename}-${Date.now()}`, releases, summary);
} else {
await writeBumpFile(rootDir, filename, releases, summary);
}

log.success(`🐸 Created bump file with ${changedPackages.length} package(s) set to none: .bumpy/${filename}.md`);
for (const name of changedPackages) {
log.dim(` ${name}: none`);
}
return;
}

let releases: BumpFileRelease[];
let summary: string;
let filename: string;
Expand Down
Loading