Release Workflow
Version 1.6.9 | Updated: September 04, 2026
Release Workflow
Status: agreed target model (DEV-1872, 2026-07-23). Trunk-based. The tooling (
misc/release.sh) andCLAUDE.mdstill describe the previous version-branch-development flow and must be updated to match — see Tooling to update.
Branching model
-
main— the trunk. Always releasable, the single source of truth. Every feature and every fix lands here first (directly, or by cherry-pick from a release line). Nothing is “done” until it is onmain. -
Feature branches — cut from
main, namedfeature/<DEV-xxxx>-<slug>, merged back tomainvia PR. A feature may add or change documentation; its docs build with the branch (preview) and land inmain’s docs on merge. -
Version / release branches (e.g.
1.6.8) — cut frommainfor a release. They receive stabilization and hotfixes only, not net-new feature work. QA installs a specific line with--branch 1.6.8. -
Older versions — a fix or feature needed on an older released line is authored on that line, then cherry-picked to
mainand forward to any newer still-active lines. Never merge an older branch forward wholesale — a full merge drags stale code onto the newer line.
Workflow diagram
gitGraph commit branch feature commit commit checkout main merge feature commit branch release commit id: "stabilize" commit id: "v1.6.8" tag: "1.6.8" commit id: "hotfix" checkout main cherry-pick id: "hotfix" commit
-
featureis cut frommainand merged back via PR. -
release(a version branch, e.g.1.6.8) is cut frommain, takes stabilization + hotfixes only, and is tagged for the release. -
a hotfix made on
releaseis cherry-picked back tomain(and forward to any newer active line) — never merged up. -
backports for an older line follow the same shape: authored on that line, cherry-picked to
mainand to newer lines. -
docs follow the branch:
main→ latest/dev, eachrelease→/<version>/, a feature branch → a preview build for its new/changed docs.
Rules
-
Cherry-pick, don’t merge up. A fix reaches every active line by cherry-pick, never by merging an older branch into a newer one.
-
Backport vs. new feature. New features branch from
main. Backports are authored where they are needed and cherry-picked tomainand newer lines. -
Keep few live version branches. Only the next release plus genuinely customer-supported lines stay active; older versions are frozen (hotfix-only) per the support window. Fewer live lines = fewer forward-ports.
-
A fix must reach
main. A version branch cannot be released or closed while any of its fixes are missing frommain— enforced by CI; forward-port PRs are opened automatically. -
Hotfix SLA. Security / critical fixes propagate to all active customer lines and
mainwithin the agreed window.
Documentation
-
Each version publishes its own versioned docs (Antora,
docs-friendly-tech.pages.dev/grafana-monitoring/<version>/). -
mainpublishes the latest / dev docs. -
Feature branches that add or change docs get a docs build (preview) so the new content is reviewable before merge. On merge the docs go to
main’s docs, and into a version’s docs when a release branch carries the change. -
VERSIONanddocs/antora.ymlare per-branch and kept in sync (pre-commit version check).
Interactive installer gate
The install command in our own docs is curl … | sudo bash -s, and the
installer draws a menu over it. That path has broken in ways no unit test saw:
a black screen on MobaXterm under sudo, and a run that hung forever waiting
for a keypress on a /dev/tty nobody was watching.
Before tagging a release, work through
interactive-release-checklist.md. It has
four parts and all four are required:
-
The automated Phase 1 suite —
bash misc/testing/interactive/run-phase1.sh, mirrored in CI by theinteractivejob in.github/workflows/sandbox-tests.yml. Compare against the absolute counts recorded in the checklist, not only againstFAILED STAGES: 0: every gate asserts “at or above a floor”, which a suite that quietly shrank still clears. -
Mutation coverage —
bash misc/testing/scripts/check-red-verify.shplus a scopedred-verify.shsweep. A suite where every test passes proves nothing until the tests have been watched to fail against the defects they guard; that is the whole reason this phase exists. -
A manual client matrix — OpenSSH, Windows Terminal, MobaXterm and PuTTY / a web console. The automated suites run on terminals we control and cannot speak for the clients customers actually use.
-
Acknowledgement of the known open defect: Ctrl-C at the config menu does not restore the terminal. Phase 1 reproduces it and neither state fails CI, so a release must not be signed off assuming it is fixed.
Three prerequisites are easy to miss and silent when absent, so section 0 of the
checklist covers them: the pre-commit gate does not exist until
bash misc/install-hooks.sh --yes has been run (once per clone — in a worktree
the hook lives in the shared git directory and covers every worktree); tmux
must be installed on every runner carrying the ft-ci label, because the
interactive job’s rendering suite refuses to skip under CI; and a Docker
daemon must be running on the machine you sign off from, unless promtool is
installed locally. Without either, validate-all’s Test 41 fails with
failed to connect to the docker API, and step 2’s red-verify.sh sweeps abort
with exit 65 and the baseline run is not a usable reference — a red baseline,
not a broken gate.
The agent-facing version of the same rule — which test to update when you touch
TTY detection, /dev/tty, screen/cursor handling or the sourced UI — is in
AGENTS.md at the repository root.
Releasing
./misc/release.sh # patch bump (1.6.8 → 1.6.9)
./misc/release.sh minor # minor bump (1.6.8 → 1.7.0)
./misc/release.sh major # major bump (1.6.8 → 2.0.0)
The bump names the next development branch, not the release: the version
being released is whatever VERSION already says.
The released branch is kept. It used to be deleted once merged and tagged,
on the reasoning that the line was finished. It is not: the branch is what QA
installs with --branch, what a customer’s stand is pinned to, and what a
support question three months later is about. A tag answers “what was
released”; the branch answers “what is a stand running”. Pass --delete-branch
to opt into the old behaviour:
./misc/release.sh minor --delete-branch
Requirements
-
No uncommitted changes.
-
GitHub CLI (
gh) installed and authenticated.
The script’s current behaviour still assumes the previous model (see below). Treat this section as the intended release entry point; the script itself is pending adaptation.
Tooling to update
Follow-ups to make the tooling match this model (DEV-1872 automation; ties into DEV-1916 CI/CD, which adds build → scan → publish → deploy stages the flow must accommodate):
-
misc/release.sh— today it must run from a version branch, merges the branch intomain, deletes it, creates the next version branch, and continues development there (the version-branch-dev model). Under trunk-based it should instead cut/tag a release branch frommainand leave development onmain. Needs rework. -
CLAUDE.md— the note “Development happens on version branches;mainonly receives merges at release time” must be updated to the trunk-based model. -
CI — add the “fix is on
main” gate before a version branch can be released, plus automatic forward-port PRs from an older line to newer ones. -
Docs pipeline — add a per-feature-branch docs preview build so new or changed documentation is reviewable before merge.
Bootstrap commands
-
… | bash -s — <ip>— latest release frommain -
… | bash -s — --branch 1.6.8 <ip>— specific line (dev / release branch) -
… | bash -s — --version-list— show all versions