Summary
The validate-release entry gate in build-release-task.yml runs unconditionally, including in PR smoke builds. A PR smoke build checks out the PR head in detached HEAD, so NBGV always computes a prerelease version (X.Y.Z-g<sha>). For a main-base PR — i.e. a develop -> main promotion that carries a build target (a library/app change being promoted) — the gate's public-release branch then fails:
::error::Public (main) release version 'X.Y.Z-g<sha>' carries a prerelease suffix; refusing to publish.
The smoke build's validate-release job fails → build is skipped → the required Check pull request workflow status fails. Every develop -> main promotion PR that includes a build-target change is blocked by its own smoke build.
Impact
Masked when a promotion is merged via admin bypass (e.g. resolving a merge conflict), so it can lurk. But a clean promotion carrying library changes cannot pass CI. Confirmed in a derived repo: a real main-base PR smoke build failed with SEMVER2=1.4.4-g901404c71a, branch=main.
Root cause
validate-release has no smoke guard. Smoke builds (detached PR checkout) always produce a prerelease version — correct for the build, but it trips the branch == main arm of the gate. The gate's purpose is to guard real publishes, which smoke builds never do.
Proposed fix
Skip the check for smoke builds, keeping the job in the graph so build-nugetlibrary's needs: [get-version, validate-release] stays satisfied (the job still succeeds):
- name: Validate branch and version consistency step
env:
SEMVER2: ${{ needs.get-version.outputs.SemVer2 }}
BRANCH: ${{ inputs.branch }}
SMOKE: ${{ inputs.smoke }}
run: |
set -euo pipefail
# This gate guards real publishes. A smoke build checks out the PR head in detached HEAD, so NBGV always
# yields a prerelease version; on a main-base PR that would trip the public-release check and fail every
# develop->main promotion that carries a build target. Skip the gate for smoke builds (they never publish).
if [[ "$SMOKE" == "true" ]]; then
echo "Smoke build; skipping release version validation."
exit 0
fi
CORE_AND_PRE="${SEMVER2%%+*}"
if [[ "$BRANCH" == "main" ]]; then
...
Verified
A push-probe invoking build-release-task with smoke: true for both branch: main and branch: develop:
| base |
validate-release |
build |
publish |
| main |
success (skipped) |
Release |
github-release skipped |
| develop |
success (skipped) |
Debug |
github-release skipped |
Before the fix, the main-base validate-release failed; after, both pass and nothing publishes.
Found via end-to-end CI flow validation in a derived repo (the validate-release gate originates from #213/#214's re-sync).
Summary
The
validate-releaseentry gate inbuild-release-task.ymlruns unconditionally, including in PR smoke builds. A PR smoke build checks out the PR head in detached HEAD, so NBGV always computes a prerelease version (X.Y.Z-g<sha>). For a main-base PR — i.e. adevelop -> mainpromotion that carries a build target (a library/app change being promoted) — the gate's public-release branch then fails:The smoke build's
validate-releasejob fails →buildis skipped → the requiredCheck pull request workflow statusfails. Everydevelop -> mainpromotion PR that includes a build-target change is blocked by its own smoke build.Impact
Masked when a promotion is merged via admin bypass (e.g. resolving a merge conflict), so it can lurk. But a clean promotion carrying library changes cannot pass CI. Confirmed in a derived repo: a real main-base PR smoke build failed with
SEMVER2=1.4.4-g901404c71a,branch=main.Root cause
validate-releasehas no smoke guard. Smoke builds (detached PR checkout) always produce a prerelease version — correct for the build, but it trips thebranch == mainarm of the gate. The gate's purpose is to guard real publishes, which smoke builds never do.Proposed fix
Skip the check for smoke builds, keeping the job in the graph so
build-nugetlibrary'sneeds: [get-version, validate-release]stays satisfied (the job still succeeds):Verified
A push-probe invoking
build-release-taskwithsmoke: truefor bothbranch: mainandbranch: develop:Before the fix, the main-base
validate-releasefailed; after, both pass and nothing publishes.Found via end-to-end CI flow validation in a derived repo (the
validate-releasegate originates from #213/#214's re-sync).