Skip to content

Commit fe31f8a

Browse files
committed
rename --mode to --expect-mode for clarity
The flag asserts the detected mode rather than setting it, so the name should reflect that. Reads more naturally in YAML where there's no surrounding context. Internal `assertMode` field name unchanged.
1 parent cccf862 commit fe31f8a

7 files changed

Lines changed: 37 additions & 29 deletions

File tree

.bumpy/ci-expect-mode-flag.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@varlock/bumpy': minor
3+
---
4+
5+
Add `--expect-mode` flag to `bumpy ci release` for asserting the detected release mode (`version-pr` or `publish`). Enables split-job release workflows where each job fails loudly if the runtime state doesn't match what the job expects. Refactored `ReleaseOptions` to rename the existing `mode` field to `autoPublish: boolean` and add `assertMode`. `--expect-mode` and `--auto-publish` cannot be combined.

.bumpy/ci-mode-flag.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.github/workflows/release.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ jobs:
5858
- run: bun install
5959
# -------------------------------
6060

61-
- run: bunx @varlock/bumpy ci release --mode version-pr
61+
- run: bunx @varlock/bumpy ci release --expect-mode version-pr
6262
env:
6363
GH_TOKEN: ${{ github.token }}
6464
BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }} # <- PAT so that version PR triggers CI
@@ -92,7 +92,7 @@ jobs:
9292

9393
- run: echo "📦 Publishing packages:" && echo "${{ needs.plan.outputs.packages }}"
9494

95-
- run: bunx @varlock/bumpy ci release --mode publish
95+
- run: bunx @varlock/bumpy ci release --expect-mode publish
9696
env:
9797
GH_TOKEN: ${{ github.token }}
9898
# We dont use the default GH token so that further workflows can be triggred by GH release events

docs/cli.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -231,12 +231,12 @@ bumpy ci release --auto-publish
231231
bumpy ci release --auto-publish --tag beta
232232
```
233233

234-
| Flag | Description |
235-
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
236-
| `--mode <mode>` | Assert detected mode: `version-pr` or `publish`. Errors if the detected mode differs. Use to gate split-job workflows so a job can't silently fall into the wrong path. |
237-
| `--auto-publish` | Version + publish directly instead of creating a PR |
238-
| `--tag <tag>` | npm dist-tag (for `--auto-publish`) |
239-
| `--branch <name>` | Version PR branch name (default: `bumpy/version-packages`) |
234+
| Flag | Description |
235+
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
236+
| `--expect-mode <mode>` | Assert detected mode: `version-pr` or `publish`. Errors if the detected mode differs. Use to gate split-job workflows so a job can't silently fall into the wrong path. |
237+
| `--auto-publish` | Version + publish directly instead of creating a PR |
238+
| `--tag <tag>` | npm dist-tag (for `--auto-publish`) |
239+
| `--branch <name>` | Version PR branch name (default: `bumpy/version-packages`) |
240240

241241
Requires `GH_TOKEN`. When `BUMPY_GH_TOKEN` is set, it is automatically used to push the version branch and create/edit the PR so that PR workflows trigger (see [GitHub Actions setup](github-actions.md#token-setup)).
242242

docs/github-actions.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ jobs:
8080
fetch-depth: 0
8181
- uses: oven-sh/setup-bun@v2
8282
- run: bun install
83-
- run: bunx @varlock/bumpy ci release --mode version-pr
83+
- run: bunx @varlock/bumpy ci release --expect-mode version-pr
8484
env:
8585
GH_TOKEN: ${{ github.token }}
8686
BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }} # so the version PR triggers CI
@@ -106,7 +106,7 @@ jobs:
106106
- run: bun install
107107
# Expensive build steps that only matter before publish go here:
108108
# - run: bun run build
109-
- run: bunx @varlock/bumpy ci release --mode publish
109+
- run: bunx @varlock/bumpy ci release --expect-mode publish
110110
env:
111111
GH_TOKEN: ${{ github.token }}
112112
BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }} # so `release: published` workflows trigger
@@ -116,14 +116,22 @@ jobs:
116116
117117
- `plan` runs `bumpy ci plan` to determine whether the current push should update the Version Packages PR (`version-pr`), publish unpublished packages (`publish`), or do nothing.
118118
- Only one of `version-pr` or `publish` runs per push. The other is skipped via the `if:` condition.
119-
- The `--mode` flag on `ci release` asserts that the detected mode matches what each job expects — if the runtime state ever drifts, the job fails loudly instead of silently doing the wrong thing.
119+
- The `--expect-mode` flag on `ci release` asserts that the detected mode matches what each job expects — if the runtime state ever drifts, the job fails loudly instead of silently doing the wrong thing.
120120
- Expensive build steps (compilation, tests, bundling) only run inside the `publish` job, so PR merges that just maintain the version PR stay cheap.
121121

122-
### One-time setup
122+
### Required setup
123123

124-
1. **Create the `publish` environment** in repo Settings → Environments. GitHub auto-creates it on the first run, but creating it manually lets you add protection rules (required reviewers, branch restrictions to `main` only) before any release runs.
125-
2. **Pin the npm trusted publisher to environment `publish`** on each package's npmjs.com settings → Trusted Publishers → GitHub Actions. Set the environment field to `publish`. This binds the OIDC trust to that specific environment — even if someone adds a rogue workflow file, npm will reject any token request that doesn't carry the `publish` environment claim.
126-
3. **Set `BUMPY_GH_TOKEN`** — see [Token setup](#token-setup) below.
124+
1. **Pin the npm trusted publisher to environment `publish`** on each package's npmjs.com settings → Trusted Publishers → GitHub Actions. Set the environment field to `publish`. This binds the OIDC trust to that specific environment — even if someone adds a rogue workflow file, npm will reject any token request that doesn't carry the `publish` environment claim.
125+
2. **Set `BUMPY_GH_TOKEN`** — see [Token setup](#token-setup) below.
126+
127+
That's it — the `publish` environment auto-creates on the first publish run, so no manual GitHub setup is required.
128+
129+
### Optional hardening: protection rules on the `publish` environment
130+
131+
If you create the environment manually in repo Settings → Environments _before_ the first publish, you can attach protection rules:
132+
133+
- **Restrict deployment branches to `main`** — recommended. Cheap defense in depth: non-`main` refs can never request an OIDC token from this environment, even if a workflow trigger is accidentally widened later.
134+
- **Required reviewers** — optional. Adds a manual approval gate before each publish. Usually redundant if `npmStaged: true` is enabled (below), since you already have a 2FA approval gate on npmjs.com.
127135

128136
**Recommended publish config** — enable provenance and staged publishing for maximum security:
129137

@@ -152,7 +160,7 @@ publish:
152160
contents: write
153161
steps:
154162
# ... checkout/setup-bun/setup-node/install steps ...
155-
- run: bunx @varlock/bumpy ci release --mode publish
163+
- run: bunx @varlock/bumpy ci release --expect-mode publish
156164
env:
157165
GH_TOKEN: ${{ github.token }}
158166
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

packages/bumpy/src/cli.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,19 +117,19 @@ async function main() {
117117
await ciPlanCommand(rootDir);
118118
} else if (subcommand === 'release') {
119119
const { ciReleaseCommand } = await import('./commands/ci.ts');
120-
const assertModeFlag = ciFlags.mode;
120+
const expectModeFlag = ciFlags['expect-mode'];
121121
const autoPublishFlag = ciFlags['auto-publish'] === true;
122-
if (assertModeFlag !== undefined && assertModeFlag !== 'version-pr' && assertModeFlag !== 'publish') {
123-
log.error(`Invalid --mode value: "${assertModeFlag}". Must be "version-pr" or "publish".`);
122+
if (expectModeFlag !== undefined && expectModeFlag !== 'version-pr' && expectModeFlag !== 'publish') {
123+
log.error(`Invalid --expect-mode value: "${expectModeFlag}". Must be "version-pr" or "publish".`);
124124
process.exit(1);
125125
}
126-
if (assertModeFlag !== undefined && autoPublishFlag) {
127-
log.error('--mode and --auto-publish cannot be used together.');
126+
if (expectModeFlag !== undefined && autoPublishFlag) {
127+
log.error('--expect-mode and --auto-publish cannot be used together.');
128128
process.exit(1);
129129
}
130130
await ciReleaseCommand(rootDir, {
131131
autoPublish: autoPublishFlag,
132-
assertMode: assertModeFlag as 'version-pr' | 'publish' | undefined,
132+
assertMode: expectModeFlag as 'version-pr' | 'publish' | undefined,
133133
tag: ciFlags.tag as string | undefined,
134134
branch: ciFlags.branch as string | undefined,
135135
});
@@ -250,7 +250,7 @@ function printHelp() {
250250
--no-fail Warn only, never exit 1
251251
252252
CI release options:
253-
--mode <mode> Assert detected mode: "version-pr" or "publish" (errors if mismatched)
253+
--expect-mode <mode> Assert detected mode: "version-pr" or "publish" (errors if mismatched)
254254
--auto-publish Version + publish directly (default: create version PR)
255255
--tag <tag> npm dist-tag for auto-publish
256256
--branch <name> Branch name for version PR (default: bumpy/version-packages)

packages/bumpy/src/commands/ci.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ export async function ciReleaseCommand(rootDir: string, opts: ReleaseOptions): P
409409
if (opts.assertMode && opts.assertMode !== detectedMode) {
410410
throw new Error(
411411
`Expected mode "${opts.assertMode}" but detected "${detectedMode}". ` +
412-
`Either remove --mode, or gate this step on the output of "bumpy ci plan".`,
412+
`Either remove --expect-mode, or gate this step on the output of "bumpy ci plan".`,
413413
);
414414
}
415415

0 commit comments

Comments
 (0)