bread-ecosystem/docs/release-channels.md
Breadway 4ac54c610d
All checks were successful
dev bread-theme / build (push) Successful in 13s
dev bakery / build (push) Successful in 1m2s
bakery: add stable/beta/dev build tracks
Adds a track concept to bakery (separate from the existing bakery/pacman
distribution channel): stable (unchanged tag-triggered releases), beta
(deliberate beta-v* tag promotion), and dev (published on every push to
dev). Each track gets its own signed index + artifact tree under
dl.breadway.dev so stable's paths and existing installs are untouched.

- bakery: new Track type, a global track preference in installed.json
  (defaults to stable via serde, no migration needed), `bakery track
  show`/`set`, a BAKERY_INDEX_BASE_URL override for testing, and a real
  semver comparison in `update` (was a plain string-equality check before).
  ANSI-colored/aligned CLI output (TTY + NO_COLOR aware).
- gen-index.sh: TRACK env var selects which subtree to read/write.
- CI: dev-bakery.yml/beta-bakery.yml/dev-bread-theme.yml/beta-bread-theme.yml
  publish those two products on the new tracks; dev/beta skip the GitHub
  Release upload step (no per-commit release spam).
- docs/release-channels.md documents the three-track policy.
2026-07-22 09:19:31 +08:00

7.8 KiB

Release channel policy

There are two independent distribution channels in the bread ecosystem, plus a third "neither" state for repos that aren't distributed yet. Every repo under Breadway/ should sit in exactly one of these three buckets, and its .forgejo/workflows/ directory + packaging metadata should match that bucket exactly — no more files, no fewer.

The two channels

bakery channel (bakery install <name>, curl .../get | sh, or a raw binary download from dl.breadway.dev / the GitHub release page). A repo is on this channel if and only if all of the following are true:

  1. It has a bakery.toml at the root (or, for a multi-product repo like bread-ecosystem, one per product directory).
  2. It has an entry in bread-ecosystem's registry/bread-ecosystem.toml. scripts/gen-index.sh only ever looks at repos listed there — a bakery.toml that isn't backed by a registry entry is inert.
  3. It has a .forgejo/workflows/release.yml (or a product-specific name like release-bread-theme.yml / release-bakery.yml for multi-product repos) that builds the binary, drops it under /srv/breadway-dl/<name>/, copies bakery.toml alongside it, regenerates index.json via bread-ecosystem/scripts/gen-index.sh, and uploads the same artifacts to a GitHub release as a fallback mirror.

All three must be present together. Two out of three is a bug, not a partial rollout — either finish the third piece or remove the other two.

pacman channel (pacman -S <name> from the self-hosted [breadway] repo, built via AUR-style PKGBUILDs). A repo is on this channel if and only if:

  1. It has a PKGBUILD under packaging/ (either packaging/PKGBUILD or packaging/arch/PKGBUILD — both patterns exist in the wild, pick whichever a sibling repo of the same shape already uses).
  2. It has a .forgejo/workflows/package.yml that builds the package in an archlinux:latest container and curl -X PUTs the resulting .pkg.tar.zst to https://git.breadway.dev/api/packages/Breadway/arch/os.

A repo can be on both channels (most GUI/daemon apps are — see breadbar, breadbox, breadcrumbs, bread, breadpad, breadpaper), bakery only (breadclip, breadmon, breadsearch, breadshot, bread-theme, bakery itself), pacman only (breadlock, breadhelp — both are OS-integration pieces where package-manager rigor matters more than a curl-script), or neither (dev-only / not yet released; no bakery.toml, no PKGBUILD, no release or package workflow — just the repo itself, e.g. breadarr today).

bos is a fourth, deliberately special case: it ships as an ISO, not a binary, via its own release-iso.yml. It is never on either channel and should never carry a bakery.toml or PKGBUILD.

Build tracks (stable/beta/dev) — orthogonal to channels

Within the bakery channel only, a repo can additionally publish up to three tracks: stable (the existing tag-triggered v* flow, unchanged), beta (a deliberate promotion triggered by a beta-v* tag), and dev (published automatically on every push to the dev branch). Don't confuse "track" with "channel" above — channel is how a binary reaches a user (bakery vs. pacman); track is which build of a bakery-channel package they get.

Each track lives in its own subtree so they never collide:

Track Index URL Artifact root Trigger
stable dl.breadway.dev/index.json /srv/breadway-dl/<pkg>/<ver>/ push tag v*
beta dl.breadway.dev/beta/index.json /srv/breadway-dl/beta/<pkg>/<ver>/ push tag beta-v*
dev dl.breadway.dev/dev/index.json /srv/breadway-dl/dev/<pkg>/<ver>/ push to branch dev

scripts/gen-index.sh takes a TRACK env var (default stable) to select which subtree it reads/writes — every existing stable release workflow needs zero changes. Dev/beta builds skip the GitHub Release upload step entirely (no release-per-commit spam for dev, and beta doesn't need a GitHub mirror either) — dl.breadway.dev is their only distribution point.

Adding beta/dev to a bakery-channel repo: copy dev-bakery.yml / beta-bakery.yml (or bread's dev-release.yml / beta-release.yml if the repo isn't part of this monorepo) from bread-ecosystem/bread, and swap the repo/binary names the same way the checklist below describes for release.yml. Not every bakery-channel repo needs beta/dev on day one — gen-index.sh silently skips any product with no release dir under a given track's tree, same as it already does for an unreleased product on stable.

Client side: bakery track show / bakery track set <stable|beta|dev> remembers a global track preference (~/.local/state/bakery/installed.json) and validates the target track's index is reachable and signed before switching — it never auto-reinstalls on switch, run bakery update --all afterwards.

mirror.yml is not part of this policy

Every repo previously carried its own .forgejo/workflows/mirror.yml doing a git clone --mirror + push to GitHub with a per-repo MIRROR_TOKEN secret. That pattern is being replaced ecosystem-wide by Forgejo's native Push Mirror feature, provisioned centrally by bread-ecosystem/scripts/setup-push-mirrors.sh against the live repo list — see that script and scripts/cleanup-old-mirror-workflows.sh. Once the migration is confirmed working, no repo should have a mirror.yml and this document doesn't require one. Don't add mirror.yml to a repo that's missing it; that gap is intentional and about to be moot everywhere.

Checklist for adding a repo to a channel

  • Bakery: write bakery.toml, add a [[products]] entry to bread-ecosystem/registry/bread-ecosystem.toml, copy a sibling's release.yml (prefer one with the same shape: single binary vs. binary + systemd service — compare against bread/release.yml if there's a service to install, breadmon/release.yml if not) and swap the repo name / binary name / PKG_DIR.
  • Pacman: write packaging/PKGBUILD (or packaging/arch/PKGBUILD), copy a sibling's package.yml and swap the repo/package name and system_depspacman -Syu package list.
  • Never add either file type "just in case." An unused bakery.toml or PKGBUILD is exactly the kind of drift this document exists to prevent (see the breadlock/breadarr/bos-settings history in the audit that produced this doc — two of those had a stray bakery.toml nothing served, one was missing the registry entry + release.yml that would have made an existing bakery.toml real).

Current state (as of this pass)

Repo bakery pacman tracks notes
bread-ecosystem (bakery product) yes yes stable, beta, dev release-bakery.yml recovered from a dead .github/workflows/release.yml that referenced a hestia self-hosted runner GitHub never had registered
bread-ecosystem (bread-theme product) yes no stable, beta, dev
bread yes yes stable, beta, dev pilot repo for the beta/dev track rollout
breadbar, breadbox, breadcrumbs, breadpad, breadpaper yes yes stable only complete, used as templates; not yet rolled out to beta/dev
breadclip, breadmon, breadsearch, breadshot yes no stable only complete
breadlock, breadhelp no yes n/a breadlock's bakery.toml was removed as orphaned; its README wrongly claimed it was a registry entry
bos-settings yes yes stable only was missing both the registry entry and release.yml; both added
bos no no n/a ISO-only via release-iso.yml; had an erroneous bakery.toml copy-pasted from bos-settings, removed
breadarr no no n/a had an orphaned bakery.toml with no registry entry and zero workflows; removed. Not yet assigned a channel — do that deliberately when it's ready to ship, don't infer it from a stray config file