From 1d4c206563b5c10e9489b0ac2af4304d1bc457a5 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 3 Jun 2026 14:27:53 -0400 Subject: [PATCH] ci: main publishes :latest (main is the production line) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit main pushes now move :latest (in addition to the immutable :), so a merge to main updates production's pointer directly — no separate release needed just to refresh :latest. The v* release tag's distinct job becomes the dated : marker (it still refreshes :latest harmlessly). Still no :main tag. Rules 47/46 + 10/4 updated to match on both instances. Co-Authored-By: Claude Opus 4.8 (1M context) --- .forgejo/workflows/ci.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index ba50226..5ce0712 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -1,15 +1,15 @@ # CI runs first; build only proceeds if all checks pass. # # Push to dev: typecheck + lint + test + build :dev + : -# Push to main: typecheck + lint + test + build : (no moving tag) +# Push to main: typecheck + lint + test + build :latest + : # Tag v* (release): typecheck + lint + test + build :latest + : + : # -# Both dev and main are gated AND built. dev pushes move the :dev tag; main -# pushes publish only the immutable : image — no :main tag, because -# :latest (release-only) is the single production pointer and a :main alias -# would just duplicate it. Running CI on the main merge commit is intentional: -# main is validated and its : image is the rollback point. The v* release -# tag is the ONLY trigger that publishes :latest plus the immutable :. +# Both dev and main are gated AND built. dev pushes move :dev; main pushes move +# :latest — main IS the production line, so :latest tracks main's tip and there +# is no separate :main tag. Every push also gets an immutable : (the +# rollback point). A v* release tag additionally publishes the dated :; +# since main already moved :latest, the release tag's distinct job is that +# : marker (it refreshes :latest too, harmlessly). # # Successive pushes to the SAME ref supersede each other (see concurrency # below), so rapid pushes don't stack identical work; dev and main runs are @@ -142,7 +142,7 @@ jobs: build: name: Build & push image needs: [typecheck, lint, test] - # Build on dev, main, and v* tag pushes. dev → :dev, main → (sha only), + # Build on dev, main, and v* tag pushes. dev → :dev, main → :latest, # tag → :latest + :; every build also gets an immutable :. if: github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') runs-on: python-ci @@ -171,8 +171,9 @@ jobs: TAGS="$TAGS,${{ env.IMAGE }}:dev" ;; refs/heads/main) - # main publishes only the immutable : image (set above) — - # no :main tag; :latest (release-only) is the production pointer. + # main IS the production line: publish :latest (plus the : + # set above). No separate :main tag. + TAGS="$TAGS,${{ env.IMAGE }}:latest" BUILD_VERSION="main" ;; refs/tags/*)