RC tag builds increment and republish the next RC with old code #20

Open
opened 2026-10-12 21:03:30 +00:00 by KofTwentyTwo · 0 comments
KofTwentyTwo commented 2026-10-12 21:03:30 +00:00 (Migrated from github.com)

Summary

A build triggered by a release-candidate tag (vX.Y.Z-RC.N) does not publish X.Y.Z-RC.N. calculate_version.sh treats the tag as a release/X.Y branch build, handle_release_branch increments the RC already in the pom, and mvn_publish deploys the next RC number with the old tag's code. That burns a version on Maven Central and publishes a duplicate artifact under a misleading number.

Where it happens

src/scripts/calculate_version.sh:

  1. Tag detection (lines 80-83): a tag matching ^v([0-9]+\.[0-9]+\.[0-9]+)-RC\.[0-9]+$ is mapped to a release branch:
    echo "This is a release candidate tag, treating as release branch"
    CURRENT_BRANCH="release/${CURRENT_TAG#v}"
    CURRENT_BRANCH="release/${CURRENT_BRANCH%-RC.*}"
    
    (Side note: this produces release/release/1.0.0, not release/1.0. It still "works" only because the regex in handle_release_branch is unanchored and matches the inner release/1.0.)
  2. handle_release_branch (lines 266-294): if the pom already holds X.Y.Z-RC.N, it sets NEW_VERSION=X.Y.0-RC.(N+1).

The tag commit is the commit the release-branch build already published as RC.N (the pom on that commit already says RC.N), so the tag build always produces RC.(N+1) with the same code.

Evidence (2026-10-12)

Both qbit repos had a publish_release workflow (qqq-orb/mvn_publish, branch_type: release) filtered on tags /v.*/:

Artifact published When Triggered by Actually contains
com.kingsrook.qbits:qbit-sql-workbench:1.0.0-RC.3 17:46Z, CircleCI job 17 tag v1.0.0-RC.2 at 0d8af84 the 1.0.0-RC.2 code
com.kingsrook.qbits:qbit-assistant:0.1.0-RC.2 17:56Z, CircleCI job 14 tag v0.1.0-RC.1 at 7263ac6 the 0.1.0-RC.1 code

Both versions are now burned. The next real candidates are 1.0.0-RC.4 and 0.1.0-RC.3.

The consumer-side mitigation is in flight: the qbit repos are changing the publish_release tag filter to GA tags only (/^v\d+\.\d+\.\d+$/, branch feature/ga-only-release-tags). That stops the trigger, but any other repo that filters on /v.*/ (or adds one later) still hits this in the orb.

Proposed fix

For a vX.Y.Z-RC.N tag build, the orb should never increment. Either:

  • Publish exactly X.Y.Z-RC.N, and exit non-zero if that version already exists on Central (it normally will, because the release-branch build published it); or
  • Refuse: exit non-zero with a clear message that RC tags are bookkeeping only and RCs publish from release/* branch builds.

Refusing is the smaller, safer change and matches how the release flow actually works (RC tags are created after the release-branch build already published). A follow-up PR implements that, with a test in tests/test_calculate_version.sh.

## Summary A build triggered by a release-candidate tag (`vX.Y.Z-RC.N`) does not publish `X.Y.Z-RC.N`. `calculate_version.sh` treats the tag as a `release/X.Y` branch build, `handle_release_branch` increments the RC already in the pom, and `mvn_publish` deploys the next RC number with the old tag's code. That burns a version on Maven Central and publishes a duplicate artifact under a misleading number. ## Where it happens `src/scripts/calculate_version.sh`: 1. Tag detection (lines 80-83): a tag matching `^v([0-9]+\.[0-9]+\.[0-9]+)-RC\.[0-9]+$` is mapped to a release branch: ```bash echo "This is a release candidate tag, treating as release branch" CURRENT_BRANCH="release/${CURRENT_TAG#v}" CURRENT_BRANCH="release/${CURRENT_BRANCH%-RC.*}" ``` (Side note: this produces `release/release/1.0.0`, not `release/1.0`. It still "works" only because the regex in `handle_release_branch` is unanchored and matches the inner `release/1.0`.) 2. `handle_release_branch` (lines 266-294): if the pom already holds `X.Y.Z-RC.N`, it sets `NEW_VERSION=X.Y.0-RC.(N+1)`. The tag commit is the commit the release-branch build already published as `RC.N` (the pom on that commit already says `RC.N`), so the tag build always produces `RC.(N+1)` with the same code. ## Evidence (2026-10-12) Both qbit repos had a `publish_release` workflow (`qqq-orb/mvn_publish`, `branch_type: release`) filtered on tags `/v.*/`: | Artifact published | When | Triggered by | Actually contains | |---|---|---|---| | `com.kingsrook.qbits:qbit-sql-workbench:1.0.0-RC.3` | 17:46Z, CircleCI job 17 | tag `v1.0.0-RC.2` at `0d8af84` | the 1.0.0-RC.2 code | | `com.kingsrook.qbits:qbit-assistant:0.1.0-RC.2` | 17:56Z, CircleCI job 14 | tag `v0.1.0-RC.1` at `7263ac6` | the 0.1.0-RC.1 code | Both versions are now burned. The next real candidates are 1.0.0-RC.4 and 0.1.0-RC.3. The consumer-side mitigation is in flight: the qbit repos are changing the `publish_release` tag filter to GA tags only (`/^v\d+\.\d+\.\d+$/`, branch `feature/ga-only-release-tags`). That stops the trigger, but any other repo that filters on `/v.*/` (or adds one later) still hits this in the orb. ## Proposed fix For a `vX.Y.Z-RC.N` tag build, the orb should never increment. Either: - **Publish exactly `X.Y.Z-RC.N`**, and exit non-zero if that version already exists on Central (it normally will, because the release-branch build published it); or - **Refuse**: exit non-zero with a clear message that RC tags are bookkeeping only and RCs publish from `release/*` branch builds. Refusing is the smaller, safer change and matches how the release flow actually works (RC tags are created after the release-branch build already published). A follow-up PR implements that, with a test in `tests/test_calculate_version.sh`.
This repo is archived. You cannot comment on issues.
1 Participants
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: QRun-IO/qqq-orb#20