ci(release): release with release-please, and check PR titles #1059
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!1059
Loading…
Reference in a new issue
No description provided.
Delete branch "ci-release-please"
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?
This replaces semantic-release with release-please, so a release is cut by merging a release PR. The same workflow then builds and attaches the release files, and each release also gets a
SHA256SUMSfile, build provenance attestations for every file, a.zsyncso AppImageUpdate and Gear Lever can update the AppImage, and a short "Which file do I download?" table under its notes. It also adds a check that PR titles are Conventional Commits. It replaces #1044.Why semantic-release was replaced
.releaserc.jsonnames theconventionalcommitspreset, butconventional-changelog-conventionalcommitswas not inpackage.json, so every run that had something to release stopped atCannot find module 'conventional-changelog-conventionalcommits'(for example run 42576776625). The green runs were the ones that stopped earlier, at "local branch is behind the remote".[skip ci]commit and is pushed withGITHUB_TOKEN, so it starts neither the Linux AppImage nor the Windows builder workflow. That needs a personal access token.fix:landed, and most of the maintainers' changes would never have released or reached the changelog.release-please reads the same Conventional Commits, so this PR also makes the titles conventional (below). In exchange, every release goes through a PR a maintainer merges, and its changelog can be edited first.
How releases work now
.github/workflows/release.ymlruns on every push to main. release-please (googleapis/release-please-actionv5.0.0, pinned by SHA) keeps one release PR open,chore: release <version>. The PR bumps.release-please-manifest.json(seeded at 2.0.11, the latest release) and adds the entry at the top ofCHANGELOG.md.v<version>and creates the GitHub release as a draft, with the changelog entry as its notes (draftandforce-tag-creationinrelease-please-config.json).linux-appimage.ymlandwindows-builder.yml, which now also takeworkflow_callwith the tag as input. They check out the tag and run their existing build and release jobs unchanged, with no duplicated steps. They attach the same files as on v2.0.3 to v2.0.7, with the same names:Hookshot-v<version>-x86_64.AppImage,hookshot-linux.txt,HookshotBuilder.exeandhookshot-setup.txt. They also attachHookshot-v<version>-x86_64.AppImage.zsync(below). New parts go tolinux-partsandbuilder-partsas before.SHA256SUMSand the notes table (scripts/release_files.sh finish), checks that all six files are on the draft and thatSHA256SUMSlists every file with its digest, signsSHA256SUMS, then publishes the draft as "latest". Players' Update and the setup readreleases/latest/download/hookshot-setup.txt, so a release is never visible without its files.Checksums, provenance, zsync and the notes table
SHA256SUMS: the SHA-256 of every other file on the release, insha256sumformat, sosha256sum -c --ignore-missing SHA256SUMSchecks a download. It is built from GitHub's own digest of each uploaded file (a file without one is downloaded and hashed). For a hand-pushed tag, which has no publish job,release_upload.shmakes it after uploading. The Linux and Windows release jobs both do that at once, so each one compares the uploadedSHA256SUMSwith the files after uploading it and makes it again if the other job changed something.actions/attest-build-provenancev4.2.2, pinned by SHA, in the jobs that build the files: the AppImage, its.zsyncandhookshot-linux.txtin the Linux build job,HookshotBuilder.exeandhookshot-setup.txtin the Windows package job, andSHA256SUMSwhere it is made. Only those jobs, and the Release workflow's jobs that call them, getid-token: writeandattestations: write. Anyone can check a file withgh attestation verify <file> -R NotRexed/Hookshot. It shows the workflow, the tag and the run that built the file.scripts/linux/appimage.shpasses appimagetool-u "gh-releases-zsync|NotRexed|Hookshot|latest|Hookshot-*-x86_64.AppImage.zsync"(the owner and repository come fromGITHUB_REPOSITORY). appimagetool writes that into the image's.upd_infosection and makes the.zsyncwith its bundled zsyncmake. The.zsyncnames the AppImage by its file name, so the URL resolves to the AppImage beside it on the same release. AppImageUpdate readsreleases/latestand takes the.zsyncthat matches the pattern. Gear Lever does the same, then downloads the matching name without.zsync. The build fails if no.zsyncwas made. The in-app Linux updater (hookshot-linux.txt) is unchanged; this only lets the AppImage itself be updated by those tools.HookshotBuilder.exe, the setup. Linux and Steam Deck: the AppImage. It adds "You need your own copy of the game" (the readme's phrasing), says the.txtfiles and the.zsyncare for the updaters, and gives thesha256sumandgh attestation verifycommands.scripts/release_upload.shreplaces files already on the release, and the draft is only published once everything is there.2.1.0-rc.1) is a prerelease and never "latest". The simple way to make one is still a hand-pushed tag, likev2.0.7-rc.1: the tag-triggered builds make the prerelease and attach the files, as they do today.Release-As: 2.1.0-rc.1also works through release-please (docs/versioning.md has the details). Thenextbranch from docs/versioning.md is dropped. No such branch exists, and release-please's prerelease versioning on a second branch would complicate merging back into main for no gain.contents: read. The release-please job hascontents: writeandpull-requests: write, the build calls and the publish job havecontents: write, and those jobs and the build jobs haveid-token: writeandattestations: writefor the attestations. Everything else stays read-only.scripts/release_upload.shmarks anyvX.Y.Z-<prerelease>tag as a prerelease (before, only-rc). It also refuses file names that look like game data, dumps or NVIDIA runtime files (*.nso,*.nca,*romfs*,*nvngx*,*dlss*, ...), as a backstop. The Windows builder's release job now runs for every release unlessvars.CI_RELEASE_WINDOWSis'false'. Before, it was off unless set to'true', which is why v2.0.7-rc.1 had noHookshotBuilder.exe.package.json,.releaserc.json, andscripts/changelog.pywith its test, which only semantic-release ran.changelog.txt(the 0.1.0 entry, written by hand) is kept as history, andCHANGELOG.mdstarts with a 2.0.7 entry that points to the release pages.PR titles
.github/workflows/pr-title.ymlrunsamannn/action-semantic-pull-requestv6.1.1, pinned by SHA, onpull_request_target(opened, edited, synchronize, reopened). It haspull-requests: readonly and never checks out the PR's code. Allowed types: feat, fix, perf, refactor, docs, test, ci, build, chore, revert. Scopes are optional.Release-As:to force a version.How it was tested
python -I -B tests/run_all.pypasses (107 passed, 14 skipped for missing local tools).rp-teststood in for main, with a seed release v1.0.0. The only test-only changes were the branch name inrelease.ymland the manifest seed.fix:commit ran the Release workflow. release-please created its branch and commit, and then GitHub refused to open the PR: "GitHub Actions is not permitted to create or approve pull requests". That is the repository setting listed below, which I did not change on the fork. I opened that branch's PR myself, with the title, body andautorelease: pendinglabel release-please uses (https://github.com/hckrman101/Hookshot/pull/15). It bumped the manifest to 1.0.1 and added the CHANGELOG.md entry above the seeded 2.0.7 one.SHA256SUMSand the table, checked the six files and published v1.0.1 as a non-prerelease "latest" release. Its notes were release-please's entry with the table below it, and it hadHookshot-v1.0.1-x86_64.AppImage,Hookshot-v1.0.1-x86_64.AppImage.zsync,hookshot-linux.txt,HookshotBuilder.exe,hookshot-setup.txtandSHA256SUMS.sha256sum -c SHA256SUMSpassed for all five files.gh attestation verify <file> -R hckrman101/Hookshotpassed for all six, each naming the workflow that built it (linux-appimage.yml,windows-builder.yml, orrelease.ymlforSHA256SUMS) atrefs/heads/rp-test. A file with the same name and other content failed../Hookshot-v1.0.1-x86_64.AppImage --appimage-updateinformationand the.upd_infoELF section both gavegh-releases-zsync|hckrman101|Hookshot|latest|Hookshot-*-x86_64.AppImage.zsync. The.zsync(zsync 0.6.2, 4096-byte blocks) has the AppImage's length, SHA-1 and file name, and a relative URL. I recomputed the rsum and MD4 sums of a sample of 300 blocks, plus the first and last, and they matched. I could not run AppImageUpdate itself here, so I followed its code (GithubReleasesZsyncUpdateInformation.cpp) and Gear Lever's (GithubUpdater.py) against the fork's API. Both foundHookshot-v1.0.1-x86_64.AppImage.zsyncon the latest release, and the AppImage it points to was there.SHA256SUMSat different times, and it ended up listing all five files.sha256sum -c, the zsync check andgh attestation verifypassed on all of them..zsyncinto the current folder, not beside its output.appimage.shnow runs it frombuild-linux/, and the check that the.zsyncexists caught the problem.release_parts.py previous, older than this PR) still apply.linux-parts,builder-parts), their tags and the test branches. The attestations stay in the fork's attestation store.What a maintainer has to do
CI_RELEASE_WINDOWStofalseto keep uploading the Windows files by hand. The draft then waits for you to publish it. Runscripts/release_files.sh finish v<version>(withGH_REPOset) after uploading them, soSHA256SUMSlists them. They then have no attestation, since they were not built by CI.GITHUB_TOKEN, which starts no checks on it, so required checks would block it unless it is excluded or a token is used.Read through the workflows, scripts and config. Permissions are scoped sensibly (workflow-level
contents: read, write andid-tokenonly on the release/build/publish jobs,pull-requests: readfor the title check with no checkout underpull_request_target), every new action is pinned by SHA with a version comment, and the release-please config is consistent with the workflow and the docs. The fork test of the whole flow is convincing.One real thing to fix before merging: the manifest seed.
.release-please-manifest.jsonsays 2.0.11, but main's latest release is now v2.0.14 (v2.0.12, .13 and .14 exist). release-please would propose 2.0.12 for the first release PR and then fail to create a tag that already exists (and its changelog would claim changes already shipped). Bump the seed to the latest release when you merge (and re-check right before, since releases keep landing). The PR text and the CHANGELOG.md placeholder entry mention 2.0.7/2.0.11, so update those too.Nit: the
release-${{ github.ref }}concurrency group queues at most one pending run, and the linux/windows builds keep a run busy for 20+ minutes. If another PR merges while the release run is pending, the pending run is cancelled. That is mostly harmless since release-please finds the merged-but-untagged release PR on the next push, but it can delay a release until the next merge to main.CI: the red Python source checks are the failures main has right now (
nx2/test_draw_parameters,test_draw_stream_visibility,test_sampler_admissionfixture breakage,test_lift_cleanup_error,test_recomplauncher_json,nx2/test_nup_out_of_space). None involve this PR's files. Merging main should clear the fixture ones. actionlint, the builder package/setup, Windows Vulkan and the AppImage build all pass.Related: #1201 and #1452 both patch the semantic-release setup (package.json, the old release.yml). They will conflict with this PR and become moot once it lands, so close them when this merges. Note main's release.yml still triggers on
nexttoo, which this PR drops as described.@ -0,0 +1,3 @@{Main's latest release is v2.0.14 (v2.0.12-.14 already exist), so this seed should be 2.0.14 (or whatever is latest at merge). With 2.0.11 the first release PR would be 2.0.12 and tagging it would collide with the existing tag.
I updated this from main and pushed one commit (
20f8d1ba), because v2.0.12 to v2.0.14 were released from release branches after the manifest was seeded:.release-please-manifest.json2.0.11 → 2.0.14, so the first release PR doesn't propose 2.0.12 again.CHANGELOG.md's base entry is now 2.0.14.release-please-config.jsongetslast-release-sha: b2e1c5a6. Those tags aren't in main's history, so this is the last main commit v2.0.14 holds (where release/v2.0.12 left main). The first release PR then lists main's work since then, instead of release-please searching for a tag it can't find on main.#2010 builds on this with a one-click Pre-release workflow for anyone with write access (the next
vX.Y.Z-rc.N), plusdocs/releasing.md.🤖 Generated with Claude Code