Make release workflow reruns idempotent when release already exists#246
Conversation
If signing (or any step after "Create release") fails, the release + tag are created but empty. Previously every downstream step was guarded by EXISTS == 'false', so reruns short-circuited to a no-op and the only fix was to delete the empty release and tag before rerunning. Now only "Create release" itself is guarded; Setup .NET, Build and test, Publish, Sign, Velopack, and Package/upload always run. The final gh release upload uses --clobber, so rerunning against an existing release safely overwrites its assets. Happened during v1.7.0: first attempt timed out on SignPath approval, the rerun skipped all work because v1.7.0 already existed, and manual release+tag deletion was needed to unstick it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
erikdarlingdata
left a comment
There was a problem hiding this comment.
What it does
Drops the steps.check.outputs.EXISTS == 'false' gate from every step after Create release (Setup .NET → Build/test → Publish → signing chain → Velopack → Package/upload). Only Create release itself keeps the guard. Reruns after the release+tag are created now re-execute build/sign/upload instead of no-opping.
What's good
- Base branch is
dev. Correct. gh release upload ... --clobberat release.yml:184 makes the zip + SHA256SUMS upload safe to repeat.vpk upload ... --mergeat release.yml:187 handles the Velopack side.- Scope is minimal — no behavior change on the happy path.
Needs attention
- release.yml:78-84 —
actions/upload-artifact@v4rejects duplicate artifact names within a run. If the user hits "Re-run failed jobs" (same run, attempt 2) after a SignPath timeout — which is exactly the scenario described in the PR body — theApp-unsignedartifact from attempt 1 will collide. Addingoverwrite: truecloses this. A brand-new workflow run is unaffected, but the maintainer will likely reach for "Re-run failed jobs" first. Inline comment left. - release.yml:117-120 —
vpk download+vpk packfor the same$VERSIONon a rerun: if a prior attempt already uploaded Velopack assets,vpk downloadwill pull them back and treat v$VERSION as "previous" when packing v$VERSION. Not the failure mode this PR targets (sign-timeout halts before Velopack runs), so not blocking. Worth a quick sanity check that vpk tolerates that case before relying on rerun for failures past the Velopack step. - Test plan is "validate on next release cycle" — fine, given the alternative (forcing a failure) would re-upload artifacts on a shipped release.
No C#/XAML changes, so Avalonia/brush/MVVM/test-coverage checks are N/A.
Generated by Claude Code
| - name: Upload Windows build for signing | ||
| if: steps.check.outputs.EXISTS == 'false' && steps.signing.outputs.ENABLED == 'true' | ||
| if: steps.signing.outputs.ENABLED == 'true' | ||
| id: upload-unsigned | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: App-unsigned | ||
| path: publish/win-x64/ |
There was a problem hiding this comment.
actions/upload-artifact@v4 requires unique artifact names within a workflow run. The target failure scenario here is "SignPath times out on attempt 1, user reruns" — if that rerun is done via GitHub's "Re-run failed jobs" (same run, attempt 2), the prior attempt's App-unsigned artifact persists and this step will fail with an artifact with this name already exists. Consider adding overwrite: true here to make the rerun path fully idempotent. A fresh workflow_dispatch run is unaffected, but "Re-run failed jobs" is the more likely maintainer action.
Generated by Claude Code
Summary
Only `Create release` retains the `EXISTS == 'false'` guard. Every downstream step (Setup .NET, Build, Publish, Sign, Velopack, Package/upload) always runs. `gh release upload --clobber` on the final step safely overwrites existing assets on rerun.
Why
Happened during v1.7.0: first run timed out on SignPath approval after creating the release + tag, rerun skipped all work because v1.7.0 already existed. The only unblock was `gh release delete v1.7.0 --cleanup-tag` then rerun. After this change, a rerun after signing failure re-does the build + sign + upload and repopulates the empty release.
Test plan
🤖 Generated with Claude Code