ci(release): release candidates from release-please, Promote to release, and a nightly of main #2018
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!2018
Loading…
Reference in a new issue
No description provided.
Delete branch "ci-release-candidates"
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?
#1059 releases straight from release-please's PR: whatever lands in a release PR goes to every player as "latest" with no test build in between. This puts a tested release candidate in front of every release. release-please proposes the candidate in its PR, merging that PR publishes it as a prerelease, and a manual Promote publishes a good one as the release. It also brings in #1062, the rolling
nightlyprerelease of main (closed in favor of this PR).Overlap with #2010: #2010 (one-click pre-releases,
docs/releasing.md) solves the same problem a different way: a button that tags the nextvX.Y.Z-rc.Nitself, then a stable release from release-please's PR. The two do not conflict as text, since #2010 only adds new files. They do conflict in what they do: both define how RC tags are numbered and how a stable release is made, and #2010's optional cron nightly overlaps thenightlyhere. Merge one of them. If this one goes in, #2010's button would make RC tags that release-please does not know about (they are not in the manifest), and Promote's "newest RC" default could pick one of them.The flow
nightlyprerelease is rebuilt from that commit. release-please opens or updates its release PR,chore: release X.Y.Z-rc.N.vX.Y.Z-rc.Nis tagged on the merge commit and built like a release. Once every file is there, it is published as a GitHub prerelease, never "latest". The next release PR proposesrc.N+1of the same version, with the changes sincerc.N.vX.Y.Zis tagged on that RC's exact commit, built from it, and published as "latest". Its notes are those of its RCs, newest first. Then.release-please-manifest.jsonis set toX.Y.Z, so the next release PR proposes the next version'src.1.There is no "start a series" step: the first fix after a release proposes the next version's
rc.1.release-please's prerelease versioning, as it behaves
I checked
PrereleaseVersioningStrategyin release-please 17.6.0, the versionrelease-please-actionv5.0.0 bundles:2.0.14:fixgives2.0.15-rc.1,featgives2.1.0-rc.1, and a breaking change gives3.0.0-rc.1.fix(andperf,revert) bumps the RC number,2.0.15-rc.1->2.0.15-rc.2. On a minor RC (2.1.0-rc.1),featalso only bumps the RC number. One quirk: afeatduring a patch series moves to the next minor and keeps the RC number (2.0.15-rc.2->2.1.0-rc.2). docs/versioning.md says how to restart it atrc.1withRelease-As:.prerelease-typeisrc.1, notrc. Withrc, the first one would be2.0.15-rc, and the one after it2.0.15-rc.1.Promote rebuilds the files instead of copying the RC's
The plan was to publish the stable version with the RC's files, byte for byte. That would break updating for every player. Each file records the version it was built as: the tools'
version.txtinside the app part, the AppImage'sVERSIONand file name, and thetagline ofhookshot-setup.txtandhookshot-linux.txt. The game (host/hos_update.c), Hookshot Builder (Updater.cs) and the Linux updater compare that version with the latest release's tag. Av2.1.0release holding2.1.0-rc.2files would offer itself as an update forever, and the builder would stop with "The update installed v2.1.0-rc.2, not v2.1.0". Clients already installed have that logic, so newer client code cannot fix it either.So Promote tags
vX.Y.Zon the RC's commit and calls the same build workflows as for an RC. The source is the same commit, the dependencies are the same checked downloads, and the previous stable release supplies the same reused parts. Update parts that did not change are the same files onbuilder-parts/linux-parts, so an update from the RC downloads little more than what names the version. The AppImage is named after the release's tag (HOOKSHOT_VERSION), notgit describe, since that commit now carries two tags.Details
.github/workflows/release.ymlis one workflow with three entry points: push to main, the release PR merged (also a push), andworkflow_dispatchfor Promote. Jobs:release-please(push),promote(dispatch, main only),linuxandwindows(calllinux-appimage.ymlandwindows-builder.ymlwith the tag, for an RC or a promoted version),publish(SHA256SUMS, the files table, checks every file is there, then publishes as a prerelease or as "latest"), andrecord(after a promote).scripts/release_promote.sh preparechecks that the RC is a published prerelease on main, creates the version's tag on its commit through the refs API, and creates the draft release with the RC notes combined (the "Which file do I download?" table is removed from each). Running it again for the same RC continues with the same tag and draft. It refuses an RC tag that is a draft or not on main, and a version that already exists elsewhere or is already released.recordrunsscripts/release_promote.sh record, which sets the manifest (only while it still holds one of that version's RCs) and.release-please-version, and adds a shortCHANGELOG.mdentry for the version that points to its RC entries. It pushes this to main withGITHUB_TOKEN, then has release-please rebuild the release PR, because that push starts no workflow. If main does not accept the push (branch protection or a ruleset), it opens a small PRchore(release): record X.Y.Z as releasedinstead. Merge it before the release PR.versioning: prereleaseandprerelease-type: rc.1are added. The manifest (2.0.14) andlast-release-sha: b2e1c5a6from #1059 are kept. Therelease-as: 2.1.0pin from #1059 is removed. It would have proposed 2.1.0 as a release, with no RC, and then the same version again. Without it, main'sfeatcommits sinceb2e1c5a6make the first release PR propose2.1.0-rc.1on their own, and promoting that gives 2.1.0. A dry run of release-please 17.6.0 on the fork gaverelease 2.1.0with the pin andrelease 2.1.0-rc.1without..release-please-version. The simple strategy writesversion.txtat the root by default, andnx2/version.pyreads that file beforegit describeas the release name of every build from a checkout, the nightly included.workflow_callon a push to main, becausegithub.event_name/github.refare the caller's. That defeatedCI_RELEASE_WINDOWS=false. It is now scoped with!inputs.tag.Unchanged from #1059, or brought in from #1062:
nightlytag and replace its files (scripts/release_upload.sh nightly). An older run never overwrites a newer commit. The nightly AppImage updates to the next nightly. The readme gets a "Latest development build" section (Windows:HookshotBuilder.exe --tag nightly).Tested on the fork
Actions are currently disabled on hckrman101/Hookshot ("Actions has been disabled for this repository", even for
workflow_dispatch), so no workflow could run there this time. Instead, I ran each step the workflow runs from this machine against the fork, on a test branchrc-test: release-please 17.6.0 (release-pr/github-release, the bundled version), the release jobs'scripts/release_upload.sh, the publish job's steps, andscripts/release_promote.sh. Stub files stood in for the builds, named like the real ones and holding the version and the commit. The manifest started at 0.0.1, seeded with a v0.0.1 release.fix: change onegave release PRchore(rc-test): release 0.0.2-rc.1. Merging it made draftv0.0.2-rc.1on the merge commit. Uploading and publishing made it a prerelease with all files,SHA256SUMSpassedsha256sum -c, and v0.0.1 stayed "latest".fix: change twogaverelease 0.0.2-rc.2, with only change two and the compare linkv0.0.2-rc.1...v0.0.2-rc.2. Merged and published as a prerelease.fix: change threegave an open PR for0.0.2-rc.3, left open.v0.0.2-rc.2.v0.0.2was tagged on rc.2's commit (6d860d5, the same SHA as the rc.2 tag). The draft's notes were the rc.2 and rc.1 entries, newest first, without their tables. After the build,v0.0.2was published as "latest", not a prerelease, and itsSHA256SUMSpassed. Its files were the rebuilt ones, carryingv0.0.2(see above for why the bytes differ from the RC's on purpose). Running prepare again for rc.2 continued with the same draft. It refusedv0.0.2-rc.1(v0.0.2 is already on another commit),v0.0.1(not an RC tag), and an RC tag that was not a published prerelease.chore(release): record 0.0.2 as releasedwas opened (fork PR 19). Merging it set the manifest to 0.0.2 and added the 0.0.2 changelog entry. The nextrelease-prthen proposed0.0.3-rc.1, with change three and the compare linkv0.0.2...v0.0.3-rc.1.Afterwards I deleted every test release, tag and branch on the fork, removed the branch protection, and put back the fork's Actions setting that I had changed briefly.
Also: actionlint 1.7.7 with shellcheck 0.10.0 passes on every workflow, and shellcheck passes on
release_promote.sh,release_upload.shandrelease_files.sh. The tests that read the build workflows pass:test_appimage_player_build,test_appimage_package_retry,test_recomplauncher_json,test_appimage_scripts.Not tested:
workflow_dispatchinput, concurrency, therecordjob's owngit pushandgh pr createfrom the runner (step 5 ran the same commands from here), and the release-please refresh withskip-github-release. These need Actions back on the fork, or the first real run.HOOKSHOT_VERSIONnaming of a release AppImage.CI_RELEASE_WINDOWS=falsepath after a promote.recordthen does not run, and docs/versioning.md gives the manual command.What a maintainer has to do
record's fallback PR), and squash merging with the PR title as the commit message.record's small PR after each Promote (before the next release PR).CI_RELEASE_WINDOWS=falseto upload the Windows files by hand.