ci(release): release with release-please, and check PR titles #1059

Merged
hckrman101 merged 14 commits from ci-release-please into main 2026-11-10 23:35:40 +00:00
hckrman101 commented 2026-11-09 08:43:30 +00:00 (Migrated from github.com)

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 SHA256SUMS file, build provenance attestations for every file, a .zsync so 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

  • It never released. .releaserc.json names the conventionalcommits preset, but conventional-changelog-conventionalcommits was not in package.json, so every run that had something to release stopped at Cannot 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".
  • With the module installed, it still would not have produced files. Its tag sits on a [skip ci] commit and is pushed with GITHUB_TOKEN, so it starts neither the Linux AppImage nor the Windows builder workflow. That needs a personal access token.
  • It reads only Conventional Commit subjects, and most of main is not written that way. Since v2.0.0, main has 332 commits: 128 merges, and 66 conventional subjects among the other 204. Of the last 100 merged PR titles, 37 are conventional. Releases would have followed whenever a contributor's fix: landed, and most of the maintainers' changes would never have released or reached the changelog.
  • It releases on every merge with nothing in between to stop it, while releases here have been cut deliberately, by hand, with written notes.

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.yml runs on every push to main. release-please (googleapis/release-please-action v5.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 of CHANGELOG.md.
  • Merging that PR is the release. release-please tags the merge commit v<version> and creates the GitHub release as a draft, with the changelog entry as its notes (draft and force-tag-creation in release-please-config.json).
  • The same workflow then calls linux-appimage.yml and windows-builder.yml, which now also take workflow_call with 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.exe and hookshot-setup.txt. They also attach Hookshot-v<version>-x86_64.AppImage.zsync (below). New parts go to linux-parts and builder-parts as before.
  • A last job adds SHA256SUMS and the notes table (scripts/release_files.sh finish), checks that all six files are on the draft and that SHA256SUMS lists every file with its digest, signs SHA256SUMS, then publishes the draft as "latest". Players' Update and the setup read releases/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, in sha256sum format, so sha256sum -c --ignore-missing SHA256SUMS checks 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.sh makes it after uploading. The Linux and Windows release jobs both do that at once, so each one compares the uploaded SHA256SUMS with the files after uploading it and makes it again if the other job changed something.
  • Build provenance: actions/attest-build-provenance v4.2.2, pinned by SHA, in the jobs that build the files: the AppImage, its .zsync and hookshot-linux.txt in the Linux build job, HookshotBuilder.exe and hookshot-setup.txt in the Windows package job, and SHA256SUMS where it is made. Only those jobs, and the Release workflow's jobs that call them, get id-token: write and attestations: write. Anyone can check a file with gh attestation verify <file> -R NotRexed/Hookshot. It shows the workflow, the tag and the run that built the file.
  • AppImage zsync: scripts/linux/appimage.sh passes appimagetool -u "gh-releases-zsync|NotRexed|Hookshot|latest|Hookshot-*-x86_64.AppImage.zsync" (the owner and repository come from GITHUB_REPOSITORY). appimagetool writes that into the image's .upd_info section and makes the .zsync with its bundled zsyncmake. The .zsync names the AppImage by its file name, so the URL resolves to the AppImage beside it on the same release. AppImageUpdate reads releases/latest and takes the .zsync that matches the pattern. Gear Lever does the same, then downloads the matching name without .zsync. The build fails if no .zsync was made. The in-app Linux updater (hookshot-linux.txt) is unchanged; this only lets the AppImage itself be updated by those tools.
  • The notes table goes under release-please's changelog entry, once. Windows: 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 .txt files and the .zsync are for the updaters, and gives the sha256sum and gh attestation verify commands.
  • No existing file name changes. The new files do not match any name the setup, the builder's update check or the Linux updater looks for. docs/versioning.md has a table of all six files.
  • Re-running the failed jobs of a Release run is idempotent. scripts/release_upload.sh replaces files already on the release, and the draft is only published once everything is there.
  • Prereleases: a version with a prerelease part (2.1.0-rc.1) is a prerelease and never "latest". The simple way to make one is still a hand-pushed tag, like v2.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.1 also works through release-please (docs/versioning.md has the details). The next branch 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.
  • Permissions: workflow-level contents: read. The release-please job has contents: write and pull-requests: write, the build calls and the publish job have contents: write, and those jobs and the build jobs have id-token: write and attestations: write for the attestations. Everything else stays read-only.
  • scripts/release_upload.sh marks any vX.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 unless vars.CI_RELEASE_WINDOWS is 'false'. Before, it was off unless set to 'true', which is why v2.0.7-rc.1 had no HookshotBuilder.exe.
  • Removed: package.json, .releaserc.json, and scripts/changelog.py with its test, which only semantic-release ran. changelog.txt (the 0.1.0 entry, written by hand) is kept as history, and CHANGELOG.md starts with a 2.0.7 entry that points to the release pages.

PR titles

  • .github/workflows/pr-title.yml runs amannn/action-semantic-pull-request v6.1.1, pinned by SHA, on pull_request_target (opened, edited, synchronize, reopened). It has pull-requests: read only and never checks out the PR's code. Allowed types: feat, fix, perf, refactor, docs, test, ci, build, chore, revert. Scopes are optional.
  • CONTRIBUTING.md has a "Pull request titles" section with examples from this repository's history, and says PRs are squash-merged so the title becomes the commit release-please reads. docs/versioning.md is rewritten for the new flow, including Release-As: to force a version.

How it was tested

  • actionlint 1.7.7 with shellcheck 0.10.0 passes on every workflow, and shellcheck passes on the scripts. python -I -B tests/run_all.py passes (107 passed, 14 skipped for missing local tools).
  • On the fork (hckrman101/Hookshot), a test branch rp-test stood in for main, with a seed release v1.0.0. The only test-only changes were the branch name in release.yml and the manifest seed.
    • Pushing a 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 and autorelease: pending label 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.
    • Squash-merging it ran the Release workflow (https://github.com/hckrman101/Hookshot/actions/runs/42653913368), and every job passed. release-please made the draft v1.0.1 and its tag, both builds attached their files, and the publish job added SHA256SUMS and 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 had Hookshot-v1.0.1-x86_64.AppImage, Hookshot-v1.0.1-x86_64.AppImage.zsync, hookshot-linux.txt, HookshotBuilder.exe, hookshot-setup.txt and SHA256SUMS.
    • I downloaded every file of v1.0.1. sha256sum -c SHA256SUMS passed for all five files. gh attestation verify <file> -R hckrman101/Hookshot passed for all six, each naming the workflow that built it (linux-appimage.yml, windows-builder.yml, or release.yml for SHA256SUMS) at refs/heads/rp-test. A file with the same name and other content failed.
    • ./Hookshot-v1.0.1-x86_64.AppImage --appimage-updateinformation and the .upd_info ELF section both gave gh-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 found Hookshot-v1.0.1-x86_64.AppImage.zsync on the latest release, and the AppImage it points to was there.
    • The hand-pushed tag path: creating v1.0.0 made the tag, and the tag-triggered builds attached the same six files (https://github.com/hckrman101/Hookshot/actions/runs/42653673217 and https://github.com/hckrman101/Hookshot/actions/runs/42653673259). The two release jobs each wrote SHA256SUMS at different times, and it ended up listing all five files. sha256sum -c, the zsync check and gh attestation verify passed on all of them.
    • An earlier run found that appimagetool writes the .zsync into the current folder, not beside its output. appimage.sh now runs it from build-linux/, and the check that the .zsync exists caught the problem.
    • The PR title check was tested earlier on two fork PRs: "Update the builder" failed with "No release type found in pull request title", and "docs(ci): fork test of the PR title check" passed. The earlier test's notes on the Windows build's occasional GitHub 504s (in release_parts.py previous, older than this PR) still apply.
    • Afterwards I deleted all fork test releases (v1.0.0, v1.0.1, 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

  1. Settings > Actions > General > Workflow permissions: turn on "Allow GitHub Actions to create and approve pull requests". Without it, release-please cannot open the release PR. The default token permission can stay read-only.
  2. Settings > General > Pull Requests: allow squash merging, and preferably only squash merging, with the default commit message set to "Pull request title" (or "Pull request title and description"). The PR title then becomes the commit release-please reads. A merge commit's own subject is ignored, so a PR merged that way releases only if its commits are conventional.
  3. Optional: set the repository variable CI_RELEASE_WINDOWS to false to keep uploading the Windows files by hand. The draft then waits for you to publish it. Run scripts/release_files.sh finish v<version> (with GH_REPO set) after uploading them, so SHA256SUMS lists them. They then have no attestation, since they were not built by CI.
  4. Optional: make the "PR title" check required under branch protection or a ruleset. Note that the release PR is opened with GITHUB_TOKEN, which starts no checks on it, so required checks would block it unless it is excluded or a token is used.
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 `SHA256SUMS` file, build provenance attestations for every file, a `.zsync` so 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 - It never released. `.releaserc.json` names the `conventionalcommits` preset, but `conventional-changelog-conventionalcommits` was not in `package.json`, so every run that had something to release stopped at `Cannot 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". - With the module installed, it still would not have produced files. Its tag sits on a `[skip ci]` commit and is pushed with `GITHUB_TOKEN`, so it starts neither the Linux AppImage nor the Windows builder workflow. That needs a personal access token. - It reads only Conventional Commit subjects, and most of main is not written that way. Since v2.0.0, main has 332 commits: 128 merges, and 66 conventional subjects among the other 204. Of the last 100 merged PR titles, 37 are conventional. Releases would have followed whenever a contributor's `fix:` landed, and most of the maintainers' changes would never have released or reached the changelog. - It releases on every merge with nothing in between to stop it, while releases here have been cut deliberately, by hand, with written notes. 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.yml` runs on every push to main. release-please (`googleapis/release-please-action` v5.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 of `CHANGELOG.md`. - Merging that PR is the release. release-please tags the merge commit `v<version>` and creates the GitHub release as a draft, with the changelog entry as its notes (`draft` and `force-tag-creation` in `release-please-config.json`). - The same workflow then calls `linux-appimage.yml` and `windows-builder.yml`, which now also take `workflow_call` with 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.exe` and `hookshot-setup.txt`. They also attach `Hookshot-v<version>-x86_64.AppImage.zsync` (below). New parts go to `linux-parts` and `builder-parts` as before. - A last job adds `SHA256SUMS` and the notes table (`scripts/release_files.sh finish`), checks that all six files are on the draft and that `SHA256SUMS` lists every file with its digest, signs `SHA256SUMS`, then publishes the draft as "latest". Players' Update and the setup read `releases/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, in `sha256sum` format, so `sha256sum -c --ignore-missing SHA256SUMS` checks 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.sh` makes it after uploading. The Linux and Windows release jobs both do that at once, so each one compares the uploaded `SHA256SUMS` with the files after uploading it and makes it again if the other job changed something. - Build provenance: `actions/attest-build-provenance` v4.2.2, pinned by SHA, in the jobs that build the files: the AppImage, its `.zsync` and `hookshot-linux.txt` in the Linux build job, `HookshotBuilder.exe` and `hookshot-setup.txt` in the Windows package job, and `SHA256SUMS` where it is made. Only those jobs, and the Release workflow's jobs that call them, get `id-token: write` and `attestations: write`. Anyone can check a file with `gh attestation verify <file> -R NotRexed/Hookshot`. It shows the workflow, the tag and the run that built the file. - AppImage zsync: `scripts/linux/appimage.sh` passes appimagetool `-u "gh-releases-zsync|NotRexed|Hookshot|latest|Hookshot-*-x86_64.AppImage.zsync"` (the owner and repository come from `GITHUB_REPOSITORY`). appimagetool writes that into the image's `.upd_info` section and makes the `.zsync` with its bundled zsyncmake. The `.zsync` names the AppImage by its file name, so the URL resolves to the AppImage beside it on the same release. AppImageUpdate reads `releases/latest` and takes the `.zsync` that matches the pattern. Gear Lever does the same, then downloads the matching name without `.zsync`. The build fails if no `.zsync` was made. The in-app Linux updater (`hookshot-linux.txt`) is unchanged; this only lets the AppImage itself be updated by those tools. - The notes table goes under release-please's changelog entry, once. Windows: `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 `.txt` files and the `.zsync` are for the updaters, and gives the `sha256sum` and `gh attestation verify` commands. - No existing file name changes. The new files do not match any name the setup, the builder's update check or the Linux updater looks for. docs/versioning.md has a table of all six files. - Re-running the failed jobs of a Release run is idempotent. `scripts/release_upload.sh` replaces files already on the release, and the draft is only published once everything is there. - Prereleases: a version with a prerelease part (`2.1.0-rc.1`) is a prerelease and never "latest". The simple way to make one is still a hand-pushed tag, like `v2.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.1` also works through release-please (docs/versioning.md has the details). The `next` branch 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. - Permissions: workflow-level `contents: read`. The release-please job has `contents: write` and `pull-requests: write`, the build calls and the publish job have `contents: write`, and those jobs and the build jobs have `id-token: write` and `attestations: write` for the attestations. Everything else stays read-only. - `scripts/release_upload.sh` marks any `vX.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 unless `vars.CI_RELEASE_WINDOWS` is `'false'`. Before, it was off unless set to `'true'`, which is why v2.0.7-rc.1 had no `HookshotBuilder.exe`. - Removed: `package.json`, `.releaserc.json`, and `scripts/changelog.py` with its test, which only semantic-release ran. `changelog.txt` (the 0.1.0 entry, written by hand) is kept as history, and `CHANGELOG.md` starts with a 2.0.7 entry that points to the release pages. ## PR titles - `.github/workflows/pr-title.yml` runs `amannn/action-semantic-pull-request` v6.1.1, pinned by SHA, on `pull_request_target` (opened, edited, synchronize, reopened). It has `pull-requests: read` only and never checks out the PR's code. Allowed types: feat, fix, perf, refactor, docs, test, ci, build, chore, revert. Scopes are optional. - CONTRIBUTING.md has a "Pull request titles" section with examples from this repository's history, and says PRs are squash-merged so the title becomes the commit release-please reads. docs/versioning.md is rewritten for the new flow, including `Release-As:` to force a version. ## How it was tested - actionlint 1.7.7 with shellcheck 0.10.0 passes on every workflow, and shellcheck passes on the scripts. `python -I -B tests/run_all.py` passes (107 passed, 14 skipped for missing local tools). - On the fork (hckrman101/Hookshot), a test branch `rp-test` stood in for main, with a seed release v1.0.0. The only test-only changes were the branch name in `release.yml` and the manifest seed. - Pushing a `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 and `autorelease: pending` label 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. - Squash-merging it ran the Release workflow (https://github.com/hckrman101/Hookshot/actions/runs/42653913368), and every job passed. release-please made the draft v1.0.1 and its tag, both builds attached their files, and the publish job added `SHA256SUMS` and 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 had `Hookshot-v1.0.1-x86_64.AppImage`, `Hookshot-v1.0.1-x86_64.AppImage.zsync`, `hookshot-linux.txt`, `HookshotBuilder.exe`, `hookshot-setup.txt` and `SHA256SUMS`. - I downloaded every file of v1.0.1. `sha256sum -c SHA256SUMS` passed for all five files. `gh attestation verify <file> -R hckrman101/Hookshot` passed for all six, each naming the workflow that built it (`linux-appimage.yml`, `windows-builder.yml`, or `release.yml` for `SHA256SUMS`) at `refs/heads/rp-test`. A file with the same name and other content failed. - `./Hookshot-v1.0.1-x86_64.AppImage --appimage-updateinformation` and the `.upd_info` ELF section both gave `gh-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 found `Hookshot-v1.0.1-x86_64.AppImage.zsync` on the latest release, and the AppImage it points to was there. - The hand-pushed tag path: creating v1.0.0 made the tag, and the tag-triggered builds attached the same six files (https://github.com/hckrman101/Hookshot/actions/runs/42653673217 and https://github.com/hckrman101/Hookshot/actions/runs/42653673259). The two release jobs each wrote `SHA256SUMS` at different times, and it ended up listing all five files. `sha256sum -c`, the zsync check and `gh attestation verify` passed on all of them. - An earlier run found that appimagetool writes the `.zsync` into the current folder, not beside its output. `appimage.sh` now runs it from `build-linux/`, and the check that the `.zsync` exists caught the problem. - The PR title check was tested earlier on two fork PRs: "Update the builder" failed with "No release type found in pull request title", and "docs(ci): fork test of the PR title check" passed. The earlier test's notes on the Windows build's occasional GitHub 504s (in `release_parts.py previous`, older than this PR) still apply. - Afterwards I deleted all fork test releases (v1.0.0, v1.0.1, `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 1. Settings > Actions > General > Workflow permissions: turn on "Allow GitHub Actions to create and approve pull requests". Without it, release-please cannot open the release PR. The default token permission can stay read-only. 2. Settings > General > Pull Requests: allow squash merging, and preferably only squash merging, with the default commit message set to "Pull request title" (or "Pull request title and description"). The PR title then becomes the commit release-please reads. A merge commit's own subject is ignored, so a PR merged that way releases only if its commits are conventional. 3. Optional: set the repository variable `CI_RELEASE_WINDOWS` to `false` to keep uploading the Windows files by hand. The draft then waits for you to publish it. Run `scripts/release_files.sh finish v<version>` (with `GH_REPO` set) after uploading them, so `SHA256SUMS` lists them. They then have no attestation, since they were not built by CI. 4. Optional: make the "PR title" check required under branch protection or a ruleset. Note that the release PR is opened with `GITHUB_TOKEN`, which starts no checks on it, so required checks would block it unless it is excluded or a token is used.
hckrman101 (Migrated from github.com) reviewed 2026-11-10 18:12:24 +00:00
hckrman101 (Migrated from github.com) left a comment

Read through the workflows, scripts and config. Permissions are scoped sensibly (workflow-level contents: read, write and id-token only on the release/build/publish jobs, pull-requests: read for the title check with no checkout under pull_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.json says 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_admission fixture 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 next too, which this PR drops as described.

Read through the workflows, scripts and config. Permissions are scoped sensibly (workflow-level `contents: read`, write and `id-token` only on the release/build/publish jobs, `pull-requests: read` for the title check with no checkout under `pull_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.json` says 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_admission` fixture 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 `next` too, which this PR drops as described.
@ -0,0 +1,3 @@
{
hckrman101 (Migrated from github.com) commented 2026-11-10 18:12:24 +00:00

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.

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.
NotRexed commented 2026-11-10 23:31:16 +00:00 (Migrated from github.com)

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.json 2.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.json gets last-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), plus docs/releasing.md.

🤖 Generated with Claude Code

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.json` 2.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.json` gets `last-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`), plus `docs/releasing.md`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Commenting is not possible because the repository is archived.
No description provided.