Skip to content

release-tag-check: git tag --sort=-v:refname | head -1 misorders prereleases, fails release job after a published stable release #384

@bedatty

Description

@bedatty

Summary

src/config/release-tag-check/action.yml decides whether a release was published by comparing the latest semver tag against a pre-release snapshot:

git fetch --tags origin
NEW_TAG=$(git tag -l 'v*' --sort=-v:refname | head -1)
if [ "$NEW_TAG" != "$PREVIOUS_TAG" ] && [ -n "$NEW_TAG" ]; then
  echo "release_published=true" >> "$GITHUB_OUTPUT"
  ...

git tag --sort=-v:refname without versionsort.suffix configured orders a prerelease tag above its stable counterpart. So with tags v2.0.0 and v2.0.0-beta.2, head -1 returns v2.0.0-beta.2, not v2.0.0.

Impact

In release.yml, when the post-publish backmerge fails (steps.semantic.outcome == 'failure', e.g. a dirty working tree breaks @saithodev/semantic-release-backmerge's git rebase), release-tag-check runs to recover. Because the snapshot PREVIOUS_TAG was also computed the same way (it was already v2.0.0-beta.2), NEW_TAG == PREVIOUS_TAGrelease_published=false, even though v2.0.0 was published.

That false false then:

  • skips the Backmerge PR fallback step (its if requires release-published == 'true'), and
  • runs Fail if release itself failed, killing the job with the misleading message "Semantic release failed before publishing a new version".

Net result: the stable release is published (GitHub release + tag + PR labels all created), the backmerge silently does not happen, and the job goes red with a message that says the opposite of what occurred.

This action is byte-identical across @v1.21.0 and the current @v1 / @v1.31.0, so bumping the shared-workflows version does not help. It affects any consumer repo using prereleases (e.g. develop → beta, release-candidate → rc).

Reproduce

printf 'v2.0.0\nv2.0.0-beta.2\nv2.0.0-beta.1\nv1.14.1\n' | xargs -n1 -I{} git tag {} 2>/dev/null
git tag -l 'v*' --sort=-v:refname | head -1   # => v2.0.0-beta.2  (expected: v2.0.0)

Real occurrence: LerianStudio/tenant-manager release run #26594352945 (published v2.0.0, job failed).

Proposed fix

Configure git's version-sort suffix so prereleases sort below the stable tag, e.g. in the action step:

git config versionsort.suffix '-'        # any tag containing '-' sorts before the bare version
# or, more explicit:
git -c versionsort.suffix=-alpha -c versionsort.suffix=-beta -c versionsort.suffix=-rc \
    tag -l 'v*' --sort=-v:refname | head -1

Alternatively, drop git sorting and select the newest tag with a semver-aware comparison (e.g. semver via node, already available in the release job), or compare creation time of the tag created by this run rather than "latest tag overall".

Adjacent note

In the tenant-manager case the trigger for the failed backmerge was a stray tracked package-lock.json dirtying the working tree; that is a consumer-repo bug (fixed there). But release-tag-check should still report the truth when any post-publish step fails — hence this issue.

Metadata

Metadata

Assignees

Labels

bugSomething is not working as expected

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions