ci: automatic releases from develop, versioned by upstream - #9
Merged
Conversation
Releases needed a human to push a v* tag and a second human to click Publish on the resulting draft. Both steps are gone: a merge into develop now cuts the release by itself. The version is never chosen. `prepare` fetches pterodactyl/wings' tags into refs/upstream-tags/ (a private namespace, because our fork carries tags with the same names pointing at our own merge commits) and picks the newest stable one that is an ancestor of develop. That is precisely "which upstream version is in develop", so our releases keep carrying upstream's numbering with nothing to maintain by hand. Nothing becomes visible until everything is verified. The draft release holds only tag_name and target_commitish, so an aborted run leaves no tag behind; binary.yaml and docker.yaml attach their output to it; and only once both succeed does `publish` check the assets are all present, move :latest by digest and un-draft. A failure anywhere before that leaves the previous release and the previous :latest untouched, and /releases/latest ignores drafts throughout. docker.yaml had to become a workflow_call target. It listened on `release: published`, which only ever fired because a human clicked Publish — a release published with GITHUB_TOKEN triggers no workflow runs, so automating that click would have silently ended every image build. Also: - Empty release notes are now impossible: a missing CHANGELOG.md section fails the job instead of publishing a release with an empty body. The section match is anchored, so v1.13.2 no longer also matches v1.13.20. - Dropped the release/vX branch and its sed bump of system/const.go. It wrote a version into a branch nobody uses while the real version comes from ldflags, and a git push mid-release is exactly what breaks a second run. - Added SHA256SUMS, and a smoke test asserting the built binary reports the version it was built with rather than "develop". - Re-releasing a version is an explicit `force: true` dispatch. Deleting a release by hand deliberately does not resurrect it.
Release notes are extracted from the matching CHANGELOG.md section, so without this the release for v1.13.2 would carry an empty body.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Releases needed a human to push a
v*tag and a second human to click Publish on the resulting draft. Both steps are gone: a merge intodevelopnow cuts the release by itself, in the shapeemeraldhost/system-node-agentuses.The version is never chosen
system-node-agentderives its version from Conventional Commits via release-please. That is the exact opposite of what we need here, so the pipeline shape was kept and the version source replaced.preparefetchespterodactyl/wings' tags intorefs/upstream-tags/and picks the newest stable one that is an ancestor ofdevelop. Since we merge the upstream tag commit itself, that is precisely "which upstream version is in develop" — our releases keep carrying upstream's numbering, with nothing to maintain by hand and no way for it to drift.The private ref namespace is not cosmetic: our fork carries tags with the same names pointing at our own merge commits (our
v1.13.1isf7ba42d, upstream's ise771816), so a plaingit fetch --tagsis rejected with "would clobber existing tag".Verified against the real history:
develop1.13.1— already published, run is a no-opupgrade-1.13.2(#8)1.13.2— merging it cuts the release1.13.1— merging it alone releases nothingsort -Vpicking1.13.1over1.7.5also confirms the ordering is numeric, not lexical. Release candidates (v1.11.0-rc.1) are filtered out.Nothing becomes visible until it is verified
The draft holds only
tag_nameandtarget_commitish, so an aborted run leaves no tag behind — GitHub creates the tag on publish./releases/latestexcludes drafts and:latestis not pushed by the image build, so a failure anywhere beforepublishleaves the previous release and the previous:latestcompletely untouched.docker.yaml had to change, or images would have stopped silently
It listened on
release: published. That only ever fired because a human clicked Publish — a release published withGITHUB_TOKENtriggers no workflow runs. Automating that click without convertingdocker.yamlinto aworkflow_calltarget would have quietly ended every image build. It keeps itspush: developtrigger for:develop.Image tags:
:1.13.2and:v1.13.2(the latter is what we publish today, kept for compatibility), plus:latestmoved by digest inpublish.Also in here
CHANGELOG.mdsection fails the job instead of publishing an empty body — which is what would have happened on the next release, since there was no## v1.13.2section. The match is anchored, sov1.13.2no longer also matchesv1.13.20.release/vXbranch and itssedbump ofsystem/const.go. Inherited from upstream, it wrote a version into a branch nobody uses while the real version comes from ldflags — and a git push mid-release is exactly what makes a second run for the same version fail.SHA256SUMS, without which the verification step has little to verify.develop.FORK_CHANGES.mdnow marks the pipeline as fork-specific, so upstream'srelease.yamldoes not get merged over it.Behaviour changes to be aware of
v*tag by hand no longer releases anything. Releases come fromdevelopand nowhere else.force: truedispatch, which deletes the release and its tag and cuts it again from the currentdevelop. Deleting a release in the UI deliberately does not resurrect it — otherwise an accidental deletion would rebuild it from whatever happens to be ondevelopat the time.preparetreats an existing draft as resume; only a published release blocks a new run.Verification
actionlint(with shellcheck) clean on all three workflows.CHANGELOG.md, results above.Merge order
#8 is already merged, so
developsits on upstreamv1.13.2with no release cut — the old workflow only fired on a tag push. Merging this PR therefore cutsv1.13.2immediately, which is the intended first live run, and it is safe by construction: a failure anywhere leaves the release a draft and:latestuntouched.The
## v1.13.2changelog section the gate requires rides along in this PR. It was written for #8 but landed on that branch after the PR had already been merged, sodevelopdoes not have it — without it here, the first automatic run would fail on its own gate.