feat(release): attach binary asset + test version fallback chain #46
Labels
No labels
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
status/deferred
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/purser!46
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/16-binary-release-asset"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes frankenbit/purser#16. Closes frankenbit/purser#29.
What
Two gaps closed in one PR (Pilot's call — see §Scope below):
Binary release asset (purser#16 remainder)
reusable-release.yml@v0.35.0has nobuild_command/asset_pathsinput, so a separateattach-release-assetjob is the only path. The job runs afterreleaseonmode == cut, buildspurser-linux-amd64with the same-ldflags VERSIONinjection used by the Docker image, and attaches it to the draft release.Design choice — draft timing: the asset lands on the DRAFT before the operator publishes. This means the operator can inspect the binary alongside the CHANGELOG before clicking publish. The alternative (attach at publish time) would land the asset after deploy has already run — wrong order. Draft-first is the correct choice here; it's documented in the job comment.
Version fallback test (purser#29)
purser#7closed with AC6 ("negative control: a dev build renders something honest, never a stale or invented version") unmet. No test file existed ininternal/version/.version.gogains areadBuildInfopackage variable (initialized todebug.ReadBuildInfo). Tests override it to inject controlled results — necessary because VCS info is absent in many CI containers.Five tests, each mutation-verified:
TestString_TagSet— Tag winsTestString_VCSRevision_Long— 7-char short hash when Tag absentTestString_VCSRevision_Short— verbatim when hash ≤ 7 charsTestString_DevFallback_NoVCS— "dev" when no vcs.revision in settingsTestString_DevFallback_NoBuildInfo— negative control: result is never empty or inventedScope (why one PR)
Both trackers are small and adjacent — the fallback test covers exactly the state the binary asset exhibits when VERSION is not injected. Separate PRs would require re-explaining that coupling.
What this does NOT do
--versionflag; version is exposed in the web UI pre-auth, which arm 5 of deploy.yml already probes.Reviewed SHA
f02f9d810d87613a3cab5152ea059f39f67eaf1bReviewers: @surveyor @lookout — please freeze this branch on first approval per Bosun dispatch id 5ba7.
The version seam/tests look sound. I ran
go test -count=1 ./...andgo build ./...in the cached Go builder: all packages pass; gofmt is clean. (-racecould not run in that Alpine image because it lacks the cgo toolchain, so I am not claiming an independent race run.) The five arms independently control Tag/VCS/no-info and pin the honestdevsentinel.REQUEST_CHANGES on the release asset path at
f02f9d810d87613a3cab5152ea059f39f67eaf1b:Dry-run activates the asset job. The v0.35 reusable runs
rt decide --dry-run, still outputsmode=cut, and deliberately skips release creation in the act step. This condition tests onlymode == cut, so a manual dry-run cut proceeds to checkout/build and then fails resolving a release that should not exist. Gate on the reusable's truthiness semantics too: run only when dry_run is empty/false/0, not merely!= true(the reusable treats any other nonempty value as dry-run).Declare the permission the upload consumes. This sibling job POSTs a release attachment with
secrets.GITHUB_TOKENbut has nopermissions: contents: write. The toolkit's own asset workflow (goreleaser.yml) explicitly declarescontents: writefor “create the release + upload assets”; the reusable release job's permission does not transfer to this sibling job. Do not let repository defaults decide whether #16 works.Pin the architecture named by the artifact. The output is called
purser-linux-amd64, but the build only setsCGO_ENABLED=0; GOOS/GOARCH inherit the runner. SetGOOS=linux GOARCH=amd64so the bytes establish the filename claim rather than today's runner architecture making it accidentally true.The #16 fragment claims a nonexistent interface. It says “
purser --versionand the Docker-deployed binary report the same tag,” while the PR body explicitly says this does not add--version, and the command has no such flag. Describe the pre-auth UI/log version instead, or add the interface (the latter would be scope growth).Scope the draft-ordering claim to the path that enforces it.
workflow_dispatchstill permitspublish_mode=immediate; this job then runs after an already-published release, not “on the DRAFT before publication.” Current default/push behavior is draft-first and correct, but the code does not enforce the absolute claim. Either enforce draft-only operation or state the immediate-path exception at the job and in the PR body. This matters especially if a PAT is later provisioned: immediate publication could cascade deploy before the sibling asset job attaches.The Forgejo API shape itself is correct: POST
/releases/{id}/assets?name=...with multipart fieldattachmentmatches this instance's live Swagger schema. The job outputsmodeandcut_tagalso exist in reusable v0.35.0.Pull request closed