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)
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.
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.
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 (developinstead ofmain), the main leg mis-computes its version and publishes a malformed non-prerelease release that becomes "Latest", and re-points the Dockerlatesttag to it.Observed behavior (downstream: ptr727/PlexCleaner)
publish-release.ymlon--ref develop(to exercise develop-only workflow changes).SemVer2 = 3.18.13-gaffdf75f42- i.e. a-g<sha>prerelease-format string - but thegithub-releasejob still created it as a non-prerelease release, because prerelease is keyed off the branch:prerelease: ${{ inputs.branch != 'main' }}.3.18.13-gaffdf75f42as Latest (most recent non-prerelease), displacing the correct stable3.18.13, and the build pushed a stray Docker tag plus relabeledlatest.--ref mainproduces 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
latestwere 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 marksbranch == 'main'as non-prerelease, yielding a non-prerelease release with a prerelease version string.Suggested guardrails (either/both)
Restrict the dispatch ref to the default branch. In the
setupjob, fail fast whengithub.event_name == 'workflow_dispatch' && github.ref_name != github.event.repository.default_branchwith 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.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') butneeds.get-version.outputs.SemVer2contains 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
developto validate develop-only workflow changes.