fix(csharp): self-healing CI release pipeline for NuGet + GitHub#85
Conversation
Adding .gitkeep for PR creation (default mode). This file will be removed when the task is complete. Issue: #84
Compile run logs, NuGet/GitHub release state, and upstream template sources used to design the fix. Captures the HTTP 403 NuGet publish failure on attempt 1 of run 25757419575 and the silent no-op on attempt 2 that left csharp-v2.4.0 stuck (tag pushed, package missing, release missing).
Issue #84: a release was version-bumped, tagged, and pushed, but the NuGet publish step returned HTTP 403, leaving package clink stuck at 2.3.0 even though tag csharp-v2.4.0 and commit b52c8f1 were already on main. Re-runs short-circuited on the pre-existing tag/commit and never retried the publish. Port the self-healing pattern from js-ai-driven-development-pipeline-template's check-release-needed.mjs to C#: a new script probes the NuGet flat-container index plus the GitHub Releases endpoint for the csproj <Version>, and emits should_release / skip_bump signals. The release and instant-release jobs now gate every publish + GitHub-release step on the union of version_committed, already_released, and (should_release && skip_bump) so that a stalled deployment resumes on the next push to main without requiring a new changeset. An upfront "Validate NuGet API key" step also surfaces missing/expired secrets before any publish attempt. Tests: - csharp/scripts/release-scripts.test.mjs: 8 new tests covering the pure decide() function, csproj parsing, and the CLI end-to-end via a 127.0.0.1 mock for NuGet + GitHub Releases. - js/test/repositoryLayout.test.mjs: regression guard asserting the self-healing gates remain in csharp.yml (Check if release is needed step + 4+ should_release gates + 5+ already_released gates). - Remove the stray root .gitkeep that violated the existing repositoryLayout test. Refs: docs/case-studies/issue-84/README.md
Working session summaryAll CI checks pass. Final summary: Done — PR #85 ready for review
What the fix does: ports This summary was automatically extracted from the AI working session output. |
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost: $13.296221📊 Context and tokens usage:Claude Opus 4.7: (4 sub-sessions)
Total: (6.1K new + 381.4K cache writes + 16.3M cache reads) input tokens, 109.1K output tokens, $13.296221 cost 🤖 Models used:
📎 Log file uploaded as Gist (5410KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
🎉 Auto-mergedThis pull request has been automatically merged by hive-mind.
Auto-merged by hive-mind with --auto-merge flag |
Fixes #84
Summary
The C# release workflow was version-bumped, tagged, and pushed for
csharp-v2.4.0, butdotnet nuget pushreturned HTTP 403 mid-flight, soclinkon NuGet stayed at2.3.0and no GitHub release was created. The next push tomainshort-circuited on the pre-existing tag + version commit and never retried.This PR ports the self-healing release pattern from
js-ai-driven-development-pipeline-templateto C# and rewirescsharp.ymlto resume mid-failed releases on the next push tomain, without requiring a new changeset.Root cause
steps.version.outputs.version_committed == 'true'.version-and-commit.mjsreturnsalready_released=truewhen the bumped tag already exists, soversion_committedis'false'on every retry after the first run pushed the tag.NUGET_API_KEYwas never validated upfront; the expired key only surfaced mid-dotnet nuget push.Full timeline, evidence captures, and template comparison are in
docs/case-studies/issue-84/README.md(added in commit7f2be75).Changes
csharp/scripts/check-release-needed.mjs(new)Pure
decide()function plus async probes:https://api.nuget.org/v3-flatcontainer/{id-lower}/index.jsonfor the csproj<Version>(returnsnullon 404).GET /repos/{owner}/{repo}/releases/tags/csharp-v{version}for the matching GitHub release.Outputs to
GITHUB_OUTPUT:should_release,skip_bump,current_version,nuget_published,github_release_exists,reason. SupportsNUGET_INDEX_URL/GITHUB_API_URLoverrides for tests..github/workflows/csharp.ymlResolve release versionso downstream steps see the right<Version>even on self-healing reruns.if:conditions to the union:Verify package on NuGetandCreate GitHub Releasenow readsteps.release_version.outputs.versionso self-healing reruns publish the correct artifact.Tests
csharp/scripts/release-scripts.test.mjs: 8 new tests covering the puredecide()function, csproj parsing, and the CLI end-to-end via a127.0.0.1mock HTTP server for NuGet + GitHub probes. 12 tests total, all pass (~700ms).js/test/repositoryLayout.test.mjs: new regression guard asserting the self-healing gates remain incsharp.yml— the "Check if release is needed" step,check-release-needed.mjsinvocation, at least 4should_release && skip_bumpgates, and at least 5already_releasedgates. 21 tests total, all pass.Cleanup
.gitkeepthat violated the existingrepositoryLayouttest.Upstream report
The same defect class is present in
csharp-ai-driven-development-pipeline-template— filed issue #11 with the same diagnosis and a pointer back to this PR.Test plan
node --test js/test/*.test.mjs csharp/scripts/*.test.mjs→ 21/21 pass locally.python3 -c "import yaml; yaml.safe_load(open('.github/workflows/csharp.yml'))"→ valid YAML.gh pr diff 85for unintended deletions — only the narrowif:conditions and the broadenedexecFileimport.maintriggers the workflow;check-release-neededcorrectly reportsclink@2.4.0already on NuGet (once the manual republish or self-heal lands) and short-circuits — or, if2.4.0is still missing, it resumes the publish + GitHub release without a new changeset.References
docs/case-studies/issue-84/README.md