## Summary - document `Prepare Desktop Release` as the canonical desktop release entry point - describe the frozen candidate, exact-head approval, and true merge-commit contract - document all platform outputs and complete release App/signing configuration - link the release runbook from the README - allow stable reruns to repair the rolling updater manifest after the versioned release has already published ## Release blocker The live repository cannot currently complete this flow: repository settings disable merge commits and the `main` ruleset allows only squash, while `scripts/verify-desktop-release-merge.sh` requires a two-parent merge whose second parent is the approved candidate. Those settings must allow merge commits before a desktop release PR is merged. ## Validation - `bash scripts/test-desktop-release-candidate.sh` - `bash scripts/test-release-ref-contract.sh` - `git diff --check` - verified live repository merge settings, `main` ruleset, release tag ruleset, Actions variable names, and secret names with GitHub API - independent review by Princess Donut; incorporated all findings, including the rolling-manifest retry gap and unsigned Windows labeling Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
15 KiB
Releasing Buzz
Buzz has three independent release lanes. Desktop and relay use release PRs.
Mobile uses immutable release-candidate tags cut directly from remote main:
| Lane | Entry point | Artifact |
|---|---|---|
| Desktop | Prepare Desktop Release |
Packaged desktop app (signed/notarized macOS, unsigned Windows, and Linux) |
| Relay | just release-relay |
ghcr.io/block/buzz container image |
| Mobile | scripts/mobile-release.sh candidate X.Y.Z |
Exact mobile-vX.Y.Z-rc.N source identity |
The lanes version independently. Desktop reads its manifests, relay reads its
crate manifest, and mobile derives both source and marketing version from the
exact candidate tag. The mobile handoff to the private buzz-releases pipeline
remains manual because OSS CI cannot trigger private CI.
Quick Start
Desktop releases are prepared from the current remote main by GitHub Actions:
gh workflow run prepare-desktop-release.yml \
--repo block/buzz \
--ref main \
-f version=0.5.3
The equivalent GitHub UI path is Actions → Prepare Desktop Release → Run
workflow, select main, enter the version without a v prefix, and run it.
The local just release-desktop <version> recipe uses the same candidate script,
but the Actions workflow is the canonical operator path because it runs with the
release App identity and does not depend on an operator checkout.
# Relay release
just release-relay
just release-relay 0.4.0
# Publish the next mobile candidate from the exact current remote main commit
scripts/mobile-release.sh candidate 0.5.0
Desktop uses an immutable generated candidate PR; relay continues using its
metadata PR. Mobile does not. Each mobile-vX.Y.Z-rc.N tag is an immutable
candidate and the artifact of record.
There is no mobile release branch, stable mobile tag alias, finalization step,
or mobile GitHub Release.
How It Works
Desktop
- Run Prepare Desktop Release with an explicit version. Automation fetches
the current
origin/main, regeneratesversion-bump/<version>as one deterministic candidate commit, records the frozen base and proposeddesktop-v<version>tag in.release/desktop-candidate.json, updates every desktop manifest and lockfile, writes a full-SHA changelog, and opens or updates the PR. - Review the recorded base and candidate SHA, the complete changelog, and CI. The candidate must receive an approval on its exact current head. Any regeneration changes that head and therefore requires a fresh approval.
- Merge with Create a merge commit. Squash and rebase are invalid for
desktop release PRs. Repository settings and the
mainruleset must allow merge commits for this option to exist. auto-tag-on-release-pr-mergeverifies the two-parent merge, exact candidate approval, and every required check, then tags the reviewed candidate—not the merge commit—asdesktop-v<version>.- The tag triggers
release.yml. It builds and stages Apple Silicon and Intel macOS, Windows, and Linux artifacts; publishes the versioned release only after the complete set succeeds; then updates the rolling updater manifest last for stable versions. A failed platform leaves no partially published versioned release.
Relay
just release-relayruns locally onmain, creates or updates arelay-release/<version>PR, bumpscrates/buzz-relay/Cargo.toml, regeneratesCargo.lock, and updates the relay changelog.- Merge the PR.
auto-tag-on-release-pr-mergepushesrelay-v<version>. - The tag triggers
docker.yml. Stable releases update the version aliases andlatest; prereleases do not. Each release also publishes an optimized, symbol-bearing image under matchingdebug-tags (for example,debug-0.3.0anddebug-latest) for native profiling. The ordinary tags remain stripped and are the default for deployments that do not need it.
Every push to main continues to publish the rolling relay :main and
:sha-<7> tags, plus matching :debug-main and :debug-sha-<7> variants.
Mobile
- Publish a candidate. From a clean checkout whose
originis the canonicalblock/buzzrepository, runscripts/mobile-release.sh candidate X.Y.Z. The script resolves and fetches the exact currentorigin/maincommit, derives the next number from exact remote tags for that marketing version, and publishes an annotatedmobile-vX.Y.Z-rc.Ntag there through the dedicatedbuzz-release-botGitHub App. It never uses the operator's checked-out commit and never moves an existing candidate. - Build the exact tag. Enter the candidate tag as
mobile_refin the private Buzz mobile Buildkite pipeline. OSS CI deliberately cannot trigger that private pipeline. The tag supplies both source commit and release version. Flutter receives clean marketing versionX.Y.Z; Buildkite's monotonically increasing build number supplies the platform build number. - Promote tested artifacts. Promote the already-built signed artifact for each platform through its store workflow. Record the exact tag with the build or rollout record. No source ref is changed and no final build is cut.
The iOS and Android artifacts for one marketing version may come from different
RC tags. For example, iOS can ship mobile-v0.5.0-rc.2 while Android ships
mobile-v0.5.0-rc.3. Each platform's exact candidate tag is its source record.
There is intentionally no single selected or final candidate for the marketing
version.
The simplification trades away a separate stabilization line. Unrelated commits
that reach main become part of every later candidate, and there is no retained
hotfix branch or branch-ancestry history. Add a dedicated hotfix flow later if a
release actually needs isolation from main.
mobile/pubspec.yaml keeps 0.0.0+1 only as a valid, visibly non-release
fallback for local development and validation builds. Release jobs always
inject both version fields. mobile/CHANGELOG.md is retained as historical
release data. It is not a release ledger for this flow.
Version Sources
| Lane | Release version authority |
|---|---|
| Desktop | desktop/package.json and synchronized desktop manifests |
| Relay | crates/buzz-relay/Cargo.toml |
| Mobile | Exact mobile-vX.Y.Z-rc.N remote tag |
just bump-desktop-version <version> updates the desktop manifests and
regenerates their lockfiles. just bump-relay-version <version> updates the
relay crate and regenerates Cargo.lock. Mobile has no bump recipe or
release-metadata PR.
Signed macOS Canary
Use the manual Signed macOS Canary workflow when you need an Apple Silicon
build of current main for explicit testing without publishing a release:
gh workflow run signed-macos-canary.yml --repo block/buzz --ref main
The workflow derives a -test.<run-number> version, signs and notarizes the
DMG, verifies it with Gatekeeper, and uploads it as a short-lived Actions
artifact with seven-day retention. Because this is a public repository, any
signed-in GitHub user can download that artifact while it exists; it is
unpublished, not private. The workflow has no release permissions, does not
create or move tags, and cannot update buzz-desktop-latest or latest.json.
Download the artifact from the completed run:
gh run download <run-id> --repo block/buzz --name <artifact-name>
The workflow intentionally accepts only main. Use the normal release process
for distributable builds or builds from an immutable release tag.
Release Retry
release.yml has no manual dispatch and cannot build from main or another
caller-selected ref. If a run for an existing immutable
desktop-v<version> tag fails, rerun that failed workflow from GitHub Actions
(or use gh run rerun <run-id> --failed --repo block/buzz). A stable rerun also
repairs buzz-desktop-latest/latest.json if the original run published the
versioned release but failed during that final rolling-manifest upload. Do not
recreate, move, or push the immutable tag again.
Mobile intentionally has no branch or arbitrary-ref fallback. The private Buildkite pipeline accepts only an exact candidate tag.
Internal Releases
For mobile, trigger the private Release Mobile pipeline with an exact RC tag for the platform build being cut. For desktop, use Release Desktop. See the buzz-releases README for the private pipeline contract.
What Gets Published
Desktop publishes two GitHub releases:
desktop-v<version>: the user-facing release with installers.buzz-desktop-latest: the rolling auto-updater release.
Mobile publishes only annotated mobile-vX.Y.Z-rc.N git tags. Store artifacts
and rollout records retain the exact tag they used. Mobile does not publish a
GitHub Release or a stable mobile-vX.Y.Z alias.
Platform Support
The release workflow builds two separate macOS DMGs: Apple
Silicon (darwin-aarch64, the release job) and Intel
(darwin-x86_64, the release-macos-x64 job), an unsigned Windows x64
NSIS installer (its filename includes _alpha-unsigned), and Linux .deb and
.AppImage packages. Both macOS DMGs are codesigned, notarized, and attached
to the same desktop-v<version> release. Intel users
download the _x64.dmg.
The Linux AppImage is post-processed by desktop/scripts/fix-appimage.sh,
which strips infra libraries over-bundled by linuxdeploy (they crash on
Mesa 25+ / GLib 2.88 distros; see
tauri-apps/tauri#15665)
and re-signs the artifact. As a result the AppImage relies on the
host's Wayland/GStreamer/graphics stack and requires GLib >= 2.72
(Ubuntu 22.04 or newer). The release-linux job builds inside a
ubuntu:22.04 container for broad GLIBC compatibility.
Prerequisites
- Write access to the
block/buzzGitHub repository - An
originremote whose configured URL is the canonicalblock/buzzrepository ghCLI version 2.87.0 or newer, authenticated with permission to dispatch the candidate workflow- Repository settings and the
mainruleset configured to allow merge commits; desktop release PRs cannot be squash- or rebase-merged - Release tag ruleset
14378754active fordesktop-v*andmobile-v*, with creation, update, deletion, and non-fast-forward protections andbuzz-release-botas its sole always-bypass actor - The
buzz-release-botApp credentials configured for GitHub Actions - The following GitHub Actions variables and secrets configured for the
desktop release lane:
Name Kind Purpose BUZZ_RELEASE_TAGGER_CLIENT_IDVariable GitHub App client ID used to prepare candidates and create tags BUZZ_RELEASE_TAGGER_PRIVATE_KEYSecret GitHub App private key OSX_CODESIGN_ROLESecret macOS signing role used by block/apple-codesign-actionCODESIGN_S3_BUCKETSecret macOS signing exchange bucket BUZZ_UPDATER_PUBLIC_KEYorSPROUT_UPDATER_PUBLIC_KEYSecret Tauri updater public key TAURI_SIGNING_PRIVATE_KEYSecret Tauri updater private key TAURI_SIGNING_PRIVATE_KEY_PASSWORDSecret Password for the private key
Mobile candidate publication requires workflow-dispatch access and the existing
release App because strict tag protection denies direct human creation. The App
must be installed on block/buzz, have Contents write and Metadata read, and
retain an always bypass on the immutable mobile-v* tag rules. It does not
require GitHub Releases permissions, repository Administration permission, or a
mobile release-branch ruleset. The publisher validates the App token's effective
current_user_can_bypass value rather than reading the ruleset's hidden bypass
actor list.
Troubleshooting
The release PR does not offer Create a merge commit
The immutable desktop flow cannot release until both the repository merge
settings and the main ruleset allow merge commits. Do not squash the PR: the
auto-tagger deliberately rejects a one-parent squash commit. Enable merge
commits, then merge the already-approved exact candidate head with Create a
merge commit.
Prepare Desktop Release fails before opening a PR
Check the workflow run first. Confirm BUZZ_RELEASE_TAGGER_CLIENT_ID and
BUZZ_RELEASE_TAGGER_PRIVATE_KEY are configured and that the release App can
write contents and pull requests. Rerunning the preparer regenerates the
candidate from the then-current origin/main; if its head changes, obtain a new
approval before merging.
Local just release-desktop fails with "must be on main branch"
Switch to main and pull latest before running the release recipe.
Local just release-desktop fails with "working tree is dirty"
Commit or stash your changes before running the release recipe.
New commits land after publishing a mobile candidate
Run scripts/mobile-release.sh candidate <version> again after the intended
fix reaches remote main. It publishes a new immutable RC tag at the new exact
remote commit. Continue referring to each tested or shipped platform artifact by
its own exact tag.
scripts/mobile-release.sh candidate fails because main moved during publication
The App-backed workflow may already have published the requested immutable RC
at the prior main tip before the operator command detects the race. Do not
move or delete that tag, and do not treat it as the candidate for current
main. Inspect the run URL from the command output, then rerun
scripts/mobile-release.sh candidate <version> to publish the next RC from the
new current main tip.
A mobile candidate command selects the wrong RC number
Do not retry by moving or deleting a tag. Inspect the exact remote mobile-v*
tags and resolve the unexpected state. Candidate numbers are monotonically
increasing remote identities.
A mobile candidate publication is rejected by repository rules
Confirm buzz-release-bot remains the sole always-bypass actor for the active
mobile-v* ruleset and that its Actions credentials are available. Do not grant
direct human creation or weaken update or deletion protection. Existing
candidate tags must remain immutable.
Auto-updater reports "no update available"
Verify that the buzz-desktop-latest release exists and contains a
valid latest.json. The manifest covers all four platform keys
(darwin-aarch64, darwin-x86_64, linux-x86_64,
windows-x86_64); a missing entry usually means that platform's
release job failed. Check the workflow run.