diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 050f3fa3..bd2418b2 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -2,15 +2,30 @@ name: release # Builds and pushes the minstrel container image to the Gitea registry. # -# push to main → :main and :latest (latest-release APK bundled) -# push tag vYYYY.MM.DD → :vYYYY.MM.DD and :latest (freshly-built APK bundled) -# workflow_dispatch → manual trigger (same rules based on the ref) +# push to main → :main and :latest (latest-release APK bundled) +# push tag vYYYY.MM.DD.HHMM → :vYYYY.MM.DD.HHMM and :latest (fresh APK bundled) +# workflow_dispatch → manual trigger (same rules based on the ref) # -# Release model: per-day CalVer tags (no trailing patch digit). The day's -# tag is intentionally mutable — if a second release happens the same day, -# move the tag with `git push -f origin vYYYY.MM.DD` and the image tag of -# the same name gets overwritten. :latest is updated by every main push -# AND every tag push, so it always reflects the newest blessed image. +# Release model: the tag IS the artifact's version name with a `v` in front. +# `v2026.09.10.1432` and `2026.09.10.1432` are the same string, derived from +# the tagged commit's UTC timestamp — so there is no mismatch to reconcile +# between what the tag says and what the APK reports, and nothing to look up +# when minting one. +# +# TAGS ARE IMMUTABLE. Never move, retarget or delete a published tag. A +# same-day second release is not a collision — HHMM makes every tag unique +# by construction, so the answer is simply another tag. +# +# This block used to say the opposite: that the per-day tag was +# "intentionally mutable" and that a same-day re-cut should +# `git push -f origin vYYYY.MM.DD`. That instruction is what the family +# rulebook now forbids outright, and it has incidents behind it — moving a +# same-day tag forward once took a published release down with it. Anyone +# installing from a tag is holding something the tag no longer points at, +# which is a worse failure than an extra row in the tag list. +# +# :latest is updated by every main push AND every tag push, so it always +# reflects the newest blessed image. # # APK pipeline: on tag pushes the android-release job builds + signs the # Android APK and uploads it as a workflow artifact. The image-release @@ -41,9 +56,10 @@ on: - '**/*.md' workflow_dispatch: -# Force-moving the per-day tag (or rapidly re-pushing to main) should -# supersede the in-flight build — the operator explicitly wants the -# later commit to win. +# A rapid re-push to main should supersede the in-flight build — the +# operator explicitly wants the later commit to win. Tags no longer enter +# into this: they are immutable and unique, so no tag build can ever be +# superseded by another run on the same ref. concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -290,8 +306,8 @@ jobs: else # Main is the protected, post-PR-merge branch. Treat it as the # rolling stable channel — every main push moves :latest. - # Pinned consumers can target :vYYYY.MM.DD; everyone else - # gets the newest main. + # Pinned consumers can target :vYYYY.MM.DD.HHMM, which never + # moves; everyone else gets the newest main. echo "args=-t ${IMAGE}:main -t ${IMAGE}:latest" >> "$GITHUB_OUTPUT" echo "version=main" >> "$GITHUB_OUTPUT" echo "::notice::Main-branch build: :main + :latest" diff --git a/README.md b/README.md index 58db87d4..14febf77 100644 --- a/README.md +++ b/README.md @@ -113,10 +113,12 @@ Most operational keys have a `MINSTREL_
_` env override. Recommen Image tags (`git.fabledsword.com/bvandeusen/minstrel:`): - `:latest` — the newest blessed image. Moves on every `main` push **and** every release. Recommended for most operators. -- `:vYYYY.MM.DD` — immutable per-day release tags. Pin one of these for a deployment you don't want moving under you. (Per-day CalVer — no trailing patch digit; a same-day re-cut moves the tag forward.) +- `:vYYYY.MM.DD.HHMM` — immutable release tags, never moved or deleted. Pin one for a deployment you don't want changing under you. The tag is the build's own version name with a `v` in front, derived from the tagged commit's UTC timestamp, so two releases can never collide and a re-cut is simply a new tag. - `:main` — the rolling post-merge tip. Same image as `:latest` at push time; choose it if you want to track `main` explicitly rather than the release line. -Every `:latest` and every `:vYYYY.MM.DD` bundles the current signed Android APK, so the in-app update channel is always live. Database migrations run automatically at startup; rollbacks require restoring a Postgres dump. +Every `:latest` and every `:vYYYY.MM.DD.HHMM` bundles the current signed Android APK, so the in-app update channel is always live. Database migrations run automatically at startup; rollbacks require restoring a Postgres dump. + +Releases before 2026-09-10 use the older per-day `:vYYYY.MM.DD` shape. Those tags still exist and still work — they are simply not extended. ## Specs