feat: adopt role-based branching strategy (ADR-013)

release/3.x -> main, release/4.x -> next, master -> archive/v2-legacy
(retired, was byte-identical to release/2.x). Branch identity is now
role-based, not version-numbered -- main and next are fixed names
that never get renamed at a major-version cutover; release/N.x is
reserved exclusively for already-superseded majors, created only at
the moment they're archived.

This directly fixes the structural cause of the bug found 2026-08-30:
build.yml hardcoded literal branch-name comparisons for the
testing/beta channel, and ADR-006's original "master -> beta channel"
rule was never superseded when release/3.x took over as the active
branch, leaving master as a silent, stale duplicate of release/2.x
that CI still treated as a legitimate publish source. Rewrote the
version-resolution logic to match roles instead: refs/heads/main,
refs/heads/next, and a refs/heads/release/*.x pattern that auto-
catches any future archived major with zero code changes needed.
Also tightened the push/PR triggers from a bare wildcard to an
explicit allowlist, and switched the release-notes CHANGELOG link to
a tag-relative permalink instead of a floating branch reference.

Research (DEP-14, openedx/frontend-base #273, semantic-release's
branch-pattern config) is cited in ADR-013; the openedx precedent in
particular fixed this identical bug the same way.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adams
2026-08-30 09:43:33 -04:00
co-authored by Claude Sonnet 5
parent 687bdd8f7f
commit 8a4750378c
9 changed files with 240 additions and 37 deletions
+23 -14
View File
@@ -2,10 +2,15 @@ name: CI / Build / Publish
on:
push:
branches: ["**"]
# main = current stable major (fixed name, never renamed at a version
# cutover). next = the in-progress next major, pre-cutover (also fixed).
# release/*.x = archived, already-superseded majors (e.g. release/2.x) --
# matched by pattern so a newly-archived major needs no workflow edit.
# See ADR-013.
branches: [main, next, "release/*.x"]
tags: ["v*.*.*"]
pull_request:
branches: [master, "release/3.x"]
branches: [main, next, "release/*.x"]
env:
PACKAGE_NAME: truenas-proxmox
@@ -94,11 +99,14 @@ jobs:
fetch-depth: 0
# ── Version resolution ─────────────────────────────────────────────────
# Version strategy:
# Tagged release (v3.x.x) → 3.x.x-1 (stable channel)
# release/3.x branch → <ver>~beta+<sha> (testing channel)
# master branch → <ver>~beta+<sha> (testing channel)
# release/* branches → <ver>~alpha+<sha> (development)
# Version strategy (see ADR-013 -- branch identity is role-based, not
# version-numbered, specifically so this logic never needs editing at a
# major-version cutover again):
# Tagged release (vX.Y.Z) → X.Y.Z-1 (stable channel)
# main (current stable) → <ver>~beta+<sha> (testing channel)
# next (in-progress next major) → <ver>~alpha+<sha> (development)
# release/*.x (archived, superseded majors, e.g. release/2.x)
# → <ver>~alpha+<sha> (development)
# everything else / PRs → <ver>~dev+<sha> (no publish)
#
# Tilde (~) sorts BELOW the base version in dpkg, so pre-release builds
@@ -123,12 +131,12 @@ jobs:
echo "::warning::Tag version (${REF#refs/tags/v}) does not match \$VERSION in TrueNAS.pm ($BASE_VERSION)"
fi
elif [[ "$REF" == refs/heads/master || "$REF" == refs/heads/release/3.x ]]; then
elif [[ "$REF" == "refs/heads/main" ]]; then
VERSION="${BASE_VERSION}~beta+${SHORT_SHA}"
CHANNEL="testing"
CLOUDSMITH_REPO="truenas-proxmox-testing"
elif [[ "$REF" == refs/heads/release/* ]]; then
elif [[ "$REF" == "refs/heads/next" || "$REF" =~ ^refs/heads/release/.+\.x$ ]]; then
VERSION="${BASE_VERSION}~alpha+${SHORT_SHA}"
CHANNEL="development"
CLOUDSMITH_REPO="truenas-proxmox-snapshots"
@@ -474,12 +482,13 @@ jobs:
git push
- name: Publish to GitHub Pages testing dist
# Only real release/3.x / master beta builds go here. "development"
# channel (other release/* branches, e.g. release/4.x) must NOT land
# in this dist — it's shared/public, and this step does `rm -rf
# Only real "main" beta builds go here (see ADR-013). "development"
# channel (next, or an archived release/*.x branch) must NOT land in
# this dist — it's shared/public, and this step does `rm -rf
# pool/testing` before copying in the new build, which would silently
# overwrite the real testing dist with an unrelated branch's alpha
# build (confirmed happening 2026-08-30 when release/4.x was created).
# build (confirmed happening 2026-08-30 when the old release/4.x
# branch, since renamed to "next", was created).
# No GitHub Pages publish target exists yet for "development" — it
# just builds/scans/uploads as a workflow artifact until one is added.
if: needs.build.outputs.channel == 'testing'
@@ -596,4 +605,4 @@ jobs:
See [README → Installation](https://github.com/TheGrandWazoo/truenas-proxmox#installation).
### Changes
See [CHANGELOG.md](https://github.com/TheGrandWazoo/truenas-proxmox/blob/release/3.x/CHANGELOG.md).
See [CHANGELOG.md](https://github.com/TheGrandWazoo/truenas-proxmox/blob/${{ github.ref_name }}/CHANGELOG.md).