Release Workflow
- Release Workflow
- At a glance
- Branches
- Feature and bugfix workflow
- Releasing a new version
- Hotfixes for a released version
- Commits and release notes
- Changelog pages
- Which ref carries which docs version
- Our own images
- Versions:
VERSIONandBUILD - Branch protection
- Interactive installer gate
- Bootstrap commands
- Before 1.7.1
Version 1.7.1 | Updated: October 07, 2026
Release Workflow
Status: in force from 1.7.1 (DEV-3006, 2026-10-07). This repository is released by the CI/CD Manager, the same way as every other Friendly Technologies project with a dev branch (northbound-api and the rest). Releases up to and including 1.7.0 were made with
misc/release.sh; see Before 1.7.1 for what that left behind.
At a glance
feature/*, bugfix/* --(QA on the branch, then PR)--> develop
|
CI/CD Manager: Finalize Sprint
(version + changelog on develop,
PR develop -> main)
|
merge commit into
v
main ---- tag release-X.Y.Z
|
+--> release/X.Y.Z (created from main,
kept for good)
develop moves to X.Y.(Z+1)
-
developis the release candidate. It holds only work that has already been tested and that goes into the next release. -
mainholds the latest release and every release before it. The installer installsmainby default. -
release/X.Y.Zis cut frommainwhen versionX.Y.Zis released. It is the place where versionX.Y.Zlives on: the docs portal publishes theX.Y.Zdocumentation from it, and a hotfix forX.Y.Zgoes there. -
Tags:
release-X.Y.Z, on themaincommit the release was made from.
Branches
| Branch | Created from | Purpose | Lifetime |
|---|---|---|---|
|
— |
The latest release and all releases before it. Every release tag points at a commit on |
Permanent |
|
|
The release candidate: tested features and fixes for the next release. |
Permanent |
|
|
New functionality. |
Deleted after merge |
|
|
Fixes for the next release. |
Deleted after merge |
|
|
Version |
Kept for good — deleting it unpublishes that version’s docs |
|
|
A fix for an already released version. |
Deleted after merge |
Only the CI/CD Manager creates release/X.Y.Z branches. Do not push any
other branch whose name starts with release/: the docs portal publishes every
release/* branch, and two branches that carry the same version stop the whole
portal build.
Feature and bugfix workflow
-
Branch
feature/<DEV-xxxx>-<slug>orbugfix/<DEV-xxxx>-<slug>fromdevelop. -
Commit using Conventional Commits with the Jira key in the subject — see Commits and release notes.
-
QA tests the branch: install it on a test server with
bootstrap.sh --branch <your branch>. On any branch other thanmainandrelease/*the installer runs that branch’s own builds of Config UI and Trap Catcher (see Our own images), so QA needs no manual.envedit. -
After QA, open a PR into
develop. Merge it only if it goes into the next release — everything that is ondevelopwhen the release is made is released.
Releasing a new version
The release manager makes the release in the CI/CD Manager (Finalize Sprint). Nobody runs a release script.
-
Finalize Sprint. The CI/CD Manager:
-
sets
docs/antora.ymltoX.Y.Zwithoutprerelease:; -
writes the version
X.Y.Zondevelop, in one commit, into every other file that carries it:VERSION,BUILD(reset to0),docs/modules/ROOT/pages/index.adoc(:revnumber:and theVersionline), and the own-image pins inprometheus-grafana-stack/.env.exampleanddocker-compose.yml, somisc/check-versions.shpasses on it; -
writes the changelog pages for
X.Y.Zondevelop(see Changelog pages); -
opens the pull request
develop→main.
-
-
Review and merge the release PR with “Create a merge commit”. Not squash, not rebase:
mainanddevelopmust keep a shared history. Merge nothing else intodevelopwhile the release PR is open. -
After the merge the CI/CD Manager:
-
tags
release-X.Y.Zon the merge commit; -
creates
release/X.Y.Zfrom it; -
moves
developtoX.Y.(Z+1):VERSION,BUILD,index.adocanddocs/antora.ymlin one commit, thenprerelease: -devindocs/antora.yml.
-
-
The push to
mainruns the own-image builds (they publish theX.Y.Zimage tags) anddocs-pdf.yml, which uploadsmisc/hub/install.shand the PDFs to the hub.
Before the release PR is merged, work through the Interactive installer gate.
Hotfixes for a released version
-
Branch
hotfix/<DEV-xxxx>-<slug>fromrelease/X.Y.Z. -
Fix, test, and merge it into
release/X.Y.Zthrough a PR. Installs pinned with--branch release/X.Y.Zget the fix. -
Bring the same fix into
develop(cherry-pick, through a PR), so the next release carries it.
The default install is main, and a fix on release/X.Y.Z does not reach
main by itself. Customers who install the default get the fix with the next
release X.Y.(Z+1) from develop. When a fix is urgent for everybody, release
the next version through Releasing a new version
instead.
Commits and release notes
-
Conventional Commits are required.
.github/workflows/commit-lint.ymlchecks every PR intomain,developorrelease/**(misc/lib/conventional-commits.sh; merge, fixup and squash commits are exempt). -
Put the Jira key in the subject:
fix(snmp): DEV-1234 keep the privacy password when SNMPv3 is edited again. The release notes list Jira issues, and QA and customers read issues, not commits. -
Use only these types:
feat,fix,perf,docs,refactor,test,build,ci,chore,refs. Any other type (style,revert,security, …) is left out of the release notes. A security fix is afix. -
A breaking change is marked with
!:feat(installer)!: …. ABREAKING CHANGE:footer without the!is not detected.
The release notes are made by the CI/CD Manager from these commits and the
Jira tickets they name, for the commits since the previous release tag. The
full rules are in the docs portal guide Release Notes Guide (ci-cd
module).
There is no CHANGELOG.md entry, no changelog fragment and no GitHub Release
for a release made by the CI/CD Manager.
Changelog pages
The CI/CD Manager writes them on develop at Finalize Sprint, so they reach
main with the release PR:
| File | Content |
|---|---|
|
For customers: breaking changes, the Jira issues raised for a customer, images and dependencies. |
|
For QA: every Jira issue in the release, and the maintenance work. |
|
Every commit, by type. |
|
The release page, linking the three. |
|
Every release, newest first. |
|
The changelog menu, newest first. It is a separate file (the second entry under |
Do not edit these pages by hand. To correct a changelog, fix the commit message or the Jira ticket and regenerate the changelog in the CI/CD Manager.
Which ref carries which docs version
The docs portal (docs-portal antora-playbook.yml) publishes grafana from the
release/ branches (minus release/.x) plus the legacy bare 1.6.x refs.
It does not publish develop, main or tags.
-
Version
X.Y.Zis published fromrelease/X.Y.Zand from nothing else. Two refs that claim the same version stop the whole portal build — this is why only the CI/CD Manager createsrelease/*branches. -
developcarries the next version withprerelease: -devand is not published.
Our own images
alertmanager-config-ui and snmp-catcher are built by this repository’s CI
(.github/workflows/<name>.yml), not mirrored. An installed host runs the tags
in prometheus-grafana-stack/.env.example; every stack run brings the host’s
.env back to that set (sync_image_versions).
-
A release pins the release. The release commit on
developsets both pins (.env.exampleand the compose defaults) toX.Y.Z.misc/check-versions.shrefuses amainorrelease/X.Y.Zwhose pins differ fromVERSION; on other branches the two places only have to agree with each other. -
CI publishes the version tag from
mainandrelease/only. Every build is tagged<branch>and<branch>-<sha>; onmainandrelease/also withVERSION. The workflows build on a change toVERSIONor.env.example, so the merge of the release PR builds theX.Y.Zimages. Until those builds finish (a few minutes), an install ofmaincannot pull the new tags. Do not announce the release before both builds are green:gh run list --workflow alertmanager-config-ui.yml --branch main(same forsnmp-catcher.yml). -
Feature, bugfix and develop installs run their own build. On any branch other than
mainandrelease/*, the installer (ensure_mirror_pins→follow_branch_image_pins) points each own image at the branch’s tag when the registry has it, and otherwise keeps the pin. An air-gapped host keeps the pin.
Versions: VERSION and BUILD
-
VERSIONis the version of the branch. The CI/CD Manager writes it at the release (X.Y.Z) and movesdevelopto the next version after it.docs/antora.yml,index.adocand, onmain/release/*, the own-image pins must match it —misc/check-versions.shchecks that (the pre-commit hook runs it). -
BUILDis reset to0at every release.misc/version-string.shprints the runtime stringX.Y.Z-b0.0.Nthat a running deployment reports; it is not a release identity — the release identity is therelease-X.Y.Ztag.
Branch protection
-
mainanddevelop— classic branch protection: changes land by PR, withcommit-lintrequired. -
release/** — therelease-branchesruleset: changes land by PR, withcommit-lintrequired. -
The CI/CD Manager’s GitHub account is on the bypass list of all three. It commits the version and changelog to
develop, createsrelease/X.Y.Z, and movesdevelopto the next version without a PR. Nobody else pushes to these branches directly. -
docs-pdf.yml’sworkflow_dispatchinputbump_typewould push aVERSIONbump tomainasgithub-actions[bot]; branch protection blocks it, which is correct — the CI/CD Manager is the only thing that movesVERSION.
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 the release PR is merged, 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. -
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.
Bootstrap commands
-
… | bash -s — <ip>— the latest release, frommain(the default ofREPO_BRANCHinmisc/hub/install.sh, which staysmain). -
… | bash -s — --branch <ref> <ip>— a specific branch: a released version (release/X.Y.Z),develop, or a feature branch for QA. It must be a branch, not a tag: bootstrap checks it out asorigin/<ref>.misc/testing/scripts/check-doc-commands.shchecks every documented--branch <ref>againstorigin. -
… | bash -s — --version-list— show all versions.
Before 1.7.1
What the earlier process left in the repository, and what to do with it:
-
Tags. Releases up to 1.6.9 are bare
X.Y.Ztags, 1.7.0 isv1.7.0. From 1.7.1 the tag isrelease-X.Y.Z. The CI/CD Manager findsv1.7.0as the previous release, so the 1.7.1 release notes start after 1.7.0. -
release/1.7.0stays: it publishes the 1.7.0 docs. -
release/1.7.x(the LTS linemisc/release.sh tagcreated) is not used. The portal does not publish it. -
Not used for releases any more:
misc/release.sh(cut,build,tag),misc/release-notes/generate.sh,release.json,.changelogs/fragments,CHANGELOG.md,.github/workflows/changelog-check.yml(it only reacts tov*tags) and the LTS logic inbranch-sync-gate.ymlandmisc/check-versions.sh. They are removed in a separate change. -
The 1.7.0 changelog has only
external.adoc(andrelease.json), made bygenerate.sh. Releases from 1.7.1 have all three pages.
branch release/1.7.1 · commit e70021b6498caa7f94c439e9d43703e4496f41e2 · page generated October 07, 2026