docs: cover the two release-onboarding footguns
cb249bf92372372f61e3949d7b277ca3c2764fc0
humdrum <me@humdrum.me> · 2026-07-08 08:25
parent b899af00
docs: cover the two release-onboarding footguns Two failure modes bit a real new-repo release and neither was documented: 1. The webhook is required and separate from .custard.yaml. Adding the config but not registering the branch_tag_create webhook makes the tag push publish nothing, silently — custard release still prints '✓ released' because it only tags+pushes and can't see the webhook. 2. custard release always runs git tag, so a repo must be in source: tag to publish via the CLI. This works even in colocated jj repos (git tag is fine there). The JUJUTSU 'tag gap' text implied pure-jj repos need bookmark mode, which steered a colocated repo into source: bookmark; the CLI then tagged but the server ignored it. Add per-repo release checklist + verify steps to MANUAL, gotcha callouts to the README auto-release section, and rewrite JUJUTSU 'The tag gap' to recommend tag mode for colocated repos and warn against bookmark + CLI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 files changed
README.md +10 −0
@@ -145,6 +145,16 @@ The tag (must be semver `vX.Y.Z`) fires the webhook → custard verifies the HMAC signature,
archives the tag, writes the tarball, and pushes an updated formula to the tap. `scripts/brew-release.sh`
remains as a manual fallback.
+> **Two easy-to-miss gotchas on a new repo:**
+> 1. The webhook is **required and separate** from `.custard.yaml`. Adding the config but forgetting
+> `repo webhook create` means the tag pushes and nothing publishes — with no error. Confirm with
+> `ssh soft repo webhook list <repo>`, and after the first release check `ssh soft repo tree
+> homebrew-tap main Formula` for `<repo>.rb`.
+> 2. **`custard release` always tags**, so a repo must be in the default `source: tag` to publish via
+> the CLI (this works even in colocated jj repos — `git tag` is fine there). `source: bookmark` is
+> only for releasing by hand-pushing a `release/vX.Y.Z` bookmark; combined with `custard release`
+> it tags but publishes nothing. See [docs/JUJUTSU.md](docs/JUJUTSU.md).
+
## Deploy & release CLI
The same `custard` binary is also a local client for shipping (the droplet runs `custard serve`;
docs/JUJUTSU.md +18 −6
@@ -44,13 +44,25 @@ are never transmitted over git push — so custard never sees them and has no way to display them.
## The tag gap
-jj cannot create or move annotated git tags. This matters because custard's Homebrew release
-pipeline is triggered when a tag is pushed (via a Soft Serve webhook), and the version pill on a
-repo's page normally reads from the highest semver tag.
+jj's *native* commands cannot create or move annotated git tags. This matters because custard's
+Homebrew release pipeline is triggered when a tag is pushed (via a Soft Serve webhook), and the
+version pill on a repo's page normally reads from the highest semver tag.
-For a pure-jj repo the fix is **bookmark mode**: instead of tagging a commit to publish a release,
-you create or move a `release/vX.Y.Z` bookmark (a plain git branch) to the commit you want to
-ship, then push it. custard detects the bookmark push and treats it as a release.
+**Most jj repos here don't hit this gap.** If your repo is **colocated** (a `.git` alongside `.jj` —
+the default `jj git init --colocate` layout), plain `git` still works in it, so the
+`custard release vX.Y.Z` CLI — which runs `git tag` + `git push` — releases exactly like it does in a
+git repo. **Stay in the default `source: tag`.** This is the recommended path; reach for bookmark
+mode only if you have a reason not to run `git tag` at all.
+
+Bookmark mode is the fix for the case where you *won't* touch git tags — a non-colocated jj repo, or
+a workflow that releases purely through jj. Instead of tagging, you create or move a `release/vX.Y.Z`
+bookmark (a plain git branch) to the commit you want to ship, then push it; custard detects the
+bookmark push and treats it as a release.
+
+> **Don't cross the streams.** `custard release` *always tags*, regardless of `source`. In a
+> `source: bookmark` repo it will tag and push successfully and print `✓ released` — but the server
+> ignores tag pushes in bookmark mode, so nothing publishes. Pick one: **tag mode + `custard release`**,
+> or **bookmark mode + `jj bookmark set release/… && jj git push`**. Never bookmark mode + the CLI.
Tag-based repos are unaffected — bookmark mode is opt-in.
docs/MANUAL.md +17 −1
@@ -102,10 +102,13 @@ `.custard.yaml`:
```yaml
brew: { enabled: true, package: "." } # or ./cmd/<name>
```
-One-time per repo, register the webhook (secret = your `WEBHOOK_SECRET`):
+**Two things are required per repo — `.custard.yaml` alone publishes nothing.** The tag push
+triggers a release only if the repo also has the webhook registered. Register it once (secret =
+your `WEBHOOK_SECRET`):
```sh
ssh soft repo webhook create <name> https://your-host/hooks/release \
-e branch_tag_create -c json -s "$WEBHOOK_SECRET"
+ssh soft repo webhook list <name> # confirm it exists before releasing
```
Release + install:
```sh
@@ -114,6 +117,19 @@ brew tap you/tap https://your-host/git/homebrew-tap.git
brew trust you/tap # newer Homebrew gates third-party taps
brew install <name> ; brew upgrade <name>
```
+
+> **`custard release` always tags — keep the repo in `source: tag` (the default).** The CLI runs
+> plain `git tag` + `git push`, which works even in a colocated jj repo. A repo in `source: bookmark`
+> ignores tag pushes, so `custard release` there tags successfully but publishes nothing. Use bookmark
+> mode only if you release by pushing a `release/vX.Y.Z` bookmark by hand (see [JUJUTSU.md](JUJUTSU.md)).
+
+> **The CLI's `✓ released` means "tag pushed," not "formula published."** It can't see whether the
+> webhook fired. After a *first* release (or any onboarding change), verify the tap actually updated:
+> ```sh
+> ssh soft repo tree homebrew-tap main Formula # is <name>.rb there?
+> ssh soft repo webhook deliveries list <name> 5 # did the delivery succeed (✅)?
+> ```
+> Empty/missing formula with a pushed tag = missing webhook or wrong `source` mode.
## Updating the forge