ci(pr-builds): build pull requests that are not drafts, and publish them signed for testers #353

Open
gab9281 wants to merge 6 commits from gab9281/Longshot:ci/pr-builds into main
Member

Why

Testers can only try a pull request today by checking it out and building it from source, so most of the hardware we need (AMD, Steam Deck, 4–8 GB cards, Windows) never runs a change before it is merged. This is the CI half of #337: every pull request that is not a draft gets its builders built, signed with a key of its own and published, so the Longshot Launcher can offer it to testers.

What changed

  • ci: .forgejo/workflows/pr-build.yml, on pull_request (opened, a push, reopened, edited; Forgejo's payload calls a push synchronized, GitHub's synchronize: both build, and both cancel the build before). A pull request that is not a draft (no WIP: or [WIP] title) builds its head with build-linux.yml and build-windows.yml, named pr-<number>-<first 8 hex of the head>, as the run's artifacts. They build as a pull request does: build-linux.yml and build-windows.yml gain RELEASE_BUILD, set for a channel's version only, so a pr- tag names the files but takes the pull request caches and never writes the release-only download cache. It is the pull request's own run, a fork's: a read-only token and no secret, so nothing in it is signed or published. A new push cancels the build before it. An edit builds only a head with no build yet: taking WIP: off builds once, and editing the description afterwards builds nothing (Forgejo's payload doesn't say what was edited, so name asks the runs and releases API; a run that passed counts only with its builders' artifacts, since an edit's run that built nothing passes too).
  • ci: .forgejo/workflows/pr-publish.yml, every 15 minutes and by hand. It checks out main and runs no pull request's code. For each open, non-draft pull request whose head has a pr-build.yml run that passed with both builders, it takes the two files from that run's artifacts and tools.lock from the head, writes SHA256SUMS, signs it with PR_SIGNING_KEY (never RELEASE_SIGNING_KEY), checks it against scripts/release_keys.json's pull_request_keys, and publishes a pre-release on no channel through release.py publish. A draft a failed publish left is published again by the next run; any error fails that build alone, and each build's folder is removed after it. The pull request's title goes on the release page as a code span, never as Markdown. Then it prunes: the builds of pull requests closed, merged or back to draft (the open ones read page by page until an empty page), each one's past its newest 2, and drafts a failed run left over 6 hours (their age with the server's offset). Without the secret it publishes nothing and says so in the run. Key or not, it ends by counting who has looked at each pull request that is not a draft (pr_builds.py counts: the people other than its author who commented on it or reviewed it, bots left out) into the release pull-requests (a pre-release on no channel, never a version; its one file pull-requests.json replaced each run), which the launcher's picker orders by: fewest people first, then the oldest.
  • scripts: scripts/pr_builds.py (name, pending, publish, prune, counts, verify), on top of release.py's API, signing, publishing and download (release.download gains to=, streaming a large file and leaving none of it behind when it fails), and check_pr_description.py's draft rule. An artifact's zip gives up exactly the one file expected, never a path.
  • scripts: scripts/release_keys.json gains pull_request_keys (empty: no key yet), and pr_builds.py refuses a list that shares a key with the release keys.
  • docs: docs/releases.md, "Pull request builds" (the same text as the launcher's copy, in its branch feat/pr-builds), and the CI table; RELEASING.md, "The pull request key (Longshot)", the one-time setup.
  • tests: tests/test_pr_builds.py: the tag an event builds (an edit's run that built nothing is no build), the pending builds (a draft left is published again), every page of open pull requests, one failing build leaving the others to go on, the title as text, the prune (never anything but a pr- build; a draft's age with the server's offset), the one file taken from an artifact, signing with a pull request key and never a release key, who has looked (the author, bots and deleted accounts are no one; a review counts), the counts never pruned, that a push is synchronized or synchronize, that a pr- tag is no release build in either builder, and that the build run has no secret while the publishing run checks out main alone.

Flags and settings

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
Secret PR_SIGNING_KEY The pull request key's private PEM: pr-publish.yml signs pull requests' builds with it unset: builds run, nothing is published Set once the key is in release_keys.json and the launcher (RELEASING.md, The pull request key) CI — —
release_keys.json pull_request_keys The keys a pull request's build may be signed with (the launcher's ReleaseKeys.PullRequestBuiltIn) empty Add the key from keygen CI, the launcher — —

Measurements

main: cf605c85 (2026-11-13)
this PR: ci/pr-builds @ ed0d385e
Hardware: none: CI only (Forgejo's runners; the local checks on Linux)
Scene: none: CI only
Method: the change's game-free checks (tests/test_pr_builds.py, and the checks that read the files it changes: release, Windows-on-Linux, PR description, AppImage package retry and player build, Linux Docker packages, recomplauncher.json, no release lookup, tools.lock), actionlint 1.7.12 with .forgejo/actionlint.yaml, and read-only runs of pending and prune --dry-run against git.magicbean.dev; tests/run_all.py on Linux, and Forgejo CI on this pull request.
How to reproduce: python -I -B tests/test_pr_builds.py; python -I scripts/pr_builds.py pending; python -I scripts/pr_builds.py prune --dry-run

main @ cf605c85 this PR @ ed0d385e
tests/test_pr_builds.py no script 32 tests, OK
test_release.py, test_windows_on_linux.py, test_check_pr_description.py, test_appimage_package_retry.py, test_appimage_player_build.py, test_linux_docker_packages.py, test_recomplauncher_json.py, test_no_release_lookup.py, test_tools_lock.py OK OK
tests/run_all.py (Linux, 16 at once) test_module_ids.py, test_pad_layout.py fail (only these two run on main) 495 passed, 2 failed (the same two, failing on main too: neither reads a file this PR changes), 63 skipped
pr_builds.py counts --dry-run (live, read-only) — 63 pull requests out of draft counted
pr-build.yml's first real build (run 4600, at ae6c238) — passed: the Linux AppImage, the Windows Builder zip and the Windows Vulkan back end
Forgejo CI on the pull request (ci.yml: the title and light checks; pr-description.yml; third-party.yml; pr-build.yml, a draft so nothing built) — all passed
actionlint 1.7.12, every workflow clean clean
pr_builds.py pending (live, read-only) — runs; 120 open pull requests, 57 not drafts, none with a pr-build.yml run yet, so nothing to publish
pr_builds.py prune --dry-run (live, read-only) — runs; nothing to prune
Ran 32 tests in 0.087s
OK

Testing

Tested: the checks above on Linux. pending and prune --dry-run against the live API: the runs filter (workflow_id, head_sha) answers in under a second, and run payloads carry pull_request.draft.

pr-build.yml on this pull request: its run at 8a6095bc built nothing (Forgejo's synchronized, fixed in ae6c238), and its run at ae6c238 built both builders as artifacts (run 4600).

Not tested: pr-publish.yml runs only from main, so its first run is after the merge (the counts release included), and publishes nothing until PR_SIGNING_KEY is set. The artifact download (/actions/artifacts/{id}/zip) and release.py publish with a fork's head as target_commitish have not run against the server yet. Nothing in the game changes.

Needs other testers: None: the launcher side, which installs these builds, is its own pull request, MagicBeanDev/LongshotLauncher pull request 59, which requires this one.

Screenshots

Nothing on screen.

Risk and rollback

  • Runner time. Each push to a non-draft pull request builds both builders the release way (about as long as a nightly). 57 pull requests aren't drafts today. A draft builds nothing, and a new push cancels the build before it. Deleting pr-build.yml stops it.
  • What the key vouches for. It says "CI built this pull request at this commit", not that anyone reviewed it: any non-draft pull request, from anyone, can get a signed build once the key is set. The launcher installs one only when a tester picks it, warns first, and shows those labelled testing wanted by default. A fork's run Forgejo holds for approval builds nothing until a maintainer approves it.
  • Releases. pr- pre-releases are on no channel (release.py's newest and the launcher's ignore them), and the prune touches only pr-<number>-<8 hex> tags.
  • Reverting the commit is enough; pr- releases already published can be deleted with prune on an empty list of pull requests.

Reviewer notes

Start with scripts/pr_builds.py name and pending, then the two workflows. The key itself (keygen, the secret, the launcher's built-in list) is a maintainer's step, on purpose: RELEASING.md, The pull request key.

Issues

See #337

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main. (main moved to 0caf0618 after this was opened; the branch merges onto it without a conflict, and the rebase waits for a force push to the fork)
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above). (on Linux at ed0d385e: 495 passed, 2 failed, 63 skipped; the two, test_module_ids.py and test_pad_layout.py, fail on main at cf605c85 too, named under Measurements)
  • Tested in the game, or what wasn't is named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • A check under tests/ that reads changed source updated in this PR, not weakened. (test_pr_builds.py reads build-linux.yml and build-windows.yml, changed here; the other checks that read them pass unchanged)
  • Docs updated.

🤖 Generated with Claude Code

## Why Testers can only try a pull request today by checking it out and building it from source, so most of the hardware we need (AMD, Steam Deck, 4–8 GB cards, Windows) never runs a change before it is merged. This is the CI half of #337: every pull request that is not a draft gets its builders built, signed with a key of its own and published, so the Longshot Launcher can offer it to testers. ## What changed - ci: `.forgejo/workflows/pr-build.yml`, on `pull_request` (opened, a push, reopened, edited; Forgejo's payload calls a push `synchronized`, GitHub's `synchronize`: both build, and both cancel the build before). A pull request that is not a draft (no `WIP:` or `[WIP]` title) builds its head with `build-linux.yml` and `build-windows.yml`, named `pr-<number>-<first 8 hex of the head>`, as the run's artifacts. They build as a pull request does: `build-linux.yml` and `build-windows.yml` gain `RELEASE_BUILD`, set for a channel's version only, so a `pr-` tag names the files but takes the pull request caches and never writes the release-only download cache. It is the pull request's own run, a fork's: a read-only token and no secret, so nothing in it is signed or published. A new push cancels the build before it. An edit builds only a head with no build yet: taking `WIP:` off builds once, and editing the description afterwards builds nothing (Forgejo's payload doesn't say what was edited, so `name` asks the runs and releases API; a run that passed counts only with its builders' artifacts, since an edit's run that built nothing passes too). - ci: `.forgejo/workflows/pr-publish.yml`, every 15 minutes and by hand. It checks out main and runs no pull request's code. For each open, non-draft pull request whose head has a `pr-build.yml` run that passed with both builders, it takes the two files from that run's artifacts and `tools.lock` from the head, writes `SHA256SUMS`, signs it with `PR_SIGNING_KEY` (never `RELEASE_SIGNING_KEY`), checks it against `scripts/release_keys.json`'s `pull_request_keys`, and publishes a pre-release on no channel through `release.py publish`. A draft a failed publish left is published again by the next run; any error fails that build alone, and each build's folder is removed after it. The pull request's title goes on the release page as a code span, never as Markdown. Then it prunes: the builds of pull requests closed, merged or back to draft (the open ones read page by page until an empty page), each one's past its newest 2, and drafts a failed run left over 6 hours (their age with the server's offset). Without the secret it publishes nothing and says so in the run. Key or not, it ends by counting who has looked at each pull request that is not a draft (`pr_builds.py counts`: the people other than its author who commented on it or reviewed it, bots left out) into the release `pull-requests` (a pre-release on no channel, never a version; its one file `pull-requests.json` replaced each run), which the launcher's picker orders by: fewest people first, then the oldest. - scripts: `scripts/pr_builds.py` (`name`, `pending`, `publish`, `prune`, `counts`, `verify`), on top of `release.py`'s API, signing, publishing and download (`release.download` gains `to=`, streaming a large file and leaving none of it behind when it fails), and `check_pr_description.py`'s draft rule. An artifact's zip gives up exactly the one file expected, never a path. - scripts: `scripts/release_keys.json` gains `pull_request_keys` (empty: no key yet), and `pr_builds.py` refuses a list that shares a key with the release keys. - docs: `docs/releases.md`, "Pull request builds" (the same text as the launcher's copy, in its branch `feat/pr-builds`), and the CI table; `RELEASING.md`, "The pull request key (Longshot)", the one-time setup. - tests: `tests/test_pr_builds.py`: the tag an event builds (an edit's run that built nothing is no build), the pending builds (a draft left is published again), every page of open pull requests, one failing build leaving the others to go on, the title as text, the prune (never anything but a `pr-` build; a draft's age with the server's offset), the one file taken from an artifact, signing with a pull request key and never a release key, who has looked (the author, bots and deleted accounts are no one; a review counts), the counts never pruned, that a push is `synchronized` or `synchronize`, that a `pr-` tag is no release build in either builder, and that the build run has no secret while the publishing run checks out main alone. ## Flags and settings | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | Secret `PR_SIGNING_KEY` | The pull request key's private PEM: `pr-publish.yml` signs pull requests' builds with it | unset: builds run, nothing is published | Set once the key is in `release_keys.json` and the launcher (RELEASING.md, The pull request key) | CI | — | — | | `release_keys.json` `pull_request_keys` | The keys a pull request's build may be signed with (the launcher's `ReleaseKeys.PullRequestBuiltIn`) | empty | Add the key from keygen | CI, the launcher | — | — | ## Measurements main: cf605c85 (2026-11-13) this PR: ci/pr-builds @ ed0d385e Hardware: none: CI only (Forgejo's runners; the local checks on Linux) Scene: none: CI only Method: the change's game-free checks (`tests/test_pr_builds.py`, and the checks that read the files it changes: release, Windows-on-Linux, PR description, AppImage package retry and player build, Linux Docker packages, recomplauncher.json, no release lookup, tools.lock), actionlint 1.7.12 with `.forgejo/actionlint.yaml`, and read-only runs of `pending` and `prune --dry-run` against git.magicbean.dev; `tests/run_all.py` on Linux, and Forgejo CI on this pull request. How to reproduce: `python -I -B tests/test_pr_builds.py`; `python -I scripts/pr_builds.py pending`; `python -I scripts/pr_builds.py prune --dry-run` | | main @ cf605c85 | this PR @ ed0d385e | |---|---|---| | `tests/test_pr_builds.py` | no script | 32 tests, OK | | `test_release.py`, `test_windows_on_linux.py`, `test_check_pr_description.py`, `test_appimage_package_retry.py`, `test_appimage_player_build.py`, `test_linux_docker_packages.py`, `test_recomplauncher_json.py`, `test_no_release_lookup.py`, `test_tools_lock.py` | OK | OK | | `tests/run_all.py` (Linux, 16 at once) | `test_module_ids.py`, `test_pad_layout.py` fail (only these two run on main) | 495 passed, 2 failed (the same two, failing on main too: neither reads a file this PR changes), 63 skipped | | `pr_builds.py counts --dry-run` (live, read-only) | — | 63 pull requests out of draft counted | | `pr-build.yml`'s first real build (run 4600, at ae6c238) | — | passed: the Linux AppImage, the Windows Builder zip and the Windows Vulkan back end | | Forgejo CI on the pull request (`ci.yml`: the title and light checks; `pr-description.yml`; `third-party.yml`; `pr-build.yml`, a draft so nothing built) | — | all passed | | actionlint 1.7.12, every workflow | clean | clean | | `pr_builds.py pending` (live, read-only) | — | runs; 120 open pull requests, 57 not drafts, none with a `pr-build.yml` run yet, so nothing to publish | | `pr_builds.py prune --dry-run` (live, read-only) | — | runs; nothing to prune | ``` Ran 32 tests in 0.087s OK ``` ## Testing **Tested:** the checks above on Linux. `pending` and `prune --dry-run` against the live API: the runs filter (`workflow_id`, `head_sha`) answers in under a second, and run payloads carry `pull_request.draft`. `pr-build.yml` on this pull request: its run at 8a6095bc built nothing (Forgejo's `synchronized`, fixed in ae6c238), and its run at ae6c238 built both builders as artifacts (run 4600). **Not tested:** `pr-publish.yml` runs only from main, so its first run is after the merge (the counts release included), and publishes nothing until `PR_SIGNING_KEY` is set. The artifact download (`/actions/artifacts/{id}/zip`) and `release.py publish` with a fork's head as `target_commitish` have not run against the server yet. Nothing in the game changes. **Needs other testers:** None: the launcher side, which installs these builds, is its own pull request, [MagicBeanDev/LongshotLauncher pull request 59](https://git.magicbean.dev/MagicBeanDev/LongshotLauncher/pulls/59), which requires this one. ## Screenshots Nothing on screen. ## Risk and rollback - **Runner time.** Each push to a non-draft pull request builds both builders the release way (about as long as a nightly). 57 pull requests aren't drafts today. A draft builds nothing, and a new push cancels the build before it. Deleting `pr-build.yml` stops it. - **What the key vouches for.** It says "CI built this pull request at this commit", not that anyone reviewed it: any non-draft pull request, from anyone, can get a signed build once the key is set. The launcher installs one only when a tester picks it, warns first, and shows those labelled `testing wanted` by default. A fork's run Forgejo holds for approval builds nothing until a maintainer approves it. - **Releases.** `pr-` pre-releases are on no channel (`release.py`'s `newest` and the launcher's ignore them), and the prune touches only `pr-<number>-<8 hex>` tags. - Reverting the commit is enough; `pr-` releases already published can be deleted with `prune` on an empty list of pull requests. ## Reviewer notes Start with `scripts/pr_builds.py` `name` and `pending`, then the two workflows. The key itself (keygen, the secret, the launcher's built-in list) is a maintainer's step, on purpose: RELEASING.md, The pull request key. ## Issues See #337 ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [ ] Rebased on current `main`. (main moved to 0caf0618 after this was opened; the branch merges onto it without a conflict, and the rebase waits for a force push to the fork) - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). (on Linux at ed0d385e: 495 passed, 2 failed, 63 skipped; the two, `test_module_ids.py` and `test_pad_layout.py`, fail on main at cf605c85 too, named under Measurements) - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. (`test_pr_builds.py` reads `build-linux.yml` and `build-windows.yml`, changed here; the other checks that read them pass unchanged) - [x] Docs updated. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
ci(pr-builds): build pull requests that are not drafts, and publish them signed for testers
All checks were successful
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 4s
PR description / Description follows the template (pull_request_target) Successful in 5s
CI / Workflow lint (actionlint) (pull_request) Successful in 7s
Pull request build / The version (pull_request) Successful in 6s
Pull request build / appimage (pull_request) Has been skipped
Pull request build / Longshot Builder zip (pull_request) Has been skipped
Pull request build / Windows Vulkan back end (llvm-mingw) (pull_request) Has been skipped
Pull request build / Linux builder (pull_request) Successful in 0s
Pull request build / Windows builder (pull_request) Successful in 0s
Third-party parts / As their notes say (pull_request) Successful in 9s
ab52449311
pr-build.yml builds a non-draft pull request's head (the AppImage and the Windows builder, named
pr-<number>-<8 hex>) in the pull request's own run, with no secret. pr-publish.yml runs main's
code every 15 minutes: it takes the builders of runs that passed, signs SHA256SUMS with the pull
request key (PR_SIGNING_KEY, never the release key) and publishes a pre-release on no channel,
then prunes. scripts/pr_builds.py does both; tests/test_pr_builds.py checks it. See #337.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
fix(pr-builds): the review's findings
Some checks failed
Pull request build / Windows Vulkan back end (llvm-mingw) (pull_request) Successful in 10m35s
Pull request build / appimage (pull_request) Successful in 14m0s
Website / Website on Cloudflare (pull_request_target) Has been skipped
PR description / Description follows the template (pull_request_target) Successful in 4s
Pull request build / The version (pull_request) Failing after 5s
Pull request build / Linux builder (pull_request) Failing after 0s
Pull request build / Windows builder (pull_request) Failing after 0s
Pull request build / Longshot Builder zip (pull_request) Successful in 2m31s
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 3s
CI / Workflow lint (actionlint) (pull_request) Successful in 5s
Third-party parts / As their notes say (pull_request) Successful in 6s
fe7a502995
- build-linux.yml, build-windows.yml: RELEASE_BUILD, set for a channel's version only, decides the caches; a pr- tag names
  the files and builds as a pull request does (its caches, never the release-only download cache).
- pr_builds.py: an edit's run that passed but built nothing is no build (a run that passed counts with its builders'
  artifacts); a draft a failed publish left is published again instead of waiting for the prune; open pull requests are
  read until an empty page; any error fails that build alone and each build's folder is removed; a draft's age reads the
  server's offset; the title goes on the release page as a code span, never as Markdown; the artifact download is
  release.download's, which streams with to=.
- docs/releases.md: the same, and "a pull request that is not a draft" for "may be tested".

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Author
Member

fe7a5029 applies a code review's findings. A pr- tag no longer builds in release mode: the builders take the pull request caches, and never write the release-only download cache. pr_builds.py: an edit's run that built nothing no longer counts as a build; a draft left by a failed publish is published again; open pull requests are read until an empty page, so prune never takes an open one for closed; one build's error no longer stops the others, and each build's folder is removed; drafts' ages use the server's offset; the title is a code span on the release page; the download is release.download's. 28 tests (was 21), the checks that read the changed files, and actionlint pass; CI passed on fe7a5029. run_all.py has not run yet (see its box).

fe7a5029 applies a code review's findings. A pr- tag no longer builds in release mode: the builders take the pull request caches, and never write the release-only download cache. pr_builds.py: an edit's run that built nothing no longer counts as a build; a draft left by a failed publish is published again; open pull requests are read until an empty page, so prune never takes an open one for closed; one build's error no longer stops the others, and each build's folder is removed; drafts' ages use the server's offset; the title is a code span on the release page; the download is release.download's. 28 tests (was 21), the checks that read the changed files, and actionlint pass; CI passed on fe7a5029. run_all.py has not run yet (see its box).
Author
Member

tests/run_all.py on Linux at fe7a5029: 495 passed, 2 failed, 63 skipped. The two failures, test_module_ids.py and test_pad_layout.py, fail on main at cf605c85 too and read no file this PR changes. run_all box ticked.

tests/run_all.py on Linux at fe7a5029: 495 passed, 2 failed, 63 skipped. The two failures, test_module_ids.py and test_pad_layout.py, fail on main at cf605c85 too and read no file this PR changes. run_all box ticked.
gab9281 changed title from WIP: ci(pr-builds): build pull requests that are not drafts, and publish them signed for testers to ci(pr-builds): build pull requests that are not drafts, and publish them signed for testers 2026-11-14 04:24:31 +00:00
Author
Member

The launcher side is open: MagicBeanDev/LongshotLauncher#59 (the pull request picker, filtered to testing wanted by default). It requires this one.

The launcher side is open: https://git.magicbean.dev/MagicBeanDev/LongshotLauncher/pulls/59 (the pull request picker, filtered to testing wanted by default). It requires this one.
docs(releases): the launcher's picker never lists a draft; letters in order within one word
All checks were successful
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Successful in 3s
CI / Conventional Commit title (pull_request) Successful in 2s
CI / Workflow lint (actionlint) (pull_request) Successful in 5s
Pull request build / The version (pull_request) Successful in 5s
Pull request build / Longshot Builder zip (pull_request) Has been skipped
Pull request build / Windows Vulkan back end (llvm-mingw) (pull_request) Has been skipped
Pull request build / appimage (pull_request) Has been skipped
Pull request build / Linux builder (pull_request) Successful in 0s
Pull request build / Windows builder (pull_request) Successful in 0s
Third-party parts / As their notes say (pull_request) Successful in 9s
0c9042447a
The same text as the launcher's copy (MagicBeanDev/LongshotLauncher pull request 59).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Author
Member

0c904244: docs/releases.md, identical to the launcher's copy (MagicBeanDev/LongshotLauncher#59): the picker never lists a draft, and its letters-in-order search works within one word. Docs only.

0c904244: docs/releases.md, identical to the launcher's copy (https://git.magicbean.dev/MagicBeanDev/LongshotLauncher/pulls/59): the picker never lists a draft, and its letters-in-order search works within one word. Docs only.
fix(release): download(to=) leaves no part of a file behind when it fails
All checks were successful
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Successful in 7s
CI / Conventional Commit title (pull_request) Successful in 4s
CI / Workflow lint (actionlint) (pull_request) Successful in 8s
Pull request build / The version (pull_request) Successful in 6s
Pull request build / appimage (pull_request) Has been skipped
Pull request build / Longshot Builder zip (pull_request) Has been skipped
Pull request build / Linux builder (pull_request) Successful in 0s
Pull request build / Windows builder (pull_request) Successful in 0s
Pull request build / Windows Vulkan back end (llvm-mingw) (pull_request) Has been skipped
Third-party parts / As their notes say (pull_request) Successful in 10s
8a6095bc2a
The same file as the launcher's (MagicBeanDev/LongshotLauncher pull request 59), from its code review.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
fix(pr-builds): a push is "synchronized" in Forgejo's payload
All checks were successful
Third-party parts / The same as upstream (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Successful in 4s
Pull request build / Longshot Builder zip (pull_request) Successful in 2m51s
CI / Conventional Commit title (pull_request) Successful in 4s
CI / Workflow lint (actionlint) (pull_request) Successful in 10s
Pull request build / The version (pull_request) Successful in 9s
Third-party parts / As their notes say (pull_request) Successful in 12s
Pull request build / appimage (pull_request) Successful in 14m33s
Pull request build / Linux builder (pull_request) Successful in 0s
Pull request build / Windows Vulkan back end (llvm-mingw) (pull_request) Successful in 11m35s
Pull request build / Windows builder (pull_request) Successful in 0s
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
ae6c238ab2
pr-build.yml's run of 8a6095bc, a push to this pull request out of draft, built nothing: Forgejo's payload says
"synchronized" for a push, GitHub's "synchronize", and name() knew only the second. A push also never cancelled the
build before it, for the same reason. Both spellings build and cancel now.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
feat(pr-builds): count who has looked at each pull request, for the launcher's order
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 3s
CI / Workflow lint (actionlint) (pull_request) Successful in 4s
Third-party parts / As their notes say (pull_request) Successful in 6s
Pull request build / Longshot Builder zip (pull_request) Successful in 2m10s
PR description / Description follows the template (pull_request_target) Failing after 8s
Pull request build / Windows Vulkan back end (llvm-mingw) (pull_request) Successful in 10m18s
Pull request build / appimage (pull_request) Successful in 12m59s
Pull request build / The version (pull_request) Failing after 5s
Pull request build / Windows builder (pull_request) Failing after 0s
Pull request build / Linux builder (pull_request) Failing after 0s
ed0d385e7a
pr-publish.yml, key or not, ends with `pr_builds.py counts`: for each open pull request that is not a draft, the people
other than its author who commented on it or reviewed it (bots and deleted accounts left out, logins in any case), in the
release "pull-requests" (a pre-release on no channel, never a version; its one file, pull-requests.json, replaced each
run). The launcher's picker shows first those the fewest people looked at, then the oldest (MagicBeanDev/LongshotLauncher
pull request 59). The prune never touches it. docs/releases.md: the same as the launcher's copy.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Author
Member

Since fe7a5029: 8a6095bc, download(to=) leaves no partial file; ae6c238, Forgejo calls a push synchronized (not synchronize), so a push built nothing, now it builds and the first real build passed (run 4600: AppImage, Builder zip, Windows back end); ed0d385e, pr_builds.py counts publishes who has looked at each pull request (release pull-requests), which the launcher (MagicBeanDev/LongshotLauncher pull request 59) orders by. 32 tests; run_all.py at ed0d385e: the same 2 failures as main. Not rebased yet on main's 0caf0618 (clean merge): the box says so.

Since fe7a5029: 8a6095bc, download(to=) leaves no partial file; ae6c238, Forgejo calls a push `synchronized` (not `synchronize`), so a push built nothing, now it builds and the first real build passed (run 4600: AppImage, Builder zip, Windows back end); ed0d385e, `pr_builds.py counts` publishes who has looked at each pull request (release `pull-requests`), which the launcher (MagicBeanDev/LongshotLauncher pull request 59) orders by. 32 tests; run_all.py at ed0d385e: the same 2 failures as main. Not rebased yet on main's 0caf0618 (clean merge): the box says so.
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 3s
CI / Workflow lint (actionlint) (pull_request) Successful in 4s
Third-party parts / As their notes say (pull_request) Successful in 6s
Pull request build / Longshot Builder zip (pull_request) Successful in 2m10s
PR description / Description follows the template (pull_request_target) Failing after 8s
Pull request build / Windows Vulkan back end (llvm-mingw) (pull_request) Successful in 10m18s
Pull request build / appimage (pull_request) Successful in 12m59s
Pull request build / The version (pull_request) Failing after 5s
Pull request build / Windows builder (pull_request) Failing after 0s
Pull request build / Linux builder (pull_request) Failing after 0s
This pull request doesn't have enough approvals yet. 0 of 1 approvals granted.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'ci/pr-builds:gab9281-ci/pr-builds'
git switch 'gab9281-ci/pr-builds'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!353
No description provided.