Version each publish leg against its own branch; validate at entry - #215

Merged
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213
Jun 26, 2026
Merged

Version each publish leg against its own branch; validate at entry#215
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Problem

Closes#213. publish-release.yml dispatched from main builds a matrix of both main and develop. NBGV derives PublicRelease from the runner's GITHUB_REF, which is refs/heads/main for every leg regardless of the ref each leg checks out. So the develop leg is classified public, NBGV strips its -g<sha> prerelease suffix, and the develop NuGet package is published as a stable version (isPrerelease=false) — consumers can resolve a develop build as if stable. The GitHub release object stays prerelease:true, masking the bug.

Fix

  • get-version-task.yml: optional branch input pins the GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned (fallback to github.ref when empty). The mislabel originates in build-nugetlibrary-task's own get-version call, so branch is threaded from all five callers (build-release-task + the four build-*-task files).
  • Validate at entry: the late, one-directional "Verify public release version" step (main-only, mid-flow in github-release) is replaced by a single validate-release job that the build jobs needs:. It checks branch↔version consistency both directions — main must carry no prerelease -; every other branch must carry one (the Publish matrix mislabels the develop leg as a public release: NBGV drops the prerelease tag, NuGet package published as stable #213 regression guard) — and fails fast before the expensive builds.
  • Pattern: codified "validate input/state consistency at entry, fail fast" in AGENTS.md "Workflow YAML Conventions", generalizing the existing publish-docker-readme-task.yml "Validate inputs step".

Verification

  • actionlint (Docker) clean on all six changed workflows; markdownlint clean on AGENTS.md; CRLF preserved.
  • Live proof (post-merge): dispatch publish-release from main, confirm the develop leg's SemVer2 regains -g<sha> and the NuGet package is isPrerelease=true; validate-release fails a clean-X.Y.Z develop version.

🤖 Generated with Claude Code

Fixes#213. On a publish dispatched from the default branch, NBGV derives
PublicRelease from the runner's GITHUB_REF (= refs/heads/main for every matrix
leg), so the develop leg loses its -g<sha> prerelease suffix and its NuGet
package is published as a stable version (isPrerelease=false).
- get-version-task.yml gains an optional `branch` input that pins the
GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned, with a
github.ref fallback when empty. Threaded from all five callers
(build-release-task + the four build-*-task files).
- Replace the late, main-only "Verify public release version" step with a
single `validate-release` entry job that the build jobs needs:, checking
branch<->version consistency both directions (main must have no prerelease
suffix; every other branch must have one) and failing fast before builds.
- Codify the validate-input/state-consistency-at-entry pattern in AGENTS.md
"Workflow YAML Conventions".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a release-pipeline versioning bug where publish-release.yml runs from main but builds a main+develop matrix, causing NBGV to classify the develop leg as a public release and publish stable NuGet versions.

Changes:

  • Add an optional branch input to get-version-task.yml and pin GITHUB_REF/GITHUB_REF_NAME for the NBGV step to the leg being versioned.
  • Thread branch through all reusable-workflow callers of get-version-task.yml so every target versions against its intended branch.
  • Replace the late, one-directional main-only version check with an early validate-release job that enforces branch<->prerelease consistency for both main and non-main legs.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
AGENTS.mdDocuments the “validate invariants at entry, fail fast” workflow convention with concrete examples.
.github/workflows/get-version-task.ymlAdds branch input and pins env so NBGV classifies the correct leg branch during matrix publishes.
.github/workflows/build-release-task.ymlThreads branch into versioning and adds an entry validate-release job gating downstream build/release jobs.
.github/workflows/build-pypilibrary-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-nugetlibrary-task.ymlPasses inputs.branch to the shared get-version workflow (fixing the mislabel root cause for NuGet).
.github/workflows/build-executable-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-docker-task.ymlPasses inputs.branch to the shared get-version workflow.

@ptr727
ptr727 merged commit 5adbcb9 into developJun 26, 2026
10 checks passed
@ptr727
ptr727 deleted the feature/version-leg-prerelease-213 branch June 26, 2026 18:05
ptr727 added a commit that referenced this pull request Jun 27, 2026
## Problem
Closes#219. The `validate-release` entry gate (added in #213/#215) runs
**unconditionally**, including in PR **smoke** builds. A smoke build
checks out the PR head in detached HEAD, so NBGV always computes a
prerelease version (`X.Y.Z-g<sha>`). On a **main-base** PR — a `develop
→ main` promotion carrying a build target — the gate's `branch ==
'main'` arm fails:
```
::error::Public (main) release version 'X.Y.Z-g<sha>' carries a prerelease suffix; refusing to publish.
```
`validate-release` fails → `build` is skipped → the required `Check pull
request workflow status` fails. **Every clean `develop → main` promotion
PR that includes a build-target change is blocked by its own smoke
build** (masked only when merged via admin bypass).
## Fix
Skip the gate for smoke builds — they never publish — keeping the job in
the graph as a **success** so `build-*`'s `needs: [get-version,
validate-release]` stays satisfied:
```yaml
SMOKE: ${{ inputs.smoke }}
...
if [[ "$SMOKE" == "true" ]]; then
echo "Smoke build; skipping release version validation."
exit 0
fi
```
Real publishes (`smoke: false`) still get both-direction validation.
## Verification
- `actionlint` (Docker, shellcheck-bundled) clean; CRLF preserved.
- Per the issue's push-probe: a `smoke: true` invocation passes for both
`branch: main` (Release) and `branch: develop` (Debug) with
`github-release` skipped; real publishes unaffected.
Found via end-to-end CI flow validation during the #213/#214 downstream
re-sync.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ptr727 added a commit that referenced this pull request Jun 27, 2026
…ride (#222)
## Problem
Closes#221; supersedes the mechanism from #215. The #213 fix (PR #215)
restored the develop leg's prerelease tag by overriding `GITHUB_REF` in
the nbgv step `env:`. **It doesn't work.** `GITHUB_REF` is
GitHub-reserved — a step-level `env:` can't reliably override it (the
runner re-injects the dispatch ref). NBGV's GitHub Actions cloud-build
provider reads `GITHUB_REF` for `BuildingRef`, so on a publish
dispatched from `main` the develop leg was still classified public and
would publish a **clean (stable)** version.
CI evidence from the first real publish after #215:
```
GITHUB_REF: refs/heads/develop # the step-env override (as configured)
"BuildingRef": "refs/heads/main" # NBGV still saw the dispatch ref
"PublicRelease": true
"SemVer2": "1.4.2" # clean, no -g suffix
```
(The `validate-release` gate correctly blocked the bad publish, so
nothing shipped — but the develop prerelease leg never publishes.)
## Fix
NBGV versions from the **checked-out branch** unless its cloud provider
overrides with `GITHUB_REF`. Each matrix leg already checks out its own
branch, so set NBGV's own `IGNORE_GITHUB_REF=true` to make it ignore the
CI ref:
```yaml
- name: Run Nerdbank.GitVersioning tool step
id: nbgv
uses: dotnet/nbgv@master
env:
IGNORE_GITHUB_REF: true
```
- Removed the ineffective `GITHUB_REF`/`GITHUB_REF_NAME` override.
- Dropped the now-useless `branch` input from `get-version-task.yml` and
its threading from all five callers (`build-release-task` + the four
`build-*-task`).
- `validate-release` entry gate (from #213/#215, smoke-skip from #219)
**stays** as the backstop.
NBGV source confirms the knob: `BuildingRef => IgnoreGitHubRef ? null :
env GITHUB_REF`.
## Verification
- `actionlint` (Docker) clean on all six changed workflows; CRLF
preserved.
- Per the issue's CI probe (real `dotnet/nbgv`): `develop` checkout +
`IGNORE_GITHUB_REF=true` → `PublicRelease=False`, `1.4.2-g…`; `main` →
`True`, `1.4.3`; `main` without the flag reproduces the bug.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ptr727
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Version each publish leg against its own branch; validate at entry - #215

Merged
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213
Jun 26, 2026
Merged

Version each publish leg against its own branch; validate at entry#215
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Problem

Closes#213. publish-release.yml dispatched from main builds a matrix of both main and develop. NBGV derives PublicRelease from the runner's GITHUB_REF, which is refs/heads/main for every leg regardless of the ref each leg checks out. So the develop leg is classified public, NBGV strips its -g<sha> prerelease suffix, and the develop NuGet package is published as a stable version (isPrerelease=false) — consumers can resolve a develop build as if stable. The GitHub release object stays prerelease:true, masking the bug.

Fix

  • get-version-task.yml: optional branch input pins the GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned (fallback to github.ref when empty). The mislabel originates in build-nugetlibrary-task's own get-version call, so branch is threaded from all five callers (build-release-task + the four build-*-task files).
  • Validate at entry: the late, one-directional "Verify public release version" step (main-only, mid-flow in github-release) is replaced by a single validate-release job that the build jobs needs:. It checks branch↔version consistency both directions — main must carry no prerelease -; every other branch must carry one (the Publish matrix mislabels the develop leg as a public release: NBGV drops the prerelease tag, NuGet package published as stable #213 regression guard) — and fails fast before the expensive builds.
  • Pattern: codified "validate input/state consistency at entry, fail fast" in AGENTS.md "Workflow YAML Conventions", generalizing the existing publish-docker-readme-task.yml "Validate inputs step".

Verification

  • actionlint (Docker) clean on all six changed workflows; markdownlint clean on AGENTS.md; CRLF preserved.
  • Live proof (post-merge): dispatch publish-release from main, confirm the develop leg's SemVer2 regains -g<sha> and the NuGet package is isPrerelease=true; validate-release fails a clean-X.Y.Z develop version.

🤖 Generated with Claude Code

Fixes#213. On a publish dispatched from the default branch, NBGV derives
PublicRelease from the runner's GITHUB_REF (= refs/heads/main for every matrix
leg), so the develop leg loses its -g<sha> prerelease suffix and its NuGet
package is published as a stable version (isPrerelease=false).
- get-version-task.yml gains an optional `branch` input that pins the
GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned, with a
github.ref fallback when empty. Threaded from all five callers
(build-release-task + the four build-*-task files).
- Replace the late, main-only "Verify public release version" step with a
single `validate-release` entry job that the build jobs needs:, checking
branch<->version consistency both directions (main must have no prerelease
suffix; every other branch must have one) and failing fast before builds.
- Codify the validate-input/state-consistency-at-entry pattern in AGENTS.md
"Workflow YAML Conventions".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a release-pipeline versioning bug where publish-release.yml runs from main but builds a main+develop matrix, causing NBGV to classify the develop leg as a public release and publish stable NuGet versions.

Changes:

  • Add an optional branch input to get-version-task.yml and pin GITHUB_REF/GITHUB_REF_NAME for the NBGV step to the leg being versioned.
  • Thread branch through all reusable-workflow callers of get-version-task.yml so every target versions against its intended branch.
  • Replace the late, one-directional main-only version check with an early validate-release job that enforces branch<->prerelease consistency for both main and non-main legs.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
AGENTS.mdDocuments the “validate invariants at entry, fail fast” workflow convention with concrete examples.
.github/workflows/get-version-task.ymlAdds branch input and pins env so NBGV classifies the correct leg branch during matrix publishes.
.github/workflows/build-release-task.ymlThreads branch into versioning and adds an entry validate-release job gating downstream build/release jobs.
.github/workflows/build-pypilibrary-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-nugetlibrary-task.ymlPasses inputs.branch to the shared get-version workflow (fixing the mislabel root cause for NuGet).
.github/workflows/build-executable-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-docker-task.ymlPasses inputs.branch to the shared get-version workflow.

@ptr727
ptr727 merged commit 5adbcb9 into developJun 26, 2026
10 checks passed
@ptr727
ptr727 deleted the feature/version-leg-prerelease-213 branch June 26, 2026 18:05
ptr727 added a commit that referenced this pull request Jun 27, 2026
## Problem
Closes#219. The `validate-release` entry gate (added in #213/#215) runs
**unconditionally**, including in PR **smoke** builds. A smoke build
checks out the PR head in detached HEAD, so NBGV always computes a
prerelease version (`X.Y.Z-g<sha>`). On a **main-base** PR — a `develop
→ main` promotion carrying a build target — the gate's `branch ==
'main'` arm fails:
```
::error::Public (main) release version 'X.Y.Z-g<sha>' carries a prerelease suffix; refusing to publish.
```
`validate-release` fails → `build` is skipped → the required `Check pull
request workflow status` fails. **Every clean `develop → main` promotion
PR that includes a build-target change is blocked by its own smoke
build** (masked only when merged via admin bypass).
## Fix
Skip the gate for smoke builds — they never publish — keeping the job in
the graph as a **success** so `build-*`'s `needs: [get-version,
validate-release]` stays satisfied:
```yaml
SMOKE: ${{ inputs.smoke }}
...
if [[ "$SMOKE" == "true" ]]; then
echo "Smoke build; skipping release version validation."
exit 0
fi
```
Real publishes (`smoke: false`) still get both-direction validation.
## Verification
- `actionlint` (Docker, shellcheck-bundled) clean; CRLF preserved.
- Per the issue's push-probe: a `smoke: true` invocation passes for both
`branch: main` (Release) and `branch: develop` (Debug) with
`github-release` skipped; real publishes unaffected.
Found via end-to-end CI flow validation during the #213/#214 downstream
re-sync.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ptr727 added a commit that referenced this pull request Jun 27, 2026
…ride (#222)
## Problem
Closes#221; supersedes the mechanism from #215. The #213 fix (PR #215)
restored the develop leg's prerelease tag by overriding `GITHUB_REF` in
the nbgv step `env:`. **It doesn't work.** `GITHUB_REF` is
GitHub-reserved — a step-level `env:` can't reliably override it (the
runner re-injects the dispatch ref). NBGV's GitHub Actions cloud-build
provider reads `GITHUB_REF` for `BuildingRef`, so on a publish
dispatched from `main` the develop leg was still classified public and
would publish a **clean (stable)** version.
CI evidence from the first real publish after #215:
```
GITHUB_REF: refs/heads/develop # the step-env override (as configured)
"BuildingRef": "refs/heads/main" # NBGV still saw the dispatch ref
"PublicRelease": true
"SemVer2": "1.4.2" # clean, no -g suffix
```
(The `validate-release` gate correctly blocked the bad publish, so
nothing shipped — but the develop prerelease leg never publishes.)
## Fix
NBGV versions from the **checked-out branch** unless its cloud provider
overrides with `GITHUB_REF`. Each matrix leg already checks out its own
branch, so set NBGV's own `IGNORE_GITHUB_REF=true` to make it ignore the
CI ref:
```yaml
- name: Run Nerdbank.GitVersioning tool step
id: nbgv
uses: dotnet/nbgv@master
env:
IGNORE_GITHUB_REF: true
```
- Removed the ineffective `GITHUB_REF`/`GITHUB_REF_NAME` override.
- Dropped the now-useless `branch` input from `get-version-task.yml` and
its threading from all five callers (`build-release-task` + the four
`build-*-task`).
- `validate-release` entry gate (from #213/#215, smoke-skip from #219)
**stays** as the backstop.
NBGV source confirms the knob: `BuildingRef => IgnoreGitHubRef ? null :
env GITHUB_REF`.
## Verification
- `actionlint` (Docker) clean on all six changed workflows; CRLF
preserved.
- Per the issue's CI probe (real `dotnet/nbgv`): `develop` checkout +
`IGNORE_GITHUB_REF=true` → `PublicRelease=False`, `1.4.2-g…`; `main` →
`True`, `1.4.3`; `main` without the flag reproduces the bug.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ptr727
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Version each publish leg against its own branch; validate at entry - #215

Merged
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213
Jun 26, 2026
Merged

Version each publish leg against its own branch; validate at entry#215
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Problem

Closes#213. publish-release.yml dispatched from main builds a matrix of both main and develop. NBGV derives PublicRelease from the runner's GITHUB_REF, which is refs/heads/main for every leg regardless of the ref each leg checks out. So the develop leg is classified public, NBGV strips its -g<sha> prerelease suffix, and the develop NuGet package is published as a stable version (isPrerelease=false) — consumers can resolve a develop build as if stable. The GitHub release object stays prerelease:true, masking the bug.

Fix

  • get-version-task.yml: optional branch input pins the GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned (fallback to github.ref when empty). The mislabel originates in build-nugetlibrary-task's own get-version call, so branch is threaded from all five callers (build-release-task + the four build-*-task files).
  • Validate at entry: the late, one-directional "Verify public release version" step (main-only, mid-flow in github-release) is replaced by a single validate-release job that the build jobs needs:. It checks branch↔version consistency both directions — main must carry no prerelease -; every other branch must carry one (the Publish matrix mislabels the develop leg as a public release: NBGV drops the prerelease tag, NuGet package published as stable #213 regression guard) — and fails fast before the expensive builds.
  • Pattern: codified "validate input/state consistency at entry, fail fast" in AGENTS.md "Workflow YAML Conventions", generalizing the existing publish-docker-readme-task.yml "Validate inputs step".

Verification

  • actionlint (Docker) clean on all six changed workflows; markdownlint clean on AGENTS.md; CRLF preserved.
  • Live proof (post-merge): dispatch publish-release from main, confirm the develop leg's SemVer2 regains -g<sha> and the NuGet package is isPrerelease=true; validate-release fails a clean-X.Y.Z develop version.

🤖 Generated with Claude Code

Fixes#213. On a publish dispatched from the default branch, NBGV derives
PublicRelease from the runner's GITHUB_REF (= refs/heads/main for every matrix
leg), so the develop leg loses its -g<sha> prerelease suffix and its NuGet
package is published as a stable version (isPrerelease=false).
- get-version-task.yml gains an optional `branch` input that pins the
GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned, with a
github.ref fallback when empty. Threaded from all five callers
(build-release-task + the four build-*-task files).
- Replace the late, main-only "Verify public release version" step with a
single `validate-release` entry job that the build jobs needs:, checking
branch<->version consistency both directions (main must have no prerelease
suffix; every other branch must have one) and failing fast before builds.
- Codify the validate-input/state-consistency-at-entry pattern in AGENTS.md
"Workflow YAML Conventions".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a release-pipeline versioning bug where publish-release.yml runs from main but builds a main+develop matrix, causing NBGV to classify the develop leg as a public release and publish stable NuGet versions.

Changes:

  • Add an optional branch input to get-version-task.yml and pin GITHUB_REF/GITHUB_REF_NAME for the NBGV step to the leg being versioned.
  • Thread branch through all reusable-workflow callers of get-version-task.yml so every target versions against its intended branch.
  • Replace the late, one-directional main-only version check with an early validate-release job that enforces branch<->prerelease consistency for both main and non-main legs.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
AGENTS.mdDocuments the “validate invariants at entry, fail fast” workflow convention with concrete examples.
.github/workflows/get-version-task.ymlAdds branch input and pins env so NBGV classifies the correct leg branch during matrix publishes.
.github/workflows/build-release-task.ymlThreads branch into versioning and adds an entry validate-release job gating downstream build/release jobs.
.github/workflows/build-pypilibrary-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-nugetlibrary-task.ymlPasses inputs.branch to the shared get-version workflow (fixing the mislabel root cause for NuGet).
.github/workflows/build-executable-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-docker-task.ymlPasses inputs.branch to the shared get-version workflow.

@ptr727
ptr727 merged commit 5adbcb9 into developJun 26, 2026
10 checks passed
@ptr727
ptr727 deleted the feature/version-leg-prerelease-213 branch June 26, 2026 18:05
ptr727 added a commit that referenced this pull request Jun 27, 2026
## Problem
Closes#219. The `validate-release` entry gate (added in #213/#215) runs
**unconditionally**, including in PR **smoke** builds. A smoke build
checks out the PR head in detached HEAD, so NBGV always computes a
prerelease version (`X.Y.Z-g<sha>`). On a **main-base** PR — a `develop
→ main` promotion carrying a build target — the gate's `branch ==
'main'` arm fails:
```
::error::Public (main) release version 'X.Y.Z-g<sha>' carries a prerelease suffix; refusing to publish.
```
`validate-release` fails → `build` is skipped → the required `Check pull
request workflow status` fails. **Every clean `develop → main` promotion
PR that includes a build-target change is blocked by its own smoke
build** (masked only when merged via admin bypass).
## Fix
Skip the gate for smoke builds — they never publish — keeping the job in
the graph as a **success** so `build-*`'s `needs: [get-version,
validate-release]` stays satisfied:
```yaml
SMOKE: ${{ inputs.smoke }}
...
if [[ "$SMOKE" == "true" ]]; then
echo "Smoke build; skipping release version validation."
exit 0
fi
```
Real publishes (`smoke: false`) still get both-direction validation.
## Verification
- `actionlint` (Docker, shellcheck-bundled) clean; CRLF preserved.
- Per the issue's push-probe: a `smoke: true` invocation passes for both
`branch: main` (Release) and `branch: develop` (Debug) with
`github-release` skipped; real publishes unaffected.
Found via end-to-end CI flow validation during the #213/#214 downstream
re-sync.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ptr727 added a commit that referenced this pull request Jun 27, 2026
…ride (#222)
## Problem
Closes#221; supersedes the mechanism from #215. The #213 fix (PR #215)
restored the develop leg's prerelease tag by overriding `GITHUB_REF` in
the nbgv step `env:`. **It doesn't work.** `GITHUB_REF` is
GitHub-reserved — a step-level `env:` can't reliably override it (the
runner re-injects the dispatch ref). NBGV's GitHub Actions cloud-build
provider reads `GITHUB_REF` for `BuildingRef`, so on a publish
dispatched from `main` the develop leg was still classified public and
would publish a **clean (stable)** version.
CI evidence from the first real publish after #215:
```
GITHUB_REF: refs/heads/develop # the step-env override (as configured)
"BuildingRef": "refs/heads/main" # NBGV still saw the dispatch ref
"PublicRelease": true
"SemVer2": "1.4.2" # clean, no -g suffix
```
(The `validate-release` gate correctly blocked the bad publish, so
nothing shipped — but the develop prerelease leg never publishes.)
## Fix
NBGV versions from the **checked-out branch** unless its cloud provider
overrides with `GITHUB_REF`. Each matrix leg already checks out its own
branch, so set NBGV's own `IGNORE_GITHUB_REF=true` to make it ignore the
CI ref:
```yaml
- name: Run Nerdbank.GitVersioning tool step
id: nbgv
uses: dotnet/nbgv@master
env:
IGNORE_GITHUB_REF: true
```
- Removed the ineffective `GITHUB_REF`/`GITHUB_REF_NAME` override.
- Dropped the now-useless `branch` input from `get-version-task.yml` and
its threading from all five callers (`build-release-task` + the four
`build-*-task`).
- `validate-release` entry gate (from #213/#215, smoke-skip from #219)
**stays** as the backstop.
NBGV source confirms the knob: `BuildingRef => IgnoreGitHubRef ? null :
env GITHUB_REF`.
## Verification
- `actionlint` (Docker) clean on all six changed workflows; CRLF
preserved.
- Per the issue's CI probe (real `dotnet/nbgv`): `develop` checkout +
`IGNORE_GITHUB_REF=true` → `PublicRelease=False`, `1.4.2-g…`; `main` →
`True`, `1.4.3`; `main` without the flag reproduces the bug.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ptr727
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Version each publish leg against its own branch; validate at entry - #215

Merged
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213
Jun 26, 2026
Merged

Version each publish leg against its own branch; validate at entry#215
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Problem

Closes#213. publish-release.yml dispatched from main builds a matrix of both main and develop. NBGV derives PublicRelease from the runner's GITHUB_REF, which is refs/heads/main for every leg regardless of the ref each leg checks out. So the develop leg is classified public, NBGV strips its -g<sha> prerelease suffix, and the develop NuGet package is published as a stable version (isPrerelease=false) — consumers can resolve a develop build as if stable. The GitHub release object stays prerelease:true, masking the bug.

Fix

  • get-version-task.yml: optional branch input pins the GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned (fallback to github.ref when empty). The mislabel originates in build-nugetlibrary-task's own get-version call, so branch is threaded from all five callers (build-release-task + the four build-*-task files).
  • Validate at entry: the late, one-directional "Verify public release version" step (main-only, mid-flow in github-release) is replaced by a single validate-release job that the build jobs needs:. It checks branch↔version consistency both directions — main must carry no prerelease -; every other branch must carry one (the Publish matrix mislabels the develop leg as a public release: NBGV drops the prerelease tag, NuGet package published as stable #213 regression guard) — and fails fast before the expensive builds.
  • Pattern: codified "validate input/state consistency at entry, fail fast" in AGENTS.md "Workflow YAML Conventions", generalizing the existing publish-docker-readme-task.yml "Validate inputs step".

Verification

  • actionlint (Docker) clean on all six changed workflows; markdownlint clean on AGENTS.md; CRLF preserved.
  • Live proof (post-merge): dispatch publish-release from main, confirm the develop leg's SemVer2 regains -g<sha> and the NuGet package is isPrerelease=true; validate-release fails a clean-X.Y.Z develop version.

🤖 Generated with Claude Code

Fixes#213. On a publish dispatched from the default branch, NBGV derives
PublicRelease from the runner's GITHUB_REF (= refs/heads/main for every matrix
leg), so the develop leg loses its -g<sha> prerelease suffix and its NuGet
package is published as a stable version (isPrerelease=false).
- get-version-task.yml gains an optional `branch` input that pins the
GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned, with a
github.ref fallback when empty. Threaded from all five callers
(build-release-task + the four build-*-task files).
- Replace the late, main-only "Verify public release version" step with a
single `validate-release` entry job that the build jobs needs:, checking
branch<->version consistency both directions (main must have no prerelease
suffix; every other branch must have one) and failing fast before builds.
- Codify the validate-input/state-consistency-at-entry pattern in AGENTS.md
"Workflow YAML Conventions".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a release-pipeline versioning bug where publish-release.yml runs from main but builds a main+develop matrix, causing NBGV to classify the develop leg as a public release and publish stable NuGet versions.

Changes:

  • Add an optional branch input to get-version-task.yml and pin GITHUB_REF/GITHUB_REF_NAME for the NBGV step to the leg being versioned.
  • Thread branch through all reusable-workflow callers of get-version-task.yml so every target versions against its intended branch.
  • Replace the late, one-directional main-only version check with an early validate-release job that enforces branch<->prerelease consistency for both main and non-main legs.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
AGENTS.mdDocuments the “validate invariants at entry, fail fast” workflow convention with concrete examples.
.github/workflows/get-version-task.ymlAdds branch input and pins env so NBGV classifies the correct leg branch during matrix publishes.
.github/workflows/build-release-task.ymlThreads branch into versioning and adds an entry validate-release job gating downstream build/release jobs.
.github/workflows/build-pypilibrary-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-nugetlibrary-task.ymlPasses inputs.branch to the shared get-version workflow (fixing the mislabel root cause for NuGet).
.github/workflows/build-executable-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-docker-task.ymlPasses inputs.branch to the shared get-version workflow.

@ptr727
ptr727 merged commit 5adbcb9 into developJun 26, 2026
10 checks passed
@ptr727
ptr727 deleted the feature/version-leg-prerelease-213 branch June 26, 2026 18:05
ptr727 added a commit that referenced this pull request Jun 27, 2026
## Problem
Closes#219. The `validate-release` entry gate (added in #213/#215) runs
**unconditionally**, including in PR **smoke** builds. A smoke build
checks out the PR head in detached HEAD, so NBGV always computes a
prerelease version (`X.Y.Z-g<sha>`). On a **main-base** PR — a `develop
→ main` promotion carrying a build target — the gate's `branch ==
'main'` arm fails:
```
::error::Public (main) release version 'X.Y.Z-g<sha>' carries a prerelease suffix; refusing to publish.
```
`validate-release` fails → `build` is skipped → the required `Check pull
request workflow status` fails. **Every clean `develop → main` promotion
PR that includes a build-target change is blocked by its own smoke
build** (masked only when merged via admin bypass).
## Fix
Skip the gate for smoke builds — they never publish — keeping the job in
the graph as a **success** so `build-*`'s `needs: [get-version,
validate-release]` stays satisfied:
```yaml
SMOKE: ${{ inputs.smoke }}
...
if [[ "$SMOKE" == "true" ]]; then
echo "Smoke build; skipping release version validation."
exit 0
fi
```
Real publishes (`smoke: false`) still get both-direction validation.
## Verification
- `actionlint` (Docker, shellcheck-bundled) clean; CRLF preserved.
- Per the issue's push-probe: a `smoke: true` invocation passes for both
`branch: main` (Release) and `branch: develop` (Debug) with
`github-release` skipped; real publishes unaffected.
Found via end-to-end CI flow validation during the #213/#214 downstream
re-sync.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ptr727 added a commit that referenced this pull request Jun 27, 2026
…ride (#222)
## Problem
Closes#221; supersedes the mechanism from #215. The #213 fix (PR #215)
restored the develop leg's prerelease tag by overriding `GITHUB_REF` in
the nbgv step `env:`. **It doesn't work.** `GITHUB_REF` is
GitHub-reserved — a step-level `env:` can't reliably override it (the
runner re-injects the dispatch ref). NBGV's GitHub Actions cloud-build
provider reads `GITHUB_REF` for `BuildingRef`, so on a publish
dispatched from `main` the develop leg was still classified public and
would publish a **clean (stable)** version.
CI evidence from the first real publish after #215:
```
GITHUB_REF: refs/heads/develop # the step-env override (as configured)
"BuildingRef": "refs/heads/main" # NBGV still saw the dispatch ref
"PublicRelease": true
"SemVer2": "1.4.2" # clean, no -g suffix
```
(The `validate-release` gate correctly blocked the bad publish, so
nothing shipped — but the develop prerelease leg never publishes.)
## Fix
NBGV versions from the **checked-out branch** unless its cloud provider
overrides with `GITHUB_REF`. Each matrix leg already checks out its own
branch, so set NBGV's own `IGNORE_GITHUB_REF=true` to make it ignore the
CI ref:
```yaml
- name: Run Nerdbank.GitVersioning tool step
id: nbgv
uses: dotnet/nbgv@master
env:
IGNORE_GITHUB_REF: true
```
- Removed the ineffective `GITHUB_REF`/`GITHUB_REF_NAME` override.
- Dropped the now-useless `branch` input from `get-version-task.yml` and
its threading from all five callers (`build-release-task` + the four
`build-*-task`).
- `validate-release` entry gate (from #213/#215, smoke-skip from #219)
**stays** as the backstop.
NBGV source confirms the knob: `BuildingRef => IgnoreGitHubRef ? null :
env GITHUB_REF`.
## Verification
- `actionlint` (Docker) clean on all six changed workflows; CRLF
preserved.
- Per the issue's CI probe (real `dotnet/nbgv`): `develop` checkout +
`IGNORE_GITHUB_REF=true` → `PublicRelease=False`, `1.4.2-g…`; `main` →
`True`, `1.4.3`; `main` without the flag reproduces the bug.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ptr727
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Version each publish leg against its own branch; validate at entry - #215

Merged
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213
Jun 26, 2026
Merged

Version each publish leg against its own branch; validate at entry#215
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Problem

Closes#213. publish-release.yml dispatched from main builds a matrix of both main and develop. NBGV derives PublicRelease from the runner's GITHUB_REF, which is refs/heads/main for every leg regardless of the ref each leg checks out. So the develop leg is classified public, NBGV strips its -g<sha> prerelease suffix, and the develop NuGet package is published as a stable version (isPrerelease=false) — consumers can resolve a develop build as if stable. The GitHub release object stays prerelease:true, masking the bug.

Fix

  • get-version-task.yml: optional branch input pins the GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned (fallback to github.ref when empty). The mislabel originates in build-nugetlibrary-task's own get-version call, so branch is threaded from all five callers (build-release-task + the four build-*-task files).
  • Validate at entry: the late, one-directional "Verify public release version" step (main-only, mid-flow in github-release) is replaced by a single validate-release job that the build jobs needs:. It checks branch↔version consistency both directions — main must carry no prerelease -; every other branch must carry one (the Publish matrix mislabels the develop leg as a public release: NBGV drops the prerelease tag, NuGet package published as stable #213 regression guard) — and fails fast before the expensive builds.
  • Pattern: codified "validate input/state consistency at entry, fail fast" in AGENTS.md "Workflow YAML Conventions", generalizing the existing publish-docker-readme-task.yml "Validate inputs step".

Verification

  • actionlint (Docker) clean on all six changed workflows; markdownlint clean on AGENTS.md; CRLF preserved.
  • Live proof (post-merge): dispatch publish-release from main, confirm the develop leg's SemVer2 regains -g<sha> and the NuGet package is isPrerelease=true; validate-release fails a clean-X.Y.Z develop version.

🤖 Generated with Claude Code

Fixes#213. On a publish dispatched from the default branch, NBGV derives
PublicRelease from the runner's GITHUB_REF (= refs/heads/main for every matrix
leg), so the develop leg loses its -g<sha> prerelease suffix and its NuGet
package is published as a stable version (isPrerelease=false).
- get-version-task.yml gains an optional `branch` input that pins the
GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned, with a
github.ref fallback when empty. Threaded from all five callers
(build-release-task + the four build-*-task files).
- Replace the late, main-only "Verify public release version" step with a
single `validate-release` entry job that the build jobs needs:, checking
branch<->version consistency both directions (main must have no prerelease
suffix; every other branch must have one) and failing fast before builds.
- Codify the validate-input/state-consistency-at-entry pattern in AGENTS.md
"Workflow YAML Conventions".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a release-pipeline versioning bug where publish-release.yml runs from main but builds a main+develop matrix, causing NBGV to classify the develop leg as a public release and publish stable NuGet versions.

Changes:

  • Add an optional branch input to get-version-task.yml and pin GITHUB_REF/GITHUB_REF_NAME for the NBGV step to the leg being versioned.
  • Thread branch through all reusable-workflow callers of get-version-task.yml so every target versions against its intended branch.
  • Replace the late, one-directional main-only version check with an early validate-release job that enforces branch<->prerelease consistency for both main and non-main legs.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
AGENTS.mdDocuments the “validate invariants at entry, fail fast” workflow convention with concrete examples.
.github/workflows/get-version-task.ymlAdds branch input and pins env so NBGV classifies the correct leg branch during matrix publishes.
.github/workflows/build-release-task.ymlThreads branch into versioning and adds an entry validate-release job gating downstream build/release jobs.
.github/workflows/build-pypilibrary-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-nugetlibrary-task.ymlPasses inputs.branch to the shared get-version workflow (fixing the mislabel root cause for NuGet).
.github/workflows/build-executable-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-docker-task.ymlPasses inputs.branch to the shared get-version workflow.

@ptr727
ptr727 merged commit 5adbcb9 into developJun 26, 2026
10 checks passed
@ptr727
ptr727 deleted the feature/version-leg-prerelease-213 branch June 26, 2026 18:05
ptr727 added a commit that referenced this pull request Jun 27, 2026
## Problem
Closes#219. The `validate-release` entry gate (added in #213/#215) runs
**unconditionally**, including in PR **smoke** builds. A smoke build
checks out the PR head in detached HEAD, so NBGV always computes a
prerelease version (`X.Y.Z-g<sha>`). On a **main-base** PR — a `develop
→ main` promotion carrying a build target — the gate's `branch ==
'main'` arm fails:
```
::error::Public (main) release version 'X.Y.Z-g<sha>' carries a prerelease suffix; refusing to publish.
```
`validate-release` fails → `build` is skipped → the required `Check pull
request workflow status` fails. **Every clean `develop → main` promotion
PR that includes a build-target change is blocked by its own smoke
build** (masked only when merged via admin bypass).
## Fix
Skip the gate for smoke builds — they never publish — keeping the job in
the graph as a **success** so `build-*`'s `needs: [get-version,
validate-release]` stays satisfied:
```yaml
SMOKE: ${{ inputs.smoke }}
...
if [[ "$SMOKE" == "true" ]]; then
echo "Smoke build; skipping release version validation."
exit 0
fi
```
Real publishes (`smoke: false`) still get both-direction validation.
## Verification
- `actionlint` (Docker, shellcheck-bundled) clean; CRLF preserved.
- Per the issue's push-probe: a `smoke: true` invocation passes for both
`branch: main` (Release) and `branch: develop` (Debug) with
`github-release` skipped; real publishes unaffected.
Found via end-to-end CI flow validation during the #213/#214 downstream
re-sync.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ptr727 added a commit that referenced this pull request Jun 27, 2026
…ride (#222)
## Problem
Closes#221; supersedes the mechanism from #215. The #213 fix (PR #215)
restored the develop leg's prerelease tag by overriding `GITHUB_REF` in
the nbgv step `env:`. **It doesn't work.** `GITHUB_REF` is
GitHub-reserved — a step-level `env:` can't reliably override it (the
runner re-injects the dispatch ref). NBGV's GitHub Actions cloud-build
provider reads `GITHUB_REF` for `BuildingRef`, so on a publish
dispatched from `main` the develop leg was still classified public and
would publish a **clean (stable)** version.
CI evidence from the first real publish after #215:
```
GITHUB_REF: refs/heads/develop # the step-env override (as configured)
"BuildingRef": "refs/heads/main" # NBGV still saw the dispatch ref
"PublicRelease": true
"SemVer2": "1.4.2" # clean, no -g suffix
```
(The `validate-release` gate correctly blocked the bad publish, so
nothing shipped — but the develop prerelease leg never publishes.)
## Fix
NBGV versions from the **checked-out branch** unless its cloud provider
overrides with `GITHUB_REF`. Each matrix leg already checks out its own
branch, so set NBGV's own `IGNORE_GITHUB_REF=true` to make it ignore the
CI ref:
```yaml
- name: Run Nerdbank.GitVersioning tool step
id: nbgv
uses: dotnet/nbgv@master
env:
IGNORE_GITHUB_REF: true
```
- Removed the ineffective `GITHUB_REF`/`GITHUB_REF_NAME` override.
- Dropped the now-useless `branch` input from `get-version-task.yml` and
its threading from all five callers (`build-release-task` + the four
`build-*-task`).
- `validate-release` entry gate (from #213/#215, smoke-skip from #219)
**stays** as the backstop.
NBGV source confirms the knob: `BuildingRef => IgnoreGitHubRef ? null :
env GITHUB_REF`.
## Verification
- `actionlint` (Docker) clean on all six changed workflows; CRLF
preserved.
- Per the issue's CI probe (real `dotnet/nbgv`): `develop` checkout +
`IGNORE_GITHUB_REF=true` → `PublicRelease=False`, `1.4.2-g…`; `main` →
`True`, `1.4.3`; `main` without the flag reproduces the bug.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ptr727
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Version each publish leg against its own branch; validate at entry - #215

Merged
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213
Jun 26, 2026
Merged

Version each publish leg against its own branch; validate at entry#215
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Problem

Closes#213. publish-release.yml dispatched from main builds a matrix of both main and develop. NBGV derives PublicRelease from the runner's GITHUB_REF, which is refs/heads/main for every leg regardless of the ref each leg checks out. So the develop leg is classified public, NBGV strips its -g<sha> prerelease suffix, and the develop NuGet package is published as a stable version (isPrerelease=false) — consumers can resolve a develop build as if stable. The GitHub release object stays prerelease:true, masking the bug.

Fix

  • get-version-task.yml: optional branch input pins the GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned (fallback to github.ref when empty). The mislabel originates in build-nugetlibrary-task's own get-version call, so branch is threaded from all five callers (build-release-task + the four build-*-task files).
  • Validate at entry: the late, one-directional "Verify public release version" step (main-only, mid-flow in github-release) is replaced by a single validate-release job that the build jobs needs:. It checks branch↔version consistency both directions — main must carry no prerelease -; every other branch must carry one (the Publish matrix mislabels the develop leg as a public release: NBGV drops the prerelease tag, NuGet package published as stable #213 regression guard) — and fails fast before the expensive builds.
  • Pattern: codified "validate input/state consistency at entry, fail fast" in AGENTS.md "Workflow YAML Conventions", generalizing the existing publish-docker-readme-task.yml "Validate inputs step".

Verification

  • actionlint (Docker) clean on all six changed workflows; markdownlint clean on AGENTS.md; CRLF preserved.
  • Live proof (post-merge): dispatch publish-release from main, confirm the develop leg's SemVer2 regains -g<sha> and the NuGet package is isPrerelease=true; validate-release fails a clean-X.Y.Z develop version.

🤖 Generated with Claude Code

Fixes#213. On a publish dispatched from the default branch, NBGV derives
PublicRelease from the runner's GITHUB_REF (= refs/heads/main for every matrix
leg), so the develop leg loses its -g<sha> prerelease suffix and its NuGet
package is published as a stable version (isPrerelease=false).
- get-version-task.yml gains an optional `branch` input that pins the
GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned, with a
github.ref fallback when empty. Threaded from all five callers
(build-release-task + the four build-*-task files).
- Replace the late, main-only "Verify public release version" step with a
single `validate-release` entry job that the build jobs needs:, checking
branch<->version consistency both directions (main must have no prerelease
suffix; every other branch must have one) and failing fast before builds.
- Codify the validate-input/state-consistency-at-entry pattern in AGENTS.md
"Workflow YAML Conventions".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a release-pipeline versioning bug where publish-release.yml runs from main but builds a main+develop matrix, causing NBGV to classify the develop leg as a public release and publish stable NuGet versions.

Changes:

  • Add an optional branch input to get-version-task.yml and pin GITHUB_REF/GITHUB_REF_NAME for the NBGV step to the leg being versioned.
  • Thread branch through all reusable-workflow callers of get-version-task.yml so every target versions against its intended branch.
  • Replace the late, one-directional main-only version check with an early validate-release job that enforces branch<->prerelease consistency for both main and non-main legs.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
AGENTS.mdDocuments the “validate invariants at entry, fail fast” workflow convention with concrete examples.
.github/workflows/get-version-task.ymlAdds branch input and pins env so NBGV classifies the correct leg branch during matrix publishes.
.github/workflows/build-release-task.ymlThreads branch into versioning and adds an entry validate-release job gating downstream build/release jobs.
.github/workflows/build-pypilibrary-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-nugetlibrary-task.ymlPasses inputs.branch to the shared get-version workflow (fixing the mislabel root cause for NuGet).
.github/workflows/build-executable-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-docker-task.ymlPasses inputs.branch to the shared get-version workflow.

@ptr727
ptr727 merged commit 5adbcb9 into developJun 26, 2026
10 checks passed
@ptr727
ptr727 deleted the feature/version-leg-prerelease-213 branch June 26, 2026 18:05
ptr727 added a commit that referenced this pull request Jun 27, 2026
## Problem
Closes#219. The `validate-release` entry gate (added in #213/#215) runs
**unconditionally**, including in PR **smoke** builds. A smoke build
checks out the PR head in detached HEAD, so NBGV always computes a
prerelease version (`X.Y.Z-g<sha>`). On a **main-base** PR — a `develop
→ main` promotion carrying a build target — the gate's `branch ==
'main'` arm fails:
```
::error::Public (main) release version 'X.Y.Z-g<sha>' carries a prerelease suffix; refusing to publish.
```
`validate-release` fails → `build` is skipped → the required `Check pull
request workflow status` fails. **Every clean `develop → main` promotion
PR that includes a build-target change is blocked by its own smoke
build** (masked only when merged via admin bypass).
## Fix
Skip the gate for smoke builds — they never publish — keeping the job in
the graph as a **success** so `build-*`'s `needs: [get-version,
validate-release]` stays satisfied:
```yaml
SMOKE: ${{ inputs.smoke }}
...
if [[ "$SMOKE" == "true" ]]; then
echo "Smoke build; skipping release version validation."
exit 0
fi
```
Real publishes (`smoke: false`) still get both-direction validation.
## Verification
- `actionlint` (Docker, shellcheck-bundled) clean; CRLF preserved.
- Per the issue's push-probe: a `smoke: true` invocation passes for both
`branch: main` (Release) and `branch: develop` (Debug) with
`github-release` skipped; real publishes unaffected.
Found via end-to-end CI flow validation during the #213/#214 downstream
re-sync.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ptr727 added a commit that referenced this pull request Jun 27, 2026
…ride (#222)
## Problem
Closes#221; supersedes the mechanism from #215. The #213 fix (PR #215)
restored the develop leg's prerelease tag by overriding `GITHUB_REF` in
the nbgv step `env:`. **It doesn't work.** `GITHUB_REF` is
GitHub-reserved — a step-level `env:` can't reliably override it (the
runner re-injects the dispatch ref). NBGV's GitHub Actions cloud-build
provider reads `GITHUB_REF` for `BuildingRef`, so on a publish
dispatched from `main` the develop leg was still classified public and
would publish a **clean (stable)** version.
CI evidence from the first real publish after #215:
```
GITHUB_REF: refs/heads/develop # the step-env override (as configured)
"BuildingRef": "refs/heads/main" # NBGV still saw the dispatch ref
"PublicRelease": true
"SemVer2": "1.4.2" # clean, no -g suffix
```
(The `validate-release` gate correctly blocked the bad publish, so
nothing shipped — but the develop prerelease leg never publishes.)
## Fix
NBGV versions from the **checked-out branch** unless its cloud provider
overrides with `GITHUB_REF`. Each matrix leg already checks out its own
branch, so set NBGV's own `IGNORE_GITHUB_REF=true` to make it ignore the
CI ref:
```yaml
- name: Run Nerdbank.GitVersioning tool step
id: nbgv
uses: dotnet/nbgv@master
env:
IGNORE_GITHUB_REF: true
```
- Removed the ineffective `GITHUB_REF`/`GITHUB_REF_NAME` override.
- Dropped the now-useless `branch` input from `get-version-task.yml` and
its threading from all five callers (`build-release-task` + the four
`build-*-task`).
- `validate-release` entry gate (from #213/#215, smoke-skip from #219)
**stays** as the backstop.
NBGV source confirms the knob: `BuildingRef => IgnoreGitHubRef ? null :
env GITHUB_REF`.
## Verification
- `actionlint` (Docker) clean on all six changed workflows; CRLF
preserved.
- Per the issue's CI probe (real `dotnet/nbgv`): `develop` checkout +
`IGNORE_GITHUB_REF=true` → `PublicRelease=False`, `1.4.2-g…`; `main` →
`True`, `1.4.3`; `main` without the flag reproduces the bug.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ptr727
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Version each publish leg against its own branch; validate at entry - #215

Merged
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213
Jun 26, 2026
Merged

Version each publish leg against its own branch; validate at entry#215
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Problem

Closes#213. publish-release.yml dispatched from main builds a matrix of both main and develop. NBGV derives PublicRelease from the runner's GITHUB_REF, which is refs/heads/main for every leg regardless of the ref each leg checks out. So the develop leg is classified public, NBGV strips its -g<sha> prerelease suffix, and the develop NuGet package is published as a stable version (isPrerelease=false) — consumers can resolve a develop build as if stable. The GitHub release object stays prerelease:true, masking the bug.

Fix

  • get-version-task.yml: optional branch input pins the GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned (fallback to github.ref when empty). The mislabel originates in build-nugetlibrary-task's own get-version call, so branch is threaded from all five callers (build-release-task + the four build-*-task files).
  • Validate at entry: the late, one-directional "Verify public release version" step (main-only, mid-flow in github-release) is replaced by a single validate-release job that the build jobs needs:. It checks branch↔version consistency both directions — main must carry no prerelease -; every other branch must carry one (the Publish matrix mislabels the develop leg as a public release: NBGV drops the prerelease tag, NuGet package published as stable #213 regression guard) — and fails fast before the expensive builds.
  • Pattern: codified "validate input/state consistency at entry, fail fast" in AGENTS.md "Workflow YAML Conventions", generalizing the existing publish-docker-readme-task.yml "Validate inputs step".

Verification

  • actionlint (Docker) clean on all six changed workflows; markdownlint clean on AGENTS.md; CRLF preserved.
  • Live proof (post-merge): dispatch publish-release from main, confirm the develop leg's SemVer2 regains -g<sha> and the NuGet package is isPrerelease=true; validate-release fails a clean-X.Y.Z develop version.

🤖 Generated with Claude Code

Fixes#213. On a publish dispatched from the default branch, NBGV derives
PublicRelease from the runner's GITHUB_REF (= refs/heads/main for every matrix
leg), so the develop leg loses its -g<sha> prerelease suffix and its NuGet
package is published as a stable version (isPrerelease=false).
- get-version-task.yml gains an optional `branch` input that pins the
GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned, with a
github.ref fallback when empty. Threaded from all five callers
(build-release-task + the four build-*-task files).
- Replace the late, main-only "Verify public release version" step with a
single `validate-release` entry job that the build jobs needs:, checking
branch<->version consistency both directions (main must have no prerelease
suffix; every other branch must have one) and failing fast before builds.
- Codify the validate-input/state-consistency-at-entry pattern in AGENTS.md
"Workflow YAML Conventions".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a release-pipeline versioning bug where publish-release.yml runs from main but builds a main+develop matrix, causing NBGV to classify the develop leg as a public release and publish stable NuGet versions.

Changes:

  • Add an optional branch input to get-version-task.yml and pin GITHUB_REF/GITHUB_REF_NAME for the NBGV step to the leg being versioned.
  • Thread branch through all reusable-workflow callers of get-version-task.yml so every target versions against its intended branch.
  • Replace the late, one-directional main-only version check with an early validate-release job that enforces branch<->prerelease consistency for both main and non-main legs.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
AGENTS.mdDocuments the “validate invariants at entry, fail fast” workflow convention with concrete examples.
.github/workflows/get-version-task.ymlAdds branch input and pins env so NBGV classifies the correct leg branch during matrix publishes.
.github/workflows/build-release-task.ymlThreads branch into versioning and adds an entry validate-release job gating downstream build/release jobs.
.github/workflows/build-pypilibrary-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-nugetlibrary-task.ymlPasses inputs.branch to the shared get-version workflow (fixing the mislabel root cause for NuGet).
.github/workflows/build-executable-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-docker-task.ymlPasses inputs.branch to the shared get-version workflow.

@ptr727
ptr727 merged commit 5adbcb9 into developJun 26, 2026
10 checks passed
@ptr727
ptr727 deleted the feature/version-leg-prerelease-213 branch June 26, 2026 18:05
ptr727 added a commit that referenced this pull request Jun 27, 2026
## Problem
Closes#219. The `validate-release` entry gate (added in #213/#215) runs
**unconditionally**, including in PR **smoke** builds. A smoke build
checks out the PR head in detached HEAD, so NBGV always computes a
prerelease version (`X.Y.Z-g<sha>`). On a **main-base** PR — a `develop
→ main` promotion carrying a build target — the gate's `branch ==
'main'` arm fails:
```
::error::Public (main) release version 'X.Y.Z-g<sha>' carries a prerelease suffix; refusing to publish.
```
`validate-release` fails → `build` is skipped → the required `Check pull
request workflow status` fails. **Every clean `develop → main` promotion
PR that includes a build-target change is blocked by its own smoke
build** (masked only when merged via admin bypass).
## Fix
Skip the gate for smoke builds — they never publish — keeping the job in
the graph as a **success** so `build-*`'s `needs: [get-version,
validate-release]` stays satisfied:
```yaml
SMOKE: ${{ inputs.smoke }}
...
if [[ "$SMOKE" == "true" ]]; then
echo "Smoke build; skipping release version validation."
exit 0
fi
```
Real publishes (`smoke: false`) still get both-direction validation.
## Verification
- `actionlint` (Docker, shellcheck-bundled) clean; CRLF preserved.
- Per the issue's push-probe: a `smoke: true` invocation passes for both
`branch: main` (Release) and `branch: develop` (Debug) with
`github-release` skipped; real publishes unaffected.
Found via end-to-end CI flow validation during the #213/#214 downstream
re-sync.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ptr727 added a commit that referenced this pull request Jun 27, 2026
…ride (#222)
## Problem
Closes#221; supersedes the mechanism from #215. The #213 fix (PR #215)
restored the develop leg's prerelease tag by overriding `GITHUB_REF` in
the nbgv step `env:`. **It doesn't work.** `GITHUB_REF` is
GitHub-reserved — a step-level `env:` can't reliably override it (the
runner re-injects the dispatch ref). NBGV's GitHub Actions cloud-build
provider reads `GITHUB_REF` for `BuildingRef`, so on a publish
dispatched from `main` the develop leg was still classified public and
would publish a **clean (stable)** version.
CI evidence from the first real publish after #215:
```
GITHUB_REF: refs/heads/develop # the step-env override (as configured)
"BuildingRef": "refs/heads/main" # NBGV still saw the dispatch ref
"PublicRelease": true
"SemVer2": "1.4.2" # clean, no -g suffix
```
(The `validate-release` gate correctly blocked the bad publish, so
nothing shipped — but the develop prerelease leg never publishes.)
## Fix
NBGV versions from the **checked-out branch** unless its cloud provider
overrides with `GITHUB_REF`. Each matrix leg already checks out its own
branch, so set NBGV's own `IGNORE_GITHUB_REF=true` to make it ignore the
CI ref:
```yaml
- name: Run Nerdbank.GitVersioning tool step
id: nbgv
uses: dotnet/nbgv@master
env:
IGNORE_GITHUB_REF: true
```
- Removed the ineffective `GITHUB_REF`/`GITHUB_REF_NAME` override.
- Dropped the now-useless `branch` input from `get-version-task.yml` and
its threading from all five callers (`build-release-task` + the four
`build-*-task`).
- `validate-release` entry gate (from #213/#215, smoke-skip from #219)
**stays** as the backstop.
NBGV source confirms the knob: `BuildingRef => IgnoreGitHubRef ? null :
env GITHUB_REF`.
## Verification
- `actionlint` (Docker) clean on all six changed workflows; CRLF
preserved.
- Per the issue's CI probe (real `dotnet/nbgv`): `develop` checkout +
`IGNORE_GITHUB_REF=true` → `PublicRelease=False`, `1.4.2-g…`; `main` →
`True`, `1.4.3`; `main` without the flag reproduces the bug.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ptr727
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Version each publish leg against its own branch; validate at entry - #215

Merged
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213
Jun 26, 2026
Merged

Version each publish leg against its own branch; validate at entry#215
ptr727 merged 1 commit into
developfrom
feature/version-leg-prerelease-213

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Problem

Closes#213. publish-release.yml dispatched from main builds a matrix of both main and develop. NBGV derives PublicRelease from the runner's GITHUB_REF, which is refs/heads/main for every leg regardless of the ref each leg checks out. So the develop leg is classified public, NBGV strips its -g<sha> prerelease suffix, and the develop NuGet package is published as a stable version (isPrerelease=false) — consumers can resolve a develop build as if stable. The GitHub release object stays prerelease:true, masking the bug.

Fix

  • get-version-task.yml: optional branch input pins the GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned (fallback to github.ref when empty). The mislabel originates in build-nugetlibrary-task's own get-version call, so branch is threaded from all five callers (build-release-task + the four build-*-task files).
  • Validate at entry: the late, one-directional "Verify public release version" step (main-only, mid-flow in github-release) is replaced by a single validate-release job that the build jobs needs:. It checks branch↔version consistency both directions — main must carry no prerelease -; every other branch must carry one (the Publish matrix mislabels the develop leg as a public release: NBGV drops the prerelease tag, NuGet package published as stable #213 regression guard) — and fails fast before the expensive builds.
  • Pattern: codified "validate input/state consistency at entry, fail fast" in AGENTS.md "Workflow YAML Conventions", generalizing the existing publish-docker-readme-task.yml "Validate inputs step".

Verification

  • actionlint (Docker) clean on all six changed workflows; markdownlint clean on AGENTS.md; CRLF preserved.
  • Live proof (post-merge): dispatch publish-release from main, confirm the develop leg's SemVer2 regains -g<sha> and the NuGet package is isPrerelease=true; validate-release fails a clean-X.Y.Z develop version.

🤖 Generated with Claude Code

Fixes#213. On a publish dispatched from the default branch, NBGV derives
PublicRelease from the runner's GITHUB_REF (= refs/heads/main for every matrix
leg), so the develop leg loses its -g<sha> prerelease suffix and its NuGet
package is published as a stable version (isPrerelease=false).
- get-version-task.yml gains an optional `branch` input that pins the
GITHUB_REF/GITHUB_REF_NAME NBGV reads to the leg being versioned, with a
github.ref fallback when empty. Threaded from all five callers
(build-release-task + the four build-*-task files).
- Replace the late, main-only "Verify public release version" step with a
single `validate-release` entry job that the build jobs needs:, checking
branch<->version consistency both directions (main must have no prerelease
suffix; every other branch must have one) and failing fast before builds.
- Codify the validate-input/state-consistency-at-entry pattern in AGENTS.md
"Workflow YAML Conventions".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a release-pipeline versioning bug where publish-release.yml runs from main but builds a main+develop matrix, causing NBGV to classify the develop leg as a public release and publish stable NuGet versions.

Changes:

  • Add an optional branch input to get-version-task.yml and pin GITHUB_REF/GITHUB_REF_NAME for the NBGV step to the leg being versioned.
  • Thread branch through all reusable-workflow callers of get-version-task.yml so every target versions against its intended branch.
  • Replace the late, one-directional main-only version check with an early validate-release job that enforces branch<->prerelease consistency for both main and non-main legs.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
AGENTS.mdDocuments the “validate invariants at entry, fail fast” workflow convention with concrete examples.
.github/workflows/get-version-task.ymlAdds branch input and pins env so NBGV classifies the correct leg branch during matrix publishes.
.github/workflows/build-release-task.ymlThreads branch into versioning and adds an entry validate-release job gating downstream build/release jobs.
.github/workflows/build-pypilibrary-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-nugetlibrary-task.ymlPasses inputs.branch to the shared get-version workflow (fixing the mislabel root cause for NuGet).
.github/workflows/build-executable-task.ymlPasses inputs.branch to the shared get-version workflow.
.github/workflows/build-docker-task.ymlPasses inputs.branch to the shared get-version workflow.

@ptr727
ptr727 merged commit 5adbcb9 into developJun 26, 2026
10 checks passed
@ptr727
ptr727 deleted the feature/version-leg-prerelease-213 branch June 26, 2026 18:05
ptr727 added a commit that referenced this pull request Jun 27, 2026
## Problem
Closes#219. The `validate-release` entry gate (added in #213/#215) runs
**unconditionally**, including in PR **smoke** builds. A smoke build
checks out the PR head in detached HEAD, so NBGV always computes a
prerelease version (`X.Y.Z-g<sha>`). On a **main-base** PR — a `develop
→ main` promotion carrying a build target — the gate's `branch ==
'main'` arm fails:
```
::error::Public (main) release version 'X.Y.Z-g<sha>' carries a prerelease suffix; refusing to publish.
```
`validate-release` fails → `build` is skipped → the required `Check pull
request workflow status` fails. **Every clean `develop → main` promotion
PR that includes a build-target change is blocked by its own smoke
build** (masked only when merged via admin bypass).
## Fix
Skip the gate for smoke builds — they never publish — keeping the job in
the graph as a **success** so `build-*`'s `needs: [get-version,
validate-release]` stays satisfied:
```yaml
SMOKE: ${{ inputs.smoke }}
...
if [[ "$SMOKE" == "true" ]]; then
echo "Smoke build; skipping release version validation."
exit 0
fi
```
Real publishes (`smoke: false`) still get both-direction validation.
## Verification
- `actionlint` (Docker, shellcheck-bundled) clean; CRLF preserved.
- Per the issue's push-probe: a `smoke: true` invocation passes for both
`branch: main` (Release) and `branch: develop` (Debug) with
`github-release` skipped; real publishes unaffected.
Found via end-to-end CI flow validation during the #213/#214 downstream
re-sync.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ptr727 added a commit that referenced this pull request Jun 27, 2026
…ride (#222)
## Problem
Closes#221; supersedes the mechanism from #215. The #213 fix (PR #215)
restored the develop leg's prerelease tag by overriding `GITHUB_REF` in
the nbgv step `env:`. **It doesn't work.** `GITHUB_REF` is
GitHub-reserved — a step-level `env:` can't reliably override it (the
runner re-injects the dispatch ref). NBGV's GitHub Actions cloud-build
provider reads `GITHUB_REF` for `BuildingRef`, so on a publish
dispatched from `main` the develop leg was still classified public and
would publish a **clean (stable)** version.
CI evidence from the first real publish after #215:
```
GITHUB_REF: refs/heads/develop # the step-env override (as configured)
"BuildingRef": "refs/heads/main" # NBGV still saw the dispatch ref
"PublicRelease": true
"SemVer2": "1.4.2" # clean, no -g suffix
```
(The `validate-release` gate correctly blocked the bad publish, so
nothing shipped — but the develop prerelease leg never publishes.)
## Fix
NBGV versions from the **checked-out branch** unless its cloud provider
overrides with `GITHUB_REF`. Each matrix leg already checks out its own
branch, so set NBGV's own `IGNORE_GITHUB_REF=true` to make it ignore the
CI ref:
```yaml
- name: Run Nerdbank.GitVersioning tool step
id: nbgv
uses: dotnet/nbgv@master
env:
IGNORE_GITHUB_REF: true
```
- Removed the ineffective `GITHUB_REF`/`GITHUB_REF_NAME` override.
- Dropped the now-useless `branch` input from `get-version-task.yml` and
its threading from all five callers (`build-release-task` + the four
`build-*-task`).
- `validate-release` entry gate (from #213/#215, smoke-skip from #219)
**stays** as the backstop.
NBGV source confirms the knob: `BuildingRef => IgnoreGitHubRef ? null :
env GITHUB_REF`.
## Verification
- `actionlint` (Docker) clean on all six changed workflows; CRLF
preserved.
- Per the issue's CI probe (real `dotnet/nbgv`): `develop` checkout +
`IGNORE_GITHUB_REF=true` → `PublicRelease=False`, `1.4.2-g…`; `main` →
`True`, `1.4.3`; `main` without the flag reproduces the bug.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ptr727