From fda685e260fe93566cf38fa8ad78df4948aa5df2 Mon Sep 17 00:00:00 2001 From: cayossarian <23534755+cayossarian@users.noreply.github.com> Date: Thu, 8 Oct 2026 15:16:05 -0700 Subject: [PATCH 1/3] ci: tag the add-on image latest only from main Every build pushed :latest beside its version tag, so a build dispatched from a pre-release branch would have become what an unversioned pull gets. Only a build of main moves :latest now; every build still pushes its version tag. --- .github/workflows/build-addon.yaml | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-addon.yaml b/.github/workflows/build-addon.yaml index 7d1a5e8..d415914 100644 --- a/.github/workflows/build-addon.yaml +++ b/.github/workflows/build-addon.yaml @@ -53,6 +53,24 @@ jobs: version=$(grep '^version:' panelbench/config.yaml | sed 's/version: *"\(.*\)"/\1/') echo "version=${version}" >> "$GITHUB_OUTPUT" + # `:latest` is what an unversioned pull gets, so only main moves it. A build + # dispatched from any other ref, a pre-release branch above all, publishes its + # version tag alone. + - name: Choose image tags + id: tags + env: + IMAGE: ${{ env.REGISTRY }}/spanpanel/panelbench/${{ matrix.arch }} + VERSION: ${{ steps.version.outputs.version }} + run: | + { + echo "tags<> "$GITHUB_OUTPUT" + - name: Build and push uses: docker/build-push-action@v7 with: @@ -62,6 +80,4 @@ jobs: push: true build-args: | BUILD_FROM=${{ matrix.base }} - tags: | - ${{ env.REGISTRY }}/spanpanel/panelbench/${{ matrix.arch }}:${{ steps.version.outputs.version }} - ${{ env.REGISTRY }}/spanpanel/panelbench/${{ matrix.arch }}:latest + tags: ${{ steps.tags.outputs.tags }} From 29a2e74dad8423a87749e4d510277dd9797dd342 Mon Sep 17 00:00:00 2001 From: cayossarian <23534755+cayossarian@users.noreply.github.com> Date: Thu, 8 Oct 2026 15:17:10 -0700 Subject: [PATCH 2/3] ci: run tests, lint and spec provenance on pre-release branches Pull requests into prerelease/** branches, and pushes to them, now run the test suite and the pre-commit lint as main does, and a pull request there that touches the vendored catalogs runs the provenance check, so a pre-release line is gated as main is. --- .github/workflows/lint.yaml | 4 ++-- .github/workflows/spec-provenance.yaml | 2 +- .github/workflows/tests.yaml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 1325617..52c3987 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -2,14 +2,14 @@ name: Lint & Type Check on: pull_request: - branches: [main] + branches: [main, "prerelease/**"] # Also on push, because pull_request alone leaves `main` unwatched. The mypy hook # was broken from the moment the emitter stopped being vendored and stayed broken # across several pushes, all of them reporting green — the only workflow running on # push was the add-on image build. The breakage surfaced on the next unrelated # dependabot PR, which is a confusing place to learn about it. push: - branches: [main] + branches: [main, "prerelease/**"] jobs: lint: diff --git a/.github/workflows/spec-provenance.yaml b/.github/workflows/spec-provenance.yaml index 833c2d1..a76e145 100644 --- a/.github/workflows/spec-provenance.yaml +++ b/.github/workflows/spec-provenance.yaml @@ -10,7 +10,7 @@ name: Spec Provenance on: pull_request: - branches: [main] + branches: [main, "prerelease/**"] paths: - ".ebus-spec.json" # Where the vendored catalogs actually are. This filter named diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index f304b59..1bce3ed 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -15,9 +15,9 @@ name: Tests on: pull_request: - branches: [main] + branches: [main, "prerelease/**"] push: - branches: [main] + branches: [main, "prerelease/**"] jobs: test: From 84dcaebe5dc94034c162a364cd368e07c0865204 Mon Sep 17 00:00:00 2001 From: cayossarian <23534755+cayossarian@users.noreply.github.com> Date: Thu, 8 Oct 2026 15:53:20 -0700 Subject: [PATCH 3/3] ci: build a stable add-on version only from main An installed add-on pulls the image by its version tag, and a pre-release branch is cut while config.yaml still names the last release, so a build dispatched from it before the bump would overwrite that release's image under every installation. Off main, the build now refuses a version without a pre-release marker (aN, bN or rcN). On every ref it refuses a version that is neither X.Y.Z nor such a pre-release. --- .github/workflows/build-addon.yaml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-addon.yaml b/.github/workflows/build-addon.yaml index d415914..212ea17 100644 --- a/.github/workflows/build-addon.yaml +++ b/.github/workflows/build-addon.yaml @@ -56,12 +56,27 @@ jobs: # `:latest` is what an unversioned pull gets, so only main moves it. A build # dispatched from any other ref, a pre-release branch above all, publishes its # version tag alone. - - name: Choose image tags + # + # That version tag is what an installed add-on pulls, so only main may build a + # stable version. A pre-release branch is cut while config.yaml still names the + # last release, and a dispatch from it before the bump would overwrite that + # release's image under every installation; it is refused instead. + - name: Check the version and choose image tags id: tags env: IMAGE: ${{ env.REGISTRY }}/spanpanel/panelbench/${{ matrix.arch }} VERSION: ${{ steps.version.outputs.version }} run: | + stable='^[0-9]+\.[0-9]+\.[0-9]+$' + prerelease='^[0-9]+\.[0-9]+\.[0-9]+(a|b|rc)[0-9]+$' + if [[ ! "${VERSION}" =~ ${stable} && ! "${VERSION}" =~ ${prerelease} ]]; then + echo "::error::panelbench/config.yaml declares version '${VERSION}', which is neither X.Y.Z nor a pre-release such as X.Y.ZbN." + exit 1 + fi + if [ "${GITHUB_REF}" != "refs/heads/main" ] && [[ ! "${VERSION}" =~ ${prerelease} ]]; then + echo "::error::${GITHUB_REF} declares the stable version ${VERSION}, which only main may build. Bump panelbench/config.yaml to a pre-release version such as X.Y.ZbN first." + exit 1 + fi { echo "tags<