How to ship
Shipping TurboPanel is two merges. Each repository does it on its own: a merge on trunk
becomes a canary, merging one pull request publishes a release candidate, and merging a second
one publishes the release. Nothing is rebuilt along the way — the release candidate and the
release are the canary's exact bytes, re-named and re-signed.
This page is for maintainers. The channels themselves are described under Canary environment.
The whole path
| Step | Who | Result |
|---|---|---|
Squash-merge a change into trunk | Anyone with a green ci-ok | A canary x.y.z-canary.N is built and published |
Merge "Release Candidate x.y.z-rc.N" (trunk → staging) | A maintainer | vx.y.z-rc.N is published from that commit's canary; staging moves; "Release x.y.z" opens |
Merge "Release x.y.z" (staging → live) and approve the release environment | A maintainer | vx.y.z becomes the latest release; live moves; the next canary is x.y.z+1 by itself |
The pull requests are opened and refreshed by a bot (the TurboPanel Release App), so their checks run. You never run a workflow by hand for a normal release.
1. Publish a release candidate
- Open the pull request titled Release Candidate x.y.z-rc.N. The number after
rc.is the next one for that version: one more than the highest candidate that already exists. - Wait for
ci-ok, then merge it with a merge commit.stagingtakes merge commits only. - A workflow takes the canary that was built from the merged commit and publishes it as
vx.y.z-rc.N— no approval click. The Release x.y.z pull request opens (or refreshes).
If something is wrong with a candidate, fix it on trunk. The next candidate pull request appears
after the next green build, and merging it publishes rc.N+1. The version number is never burned: a
candidate is replaced, not abandoned.
2. Ship the release
- Open Release x.y.z. The list is everything since the last release.
- Wait for
ci-ok, then merge it with a merge commit.livetakes merge commits only. - A workflow takes the newest candidate of that version and publishes it as
vx.y.z, marks it the latest release and moveslive. It pauses for your approval on thereleaseenvironment; approve it on the run page. That approval stays until the first release has gone through this exact path end to end; the plan is to drop it afterwards, so that merging Release x.y.z is the only act.
Nothing else opens: the next canary is the next patch by itself.
The installer and the update system follow GitHub's latest release, so the release is what a plain install gets from that moment.
3. The next number
Version numbers come from git tags, not from a file, so no pull request moves them. Once
vx.y.z is released, the next canary is x.y.z+1-canary.1, and the canary number starts again
at 1 for every new version. The build writes that number into the binary (it reports plain
x.y.z); the channel and the canary or candidate number live in the signed manifest.
Repositories ship independently
The daemon (turbopaneld), the control plane (turbopanel), the web app (ui) and the
website each have their own version and their own two merges. A daemon-only or a web-app-only
release is normal: no release waits on a matching release in another repository. The website
ships no binary, so its candidates and releases are notes-only tags on a commit.
Starting a minor or a major
A patch needs nothing. A minor (x.y.0) or a major (x.0.0; the first is 1.0.0) is
the one deliberate step: run Start Next Version in the turbopaneld repository (Actions →
Start Next Version → Run workflow, pick minor or major). Only people with write access to
that repository can run it. Tick dry-run first to see what each repository would get.
This button is the only way to start a minor or a major. There is no label on a pull request that bumps the version, and no "Start x.y.z" pull request to merge.
It pushes a start/vx.y.0 tag at the head of trunk in turbopaneld, turbopanel, ui and
the website, each one the next minor (or major) after that repository's own newest release, and
re-runs each repository's trunk build. When those builds finish (about 25 minutes for the control
plane), the canaries and the Release Candidate pull requests carry the new number. Running it
twice is harmless: a repository already on that version is skipped.
After a start, every release of that repository carries the new number, a hotfix included, so
start a minor only when everything on trunk may ship as it. A candidate that is already on
staging still ships under its own number.
When something goes wrong
| What you see | What to do |
|---|---|
The candidate pull request shows a failed ci-ok | Fix it on trunk; the pull request refreshes on the next green build |
| The candidate run says it is waiting for a canary | The merged commit's canary is still building — the run waits up to 45 minutes. If a newer merge superseded it, re-run the Publish Release Candidate workflow (Run workflow, the commit to tag) |
| The release run is waiting | Approve the release environment on the run page |
| The automatic path cannot run at all | Use the Promote workflow in that repository (to=rc with a canary, then to=release with the candidate tag). It is a break-glass form, not the normal path |
| A candidate was published from the wrong commit | Merge the fix and publish the next candidate; a published candidate is not edited |
Who needs what
- Merging to
trunk, and tostagingandlive, is pull request only — squash ontrunk, merge commits only onstagingandlive. The one required check isci-ok. - Tags and the
staging/livemoves are made by the TurboPanel Release App, not by a person. - Approving the
releaseenvironment is a maintainer action. The first candidate merge needs no approval.
Related
- Canary environment — channels, canary builds and version numbers
- Upgrade and rollback — how a host follows a channel
- Compatibility — which control plane and daemon builds work together
Last updated on