Skip to content

publish-release.yml: workflow_dispatch on a non-default ref mis-versions the other branch leg (malformed non-prerelease release becomes Latest) #183

Description

@ptr727

Summary

publish-release.yml (workflow_dispatch) always builds both branches in a matrix regardless of the ref the dispatch runs on. When dispatched on a ref other than the default branch (develop instead of main), the main leg mis-computes its version and publishes a malformed non-prerelease release that becomes "Latest", and re-points the Docker latest tag to it.

Observed behavior (downstream: ptr727/PlexCleaner)

  • Dispatch publish-release.yml on --ref develop (to exercise develop-only workflow changes).
  • The matrix runs both legs. The main leg produced SemVer2 = 3.18.13-gaffdf75f42 - i.e. a -g<sha>prerelease-format string - but the github-release job still created it as a non-prerelease release, because prerelease is keyed off the branch: prerelease: ${{ inputs.branch != 'main' }}.
  • GitHub then marked 3.18.13-gaffdf75f42 as Latest (most recent non-prerelease), displacing the correct stable 3.18.13, and the build pushed a stray Docker tag plus relabeled latest.
  • Dispatching on --ref main produces correct output (main leg -> clean stable). So the failure is specifically "dispatch ref != the branch leg."

The image content was still correct (right commit), but the version label, the GitHub "Latest" pointer, and Docker latest were wrong - a confusing public-release state that needs manual cleanup (delete release + tag, gh release edit <stable> --latest, re-dispatch on main, delete stray Docker tags).

Why it happens

The per-branch leg checks out its branch, but NBGV's public-release detection (publicReleaseRefSpec: ^refs/heads/main$) does not resolve to the public main ref when the run's triggering ref is a different branch, so it appends the prerelease -g<sha> height. The release job nonetheless marks branch == 'main' as non-prerelease, yielding a non-prerelease release with a prerelease version string.

Suggested guardrails (either/both)

  1. Restrict the dispatch ref to the default branch. In the setup job, fail fast when github.event_name == 'workflow_dispatch' && github.ref_name != github.event.repository.default_branch with a clear message ("dispatch publish from main; the matrix builds both branches"). The scheduled run already uses the default branch, and the matrix design assumes it - so there is no legitimate reason to dispatch from a non-default ref.

  2. Version-sanity safety net in github-release (root-cause-agnostic). Before creating a release, fail (or skip) when the leg is the public/non-prerelease branch (inputs.branch == 'main') but needs.get-version.outputs.SemVer2 contains a - (a prerelease suffix). A public release must never carry a prerelease version; this catches the malformed state regardless of why NBGV misfired, preventing a bad "Latest" from ever being published.

A combination is ideal: (1) stops the foot-gun at the source, (2) is a defense-in-depth net if versioning ever misfires for another reason.

Found while re-syncing a downstream and dispatching a publish on develop to validate develop-only workflow changes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions