Release image: a pre-release tag moves :latest, and an rc spelled without a dot replaces the stable :X.Y #418

Closed
opened 2026-10-01 10:46:33 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-09-29 in a read-only review of postulo at 95348908d, comparing how scripts/release_tools.py and .forgejo/workflows/image.yml treat a pre-release tag.

Checked again on 2026-10-01 against main at 0a5cad587: still present.

The release tooling accepts pre-release tags and marks their Forgejo release as a pre-release. The image workflow does not distinguish them: it pushes the same three tags as for a stable release, latest included. The compose files and the Installing Postulo page tell operators to follow a minor tag, and for one spelling of release candidate the image workflow overwrites exactly that minor tag.

  • Where: version_of_tag in scripts/release_tools.py:58-61 accepts v\d+\.\d+\.\d+(?:[-+.][0-9A-Za-z.]+)?; publish in scripts/release_tools.py:240 sets "prerelease": "-" in version or "+" in version; the Work out the tags step in .forgejo/workflows/image.yml:85-89 always writes ${image}:${version},${image}:${version%.*},${image}:latest; image_tags in scripts/release_tools.py:64-70, and verify_image (:309-342), which requires all three tags.
  • What happens: for v0.4.0-rc.1 the image is pushed as 0.4.0-rc.1, 0.4.0-rc and latest, so latest is the release candidate. For v0.4.1-rc1, ${version%.*} is 0.4, so the candidate replaces the stable :0.4 image as well. tests/test_release_tools.py:213 asserts image_tags("1.0.0-rc.1") == ("1.0.0-rc.1", "1.0.0-rc", "latest"), which fixes this behaviour in place rather than questioning it. A +build tag is accepted too, although a Docker tag cannot contain +, so its push would fail.
  • Why it matters: docker/compose.yml and docker/compose.postgres.yml pin …/postulo:X.Y, and the wiki's upgrade path is docker compose pull. An operator following latest, or the stable minor when the rc has no dot, would be moved onto a release candidate by an ordinary pull, while the Forgejo release page correctly calls it a pre-release. No pre-release has been tagged yet (tags so far are v0.1.0 to v0.3.0), so nobody has been affected, but the tooling explicitly accepts one.
  • Fix: decide what a pre-release is in one place, for example is_prerelease(version) in release_tools.py, and use it everywhere. For a pre-release, image_tags returns only the version, so verify_image checks only that tag. image.yml takes its tag list from release_tools.py instead of computing its own with ${version%.*}, so the workflow and the script cannot disagree. version_of_tag refuses + (or the + part is dropped from the image tag). If pre-releases are not wanted at all, make version_of_tag accept only vX.Y.Z and drop the prerelease expression.

Done when

  • tests/test_release_tools.py: image_tags("0.4.0-rc.1") and image_tags("0.4.1-rc1") contain neither latest nor 0.4, and version_of_tag("v0.4.0+build.1") raises ReleaseError. Both fail today. The existing assertion at line 213 is replaced.
Found on 2026-09-29 in a read-only review of postulo at 95348908d, comparing how `scripts/release_tools.py` and `.forgejo/workflows/image.yml` treat a pre-release tag. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. The release tooling accepts pre-release tags and marks their Forgejo release as a pre-release. The image workflow does not distinguish them: it pushes the same three tags as for a stable release, `latest` included. The compose files and the *Installing Postulo* page tell operators to follow a minor tag, and for one spelling of release candidate the image workflow overwrites exactly that minor tag. - **Where:** `version_of_tag` in `scripts/release_tools.py:58-61` accepts `v\d+\.\d+\.\d+(?:[-+.][0-9A-Za-z.]+)?`; `publish` in `scripts/release_tools.py:240` sets `"prerelease": "-" in version or "+" in version`; the *Work out the tags* step in `.forgejo/workflows/image.yml:85-89` always writes `${image}:${version},${image}:${version%.*},${image}:latest`; `image_tags` in `scripts/release_tools.py:64-70`, and `verify_image` (`:309-342`), which requires all three tags. - **What happens:** for `v0.4.0-rc.1` the image is pushed as `0.4.0-rc.1`, `0.4.0-rc` and `latest`, so `latest` is the release candidate. For `v0.4.1-rc1`, `${version%.*}` is `0.4`, so the candidate replaces the stable `:0.4` image as well. `tests/test_release_tools.py:213` asserts `image_tags("1.0.0-rc.1") == ("1.0.0-rc.1", "1.0.0-rc", "latest")`, which fixes this behaviour in place rather than questioning it. A `+build` tag is accepted too, although a Docker tag cannot contain `+`, so its push would fail. - **Why it matters:** `docker/compose.yml` and `docker/compose.postgres.yml` pin `…/postulo:X.Y`, and the wiki's upgrade path is `docker compose pull`. An operator following `latest`, or the stable minor when the rc has no dot, would be moved onto a release candidate by an ordinary pull, while the Forgejo release page correctly calls it a pre-release. No pre-release has been tagged yet (tags so far are `v0.1.0` to `v0.3.0`), so nobody has been affected, but the tooling explicitly accepts one. - **Fix:** decide what a pre-release is in one place, for example `is_prerelease(version)` in `release_tools.py`, and use it everywhere. For a pre-release, `image_tags` returns only the version, so `verify_image` checks only that tag. `image.yml` takes its tag list from `release_tools.py` instead of computing its own with `${version%.*}`, so the workflow and the script cannot disagree. `version_of_tag` refuses `+` (or the `+` part is dropped from the image tag). If pre-releases are not wanted at all, make `version_of_tag` accept only `vX.Y.Z` and drop the `prerelease` expression. ## Done when - `tests/test_release_tools.py`: `image_tags("0.4.0-rc.1")` and `image_tags("0.4.1-rc1")` contain neither `latest` nor `0.4`, and `version_of_tag("v0.4.0+build.1")` raises `ReleaseError`. Both fail today. The existing assertion at line 213 is replaced.
tiagoagueda added this to the 0.6.0 milestone 2026-10-01 10:46:33 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#418
No description provided.