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/fork-comment-workflow-run-split.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@varlock/bumpy': minor
---

Add a `pull_request` + `workflow_run` option for commenting on fork PRs, so the privileged half never touches fork code. `bumpy ci check --emit-comment <dir>` renders the release-plan comment to `<dir>/comment.md` for upload as an artifact, and a new `bumpy ci comment --body-file <path>` posts it from a `workflow_run` job. The target PR is resolved from the trusted `workflow_run` event (`head_sha`), never from the (untrusted) artifact.
69 changes: 19 additions & 50 deletions .github/workflows/bumpy-check.yaml
Original file line number Diff line number Diff line change
@@ -1,69 +1,38 @@
# 🐸 Bumpy CI check
# checks for missing bump files and posts/updates a PR comment with the release plan
# 🐸 Bumpy CI check (dogfood)
# Runs our own unreleased bumpy on every PR and renders the release-plan comment as an
# artifact. Runs on the UNPRIVILEGED `pull_request` event, so it's safe to build and run
# the PR's own bumpy (fork or not) — there's no write token or secrets to protect here.
# Posting the comment on fork PRs is the privileged half and lives in bumpy-comment.yaml
# (workflow_run). A normal project just adds
# bunx @varlock/bumpy ci check --emit-comment ./bumpy-comment
# to its existing CI workflow.
#
# ⚠️ NOTE - DO NOT COPY THIS FILE
# instead look at the recommended workflow in the docs
# ⚠️ DO NOT COPY THIS FILE — see the recommended setup in the docs:
# ➡️ https://bumpy.varlock.dev/blob/main/docs/github-actions.md ⬅️
#
# This repo builds and runs its OWN unreleased bumpy so we dogfood the current
# CLI on every PR. Two jobs, split by trust level:
# - non-fork PRs build and run the PR's OWN bumpy, so a PR previews its own
# ci-check changes. Safe because the code comes from this repo.
# - fork PRs build and run MAIN's bumpy and only READ the PR via `--cwd ./pr`,
# so no untrusted code ever touches the pull_request_target write token.
# A normal project just runs `bunx @varlock/bumpy@latest ci check --cwd ./pr`.

name: Bumpy Check

on: pull_request_target # < necessary so it can post comments on fork PRs
on: pull_request

permissions:
pull-requests: write
pull-requests: write # same-repo PRs comment directly; fork PRs are read-only (the poster handles those)
contents: read

jobs:
# Non-fork PRs (trusted): build and run the PR's OWN bumpy so it dogfoods its
# own changes. `--cwd .` acknowledges that the current checkout is trusted.
check-local:
if: github.event.pull_request.head.repo.full_name == github.repository
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0 # history to diff bump files against the PR base branch
- uses: oven-sh/setup-bun@v2
- run: bun install
# Build first since we run the local built version of bumpy.
- run: bun run --filter @varlock/bumpy build
# Re-install so the freshly-built CLI bin is linked.
- run: bun install
- run: bunx @varlock/bumpy ci check --cwd .
- run: bun install # link the freshly-built CLI bin
- run: bunx @varlock/bumpy ci check --emit-comment ./bumpy-comment
env:
GH_TOKEN: ${{ github.token }}

# Fork PRs (untrusted): build and run MAIN's bumpy from a trusted checkout and
# only READ the PR head via `--cwd ./pr` — never install/build/run fork code.
check-fork:
if: github.event.pull_request.head.repo.full_name != github.repository
runs-on: ubuntu-latest
steps:
# TRUSTED base checkout (main) — bumpy is built and run from here.
- uses: actions/checkout@v6
with:
ref: main
persist-credentials: false
# UNTRUSTED PR head into ./pr — only READ via --cwd, never built or run.
- uses: actions/checkout@v6
- uses: actions/upload-artifact@v4
if: always() # upload even when the check fails — the comment explains why
with:
ref: ${{ github.event.pull_request.head.sha }}
path: pr
persist-credentials: false
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bun run --filter @varlock/bumpy build
- run: bun install
# bunx runs from the trusted root; bumpy reads the PR's bump files via --cwd.
- run: bunx @varlock/bumpy ci check --cwd ./pr
env:
GH_TOKEN: ${{ github.token }}
name: bumpy-comment
path: ./bumpy-comment
40 changes: 40 additions & 0 deletions .github/workflows/bumpy-comment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# 🐸 Bumpy PR comment (dogfood)
# Privileged half of the fork-comment split: posts the release-plan comment that
# bumpy-check.yaml rendered. Triggered after that workflow completes. It NEVER checks
# out or runs PR code — it builds MAIN's bumpy and posts a pre-rendered body to the PR
# it resolves from the trusted workflow_run.head_sha. A normal project would just run
# `bunx @varlock/bumpy ci comment` instead of building from source.
#
# ⚠️ DO NOT COPY THIS FILE — see the recommended setup in the docs:
# ➡️ https://bumpy.varlock.dev/blob/main/docs/github-actions.md ⬅️
name: Bumpy PR Comment

on:
workflow_run:
workflows: ['Bumpy Check']
types: [completed]

permissions:
pull-requests: write

jobs:
comment:
runs-on: ubuntu-latest
steps:
# TRUSTED: default branch (main) only — never the PR. Build our own bumpy.
- uses: actions/checkout@v7
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bun run --filter @varlock/bumpy build
- run: bun install # link the freshly-built CLI bin
# Download AFTER checkout — checkout cleans the workspace and would wipe it.
- uses: actions/download-artifact@v4
continue-on-error: true # the check may not have produced a comment
with:
name: bumpy-comment
path: ./bumpy-comment
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ github.token }}
- run: bunx @varlock/bumpy ci comment --body-file ./bumpy-comment/comment.md
env:
GH_TOKEN: ${{ github.token }}
3 changes: 2 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ jobs:
- run: git config --global user.name "CI" && git config --global user.email "ci@example.com"
- run: bun run test

# NOTE: `bumpy ci check` lives in .github/workflows/bumpy-check.yaml
# NOTE: `bumpy ci check` runs in .github/workflows/bumpy-check.yaml (pull_request),
# and the fork-PR comment is posted from .github/workflows/bumpy-comment.yaml (workflow_run).
# see ➡️ https://bumpy.varlock.dev/blob/main/docs/github-actions.md ⬅️
27 changes: 22 additions & 5 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,18 +180,35 @@ CI command for PR checks. Computes the release plan from bump files changed in t
bumpy ci check
bumpy ci check --strict
bumpy ci check --no-fail
bumpy ci check --emit-comment ./bumpy-comment
```

| Flag | Description |
| ----------- | ---------------------------------------------------------------- |
| `--comment` | Force PR comment on or off (default: auto-detect CI environment) |
| `--strict` | Fail if any changed package is not covered by a bump file |
| `--no-fail` | Warn only, never exit non-zero |
| Flag | Description |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `--comment` | Force PR comment on or off (default: auto-detect CI environment) |
| `--strict` | Fail if any changed package is not covered by a bump file |
| `--no-fail` | Warn only, never exit non-zero |
| `--emit-comment <dir>` | Also write the rendered comment to `<dir>/comment.md` for a downstream [`ci comment`](#bumpy-ci-comment) to post (the fork-comment split) |

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

**On channel and promotion PRs:** for a PR targeting a [prerelease channel](prereleases.md) branch, the comment is channel-aware — it shows the prerelease plan (`-<preid>.x` versions) and the target dist-tag rather than implying a stable release. For a **promotion PR** (a channel branch → `main`, or a graduation like `alpha` → `beta`), the check reads the cycle's already-shipped bump files from `.bumpy/<channel>/` and shows the consolidated stable plan, calling out that merging ends the prerelease cycle. (Feature PRs that _target_ a channel branch are checked against that branch, so only the PR's own new bump files count — see [`--base`](#bumpy-check) on the local `check` command for the equivalent locally.)

## `bumpy ci comment`

Posts a pre-rendered comment (from `ci check --emit-comment`) to a PR. This is the privileged half of the [fork-comment split](github-actions.md#commenting-on-fork-prs): your `pull_request` check renders the comment as an artifact, and this command — run from a `workflow_run` job — posts it.

```bash
bumpy ci comment --body-file ./bumpy-comment/comment.md
```

| Flag | Description |
| -------------------- | ------------------------------------------------------------------ |
| `--body-file <path>` | Path to the rendered comment body (required) |
| `--pr <number>` | Target PR number (default: resolved from the `workflow_run` event) |

It needs no checkout and no bumpy project — it only posts. Under `workflow_run` it resolves the target PR from the **trusted** event (`head_sha`), never from the artifact, and treats the body as untrusted text. A missing or empty body file is a no-op. Requires `GH_TOKEN`.

## `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.
Expand Down
Loading
Loading