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/ci-plan-command.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@varlock/bumpy': minor
---

Add `bumpy ci plan` command for conditional CI builds
19 changes: 18 additions & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ on:
push:
branches: [main]

concurrency:
group: bumpy-release
cancel-in-progress: false

jobs:
release:
runs-on: ubuntu-latest
Expand All @@ -28,7 +32,20 @@ jobs:
- run: bun install
# -------------------------------

# 🐸 This is the important part - creates/updates release PR when PRs merge to main, publishes packages when release PR is merged
# 🐸 Plan first — detects mode and caches the result for ci release
# Outputs: mode (version-pr|publish|nothing), packages (comma-separated), json (full plan)
- id: plan
run: bunx @varlock/bumpy ci plan
env:
GH_TOKEN: ${{ github.token }}

# Example: conditionally run expensive steps only when publishing
# In your project, this is where you'd put build/compile/test steps
# that are only needed before a publish (not when updating the version PR)
- if: steps.plan.outputs.mode == 'publish'
run: echo "📦 Publish mode — packages to release:" && echo "${{ steps.plan.outputs.packages }}"

# Creates/updates release PR when PRs merge to main, publishes packages when release PR is merged
- run: bunx @varlock/bumpy ci release
env:
GH_TOKEN: ${{ github.token }}
Expand Down
39 changes: 39 additions & 0 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,45 @@ bumpy ci check --no-fail

Requires `GH_TOKEN` environment variable (automatically available in GitHub Actions).

## `bumpy ci plan`

CI command that reports what `ci release` would do, without acting. Outputs JSON to stdout and sets GitHub Actions step outputs so you can conditionally run expensive steps (builds, etc.) only when needed.

```bash
bumpy ci plan
```

**Output (JSON to stdout):**

```jsonc
{
"mode": "version-pr", // "version-pr" | "publish" | "nothing"
"bumpFiles": [...], // same shape as `bumpy status --json`
"releases": [...],
"packageNames": ["pkg-a", "pkg-b"]
}
```

**Modes:**

| Mode | Meaning | `releases` contains |
| ------------ | ------------------------------------------------------ | -------------------------------- |
| `version-pr` | Bump files exist — would create/update the version PR | Planned releases from bump files |
| `publish` | No bump files — unpublished packages detected | Packages that would be published |
| `nothing` | No bump files, no unpublished packages — nothing to do | Empty |

**GitHub Actions outputs** (set via `$GITHUB_OUTPUT`):

| Output | Description |
| ---------- | ------------------------------------- |
| `mode` | `version-pr`, `publish`, or `nothing` |
| `packages` | Comma-separated package names |
| `json` | Full JSON output (for `fromJSON()`) |

When `ci plan` runs before `ci release` in the same workflow, the plan is cached so `ci release` can skip duplicate registry lookups. The cache is validated against the workspace (package names and versions must match) and deleted after use.

See [GitHub Actions setup](github-actions.md) for workflow examples.

## `bumpy ci release`

CI command for releases. Has two modes:
Expand Down
83 changes: 82 additions & 1 deletion docs/github-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Bumpy handles CI automation with two commands — no separate GitHub Action or b
| Command | Trigger | What it does |
| ------------------ | -------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `bumpy ci check` | `pull_request` | Posts/updates a PR comment with the release plan. Warns about missing bump files. |
| `bumpy ci plan` | `push` to main | Reports what `ci release` would do (JSON + GitHub Actions outputs). Use to conditionally gate expensive steps. |
| `bumpy ci release` | `push` to main | Creates/updates a "Version Packages" PR. When that PR is merged, publishes packages, creates git tags, and creates GitHub releases. |

## PR check workflow
Expand All @@ -32,7 +33,7 @@ jobs:

## Release workflow

### Trusted publishing (OIDC recommended)
### Trusted publishing (OIDC ��� recommended)

No `NPM_TOKEN` secret needed. Requires npm >= 11.5.1.

Expand All @@ -43,6 +44,10 @@ on:
push:
branches: [main]

concurrency:
group: bumpy-release
cancel-in-progress: false

jobs:
release:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -78,6 +83,10 @@ on:
push:
branches: [main]

concurrency:
group: bumpy-release
cancel-in-progress: false

jobs:
release:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -105,6 +114,78 @@ Instead of the two-step flow (version PR → merge → publish), you can version
- run: bunx @varlock/bumpy ci release --auto-publish
```

## Conditional builds with `ci plan`

Publishing often requires expensive build steps that aren't needed when just updating the version PR. Use `bumpy ci plan` to detect what `ci release` would do and conditionally gate those steps.

`ci plan` outputs JSON to stdout, sets GitHub Actions step outputs, and caches the result so that `ci release` can skip duplicate registry lookups in the same workflow run.

| Output | Description |
| ---------- | ------------------------------------- |
| `mode` | `version-pr`, `publish`, or `nothing` |
| `packages` | Comma-separated package names |
| `json` | Full JSON output (for `fromJSON()`) |

### Basic: skip builds unless publishing

```yaml
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
id-token: write
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: oven-sh/setup-bun@v2
- uses: actions/setup-node@v6
with:
node-version: lts/*
- run: bun install

- id: plan
run: bunx @varlock/bumpy ci plan
env:
GH_TOKEN: ${{ github.token }}

# Only run expensive build when we're about to publish
- if: steps.plan.outputs.mode == 'publish'
run: bun run build

- run: bunx @varlock/bumpy ci release
env:
GH_TOKEN: ${{ github.token }}
BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }}
```

### Advanced: conditional steps per package

```yaml
- id: plan
run: bunx @varlock/bumpy ci plan
env:
GH_TOKEN: ${{ github.token }}

# Build only specific packages that are being released
- if: contains(steps.plan.outputs.packages, 'my-expensive-package')
run: bun run build --filter=my-expensive-package
```

## Concurrency

Use a concurrency group on your release workflow to prevent overlapping publish runs. Without this, rapid merges to main could trigger multiple workflows that race to publish the same packages.

```yaml
concurrency:
group: bumpy-release
cancel-in-progress: false # queue rather than cancel — don't skip releases
```

This is included in all the workflow examples above.

## Token setup

### `GH_TOKEN` (required)
Expand Down
6 changes: 5 additions & 1 deletion packages/bumpy/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ async function main() {
strict: ciFlags.strict === true,
noFail: ciFlags['no-fail'] === true,
});
} else if (subcommand === 'plan') {
const { ciPlanCommand } = await import('./commands/ci.ts');
await ciPlanCommand(rootDir);
} else if (subcommand === 'release') {
const { ciReleaseCommand } = await import('./commands/ci.ts');
const mode = ciFlags['auto-publish'] === true ? ('auto-publish' as const) : ('version-pr' as const);
Expand All @@ -124,7 +127,7 @@ async function main() {
const { ciSetupCommand } = await import('./commands/ci-setup.ts');
await ciSetupCommand(rootDir);
} else {
log.error(`Unknown ci subcommand: ${subcommand}. Use "ci check", "ci release", or "ci setup".`);
log.error(`Unknown ci subcommand: ${subcommand}. Use "ci check", "ci plan", "ci release", or "ci setup".`);
process.exit(1);
}
break;
Expand Down Expand Up @@ -202,6 +205,7 @@ function printHelp() {
version [--commit] Apply bump files and bump versions
publish Publish versioned packages
ci check PR check — report pending releases, comment on PR
ci plan Report what ci release would do (JSON + GitHub Actions outputs)
ci release Release — create version PR or auto-publish
ci setup Set up a token for triggering CI on version PRs
ai setup Install AI skill for creating bump files
Expand Down
Loading