Idea: install a pull request's build from the Longshot Launcher, to help test it #337

Open
opened 2026-11-14 01:58:28 +00:00 by gab9281 · 5 comments
Member

The idea

Let anyone who wants to help test a pull request install its build from the Longshot Launcher: Build another version > A pull request, pick the PR by number or title, and the launcher installs that PR's builder and builds the game with it, next to their other versions. Today a tester has to check out the PR and build it from source (forge.py pr checkout, docs/development.md), which only developers can do, so most of the hardware we need runs on (AMD, Steam Deck, 4–8 GB cards, Windows) never sees a PR before it is merged.

Where it stands

  • CI: #353 builds every non-draft PR's builders on each push and publishes them as a pre-release on no channel, pr-<n>-<8 hex>, signed with a separate pull request key (never the release key). It also publishes pull-requests.json (release pull-requests): how many people other than the author have commented on or reviewed each open PR.
  • Launcher: LongshotLauncher pull request 59, a draft, incomplete: it needs #353 merged and the pull request key made, and has never installed a build end to end.

How it works

  1. The picker gets a fifth choice, after the channels: A pull request.
    • One fuzzy search box: a number (332, #332) or words of the title or author, as typed or as letters in order within one word (rendr targts).
    • Drafts are never listed (CI builds none), and neither is a PR labelled for the other system only (platform/windows on Linux; platform/linux or platform/steam-deck on Windows).
    • A Testing wanted filter, on by default; off, every other open non-draft PR shows.
    • The order gets eyes on what has fewest: fewest people other than the author who commented or reviewed first, then the oldest.
    • Each row shows the title, author and build state (ready, built from an earlier push, or not built yet), and a Read button opens the PR.
  2. A PR build is its own version, never an update. It is on no channel; its only update is a newer push of the same PR, and the home says when the PR was merged or closed.
  3. Trust: the launcher checks a pr- build with the pull request keys only, and a channel's build with the release key only.

What must stay true

  • The release key never signs PR code.
  • No game data in any build, and none leaves the PC: PR builders are like release builders, Longshot's code and the tools of tools.lock.
  • Players who never open the picker see nothing new.

V2

Mocks, not built: none of this is in #353 or LongshotLauncher PR 59. The screens are from a throwaway prototype of the launcher (Linux, a test home with placeholder builds; the pull requests and their CI states are the real ones of 2026-11-14).

  • Saves of its own per PR build. Each PR build plays with its own user folder (--user, on both systems), longshot-pull-requests/<n> beside the shared one. The first time it starts, the shared save folder is copied there; after that the build never touches the player's saves. A newer push keeps them; they go with its last build. (V1: the saves are shared and the picker asks to export them first.)

  • How did it go?, after the game closes. Like the crash window: when a PR build's game exits normally (a crash is the crash window's), the launcher comes to the front and asks. The launcher has no sign-in, so it posts nothing itself: it copies the report and opens the PR for the tester to paste it under their own name. Also on the build's row.

    ┌──────────────────────────────────────────────────────────┐
    │  How did PR #353 go?                                     │
    │  Tell the people who wrote it: a tested PR is merged     │
    │  sooner.                                                 │
    │                                                          │
    │   ( ) Works    ( ) Broken    ( ) Some of both            │
    │   ┌ What you saw, and where you played ───────────────┐  │
    │   │                                                   │  │
    │   └───────────────────────────────────────────────────┘  │
    │   Sent with it: PR #353 at ed0d385e, launcher 1.4.0,     │
    │   Linux 6.12, 16 GB, AMD GPU.                            │
    │   Never: a path, your name, your saves.                  │
    │                                                          │
    │          [ Not now ]   [ Copy and open the PR ]          │
    └──────────────────────────────────────────────────────────┘
    
  • PR merged or closed: delete? Once its PR is merged or closed, a PR build gets no more pushes, so its row asks PR merged, delete this build? (or PR closed, …) with a Delete button. It opens the usual confirmation, which says its own saves go with it; nothing is deleted without that click, and the build stays until then. Read and How did it go? sit on the same line, so the row's actions fit (in V1 Read runs off the row). The screen is the prototype's, where that button was still Move to nightly:

    A merged PR build's row: Read, How did it go?, and the delete offer (here still Move to nightly)

  • The pull requests on a page of their own, with ‹ Channels to go back, and the keyboard kept inside every dialog: Tab goes round the dialog's controls only (today it walks into the home behind it, so Enter can press Play unseen), and a page change puts the focus on the new page's first control.

    Which pull request?, a page of its own

  • Say where CI is with the newest push rather than Not built yet: Waiting to be built, Building now, Ready in a few minutes (built, waiting for the next publish), Its build failed, from pr-build.yml's runs in the public actions API. Below, a real one:

    #353: Its build failed

  • The tester's hardware first, marked your hardware: PRs labelled for their GPU makers (gpu/amd, gpu/nvidia, gpu/intel, gpu/igpu) or platform/steam-deck on a Deck (found by its board, board_vendor = Valve), then the rest in their order. (No open, non-draft PR has this PC's labels today, so no screen.)

  • Sign only the PRs a maintainer let through. CI keeps building every non-draft PR, but pr-publish.yml signs and publishes only those with testing wanted, or whose author is in a repository variable PR_TRUSTED_AUTHORS (the job's token cannot ask Forgejo who may push). A build whose PR loses the label is deleted. The review of #353 ranked an unreviewed PR getting a signed build its top risk.

  • Tell the PR you're testing it (opt-in): the tester signs in with their git.magicbean.dev account from the launcher, and a short comment goes on the PR from their account, which counts them among the people who looked. Needs an OAuth app registered on git.magicbean.dev (an admin's to make), so it has no mock.

Screenshots (V1)

The launcher from LongshotLauncher PR 59 on Linux (KDE, 125%), against git.magicbean.dev's open PRs. No PR build is published yet and this launcher has no pull request key, so every row says Not built yet and none can be picked.

Build another version, the new choice:

The version picker with "A pull request"

Testing wanted on (the default):

Testing wanted on

Testing wanted off: every open PR that is not a draft. The dialog stays inside the window and its choices scroll:

Testing wanted off

A search, vk:

Searching vk

The first mock, for the home with a PR build installed (not built yet; its labels, states and commits are made up):

Home with a PR build (mock)

Anything else

Related: #44 (local problem reports), the test requests (docs/test-requests.md), docs/releases.md.

### The idea Let anyone who wants to help test a pull request install its build from the Longshot Launcher: *Build another version > A pull request*, pick the PR by number or title, and the launcher installs that PR's builder and builds the game with it, next to their other versions. Today a tester has to check out the PR and build it from source (`forge.py pr checkout`, docs/development.md), which only developers can do, so most of the hardware we need runs on (AMD, Steam Deck, 4–8 GB cards, Windows) never sees a PR before it is merged. #### Where it stands - **CI:** [#353](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/353) builds every non-draft PR's builders on each push and publishes them as a pre-release on no channel, `pr-<n>-<8 hex>`, signed with a separate **pull request key** (never the release key). It also publishes `pull-requests.json` (release `pull-requests`): how many people other than the author have commented on or reviewed each open PR. - **Launcher:** [LongshotLauncher pull request 59](https://git.magicbean.dev/MagicBeanDev/LongshotLauncher/pulls/59), a draft, incomplete: it needs #353 merged and the pull request key made, and has never installed a build end to end. #### How it works 1. **The picker gets a fifth choice**, after the channels: *A pull request*. - **One fuzzy search box**: a number (`332`, `#332`) or words of the title or author, as typed or as letters in order within one word (`rendr targts`). - **Drafts are never listed** (CI builds none), and neither is a PR labelled for the other system only (`platform/windows` on Linux; `platform/linux` or `platform/steam-deck` on Windows). - **A *Testing wanted* filter**, on by default; off, every other open non-draft PR shows. - **The order gets eyes on what has fewest**: fewest people other than the author who commented or reviewed first, then the oldest. - Each row shows the title, author and build state (*ready*, *built from an earlier push*, or *not built yet*), and a *Read* button opens the PR. 2. **A PR build is its own version, never an update.** It is on no channel; its only update is a newer push of the same PR, and the home says when the PR was merged or closed. 3. **Trust:** the launcher checks a `pr-` build with the pull request keys only, and a channel's build with the release key only. #### What must stay true - **The release key never signs PR code.** - **No game data in any build**, and none leaves the PC: PR builders are like release builders, Longshot's code and the tools of `tools.lock`. - Players who never open the picker see nothing new. #### V2 Mocks, not built: none of this is in #353 or LongshotLauncher PR 59. The screens are from a throwaway prototype of the launcher (Linux, a test home with placeholder builds; the pull requests and their CI states are the real ones of 2026-11-14). - [ ] **Saves of its own per PR build.** Each PR build plays with its own user folder (`--user`, on both systems), `longshot-pull-requests/<n>` beside the shared one. The first time it starts, the shared `save` folder is copied there; after that the build never touches the player's saves. A newer push keeps them; they go with its last build. (V1: the saves are shared and the picker asks to export them first.) - [ ] **How did it go?, after the game closes.** Like the crash window: when a PR build's game exits normally (a crash is the crash window's), the launcher comes to the front and asks. The launcher has no sign-in, so it posts nothing itself: it copies the report and opens the PR for the tester to paste it under their own name. Also on the build's row. ``` ┌──────────────────────────────────────────────────────────┐ │ How did PR #353 go? │ │ Tell the people who wrote it: a tested PR is merged │ │ sooner. │ │ │ │ ( ) Works ( ) Broken ( ) Some of both │ │ ┌ What you saw, and where you played ───────────────┐ │ │ │ │ │ │ └───────────────────────────────────────────────────┘ │ │ Sent with it: PR #353 at ed0d385e, launcher 1.4.0, │ │ Linux 6.12, 16 GB, AMD GPU. │ │ Never: a path, your name, your saves. │ │ │ │ [ Not now ] [ Copy and open the PR ] │ └──────────────────────────────────────────────────────────┘ ``` - [ ] **PR merged or closed: delete?** Once its PR is merged or closed, a PR build gets no more pushes, so its row asks *PR merged, delete this build?* (or *PR closed, …*) with a **Delete** button. It opens the usual confirmation, which says its own saves go with it; nothing is deleted without that click, and the build stays until then. *Read* and *How did it go?* sit on the same line, so the row's actions fit (in V1 *Read* runs off the row). The screen is the prototype's, where that button was still *Move to nightly*: ![A merged PR build's row: Read, How did it go?, and the delete offer (here still Move to nightly)](https://git.magicbean.dev/attachments/c7171cea-2d86-496e-998a-f81b80e86384) - [ ] **The pull requests on a page of their own**, with *‹ Channels* to go back, and the keyboard kept inside every dialog: Tab goes round the dialog's controls only (today it walks into the home behind it, so Enter can press *Play* unseen), and a page change puts the focus on the new page's first control. ![Which pull request?, a page of its own](https://git.magicbean.dev/attachments/08c03adc-d50e-45a1-be27-651de39b0f0e) - [ ] **Say where CI is with the newest push** rather than *Not built yet*: *Waiting to be built*, *Building now*, *Ready in a few minutes* (built, waiting for the next publish), *Its build failed*, from `pr-build.yml`'s runs in the public actions API. Below, a real one: ![#353: Its build failed](https://git.magicbean.dev/attachments/b4842a5e-5dfb-4f1f-a981-f63d7c91b02e) - [ ] **The tester's hardware first**, marked *your hardware*: PRs labelled for their GPU makers (`gpu/amd`, `gpu/nvidia`, `gpu/intel`, `gpu/igpu`) or `platform/steam-deck` on a Deck (found by its board, `board_vendor` = Valve), then the rest in their order. (No open, non-draft PR has this PC's labels today, so no screen.) - [ ] **Sign only the PRs a maintainer let through.** CI keeps building every non-draft PR, but `pr-publish.yml` signs and publishes only those with `testing wanted`, or whose author is in a repository variable `PR_TRUSTED_AUTHORS` (the job's token cannot ask Forgejo who may push). A build whose PR loses the label is deleted. The review of #353 ranked an unreviewed PR getting a signed build its top risk. - [ ] **Tell the PR you're testing it** (opt-in): the tester signs in with their git.magicbean.dev account from the launcher, and a short comment goes on the PR from their account, which counts them among the people who looked. Needs an OAuth app registered on git.magicbean.dev (an admin's to make), so it has no mock. #### Screenshots (V1) The launcher from LongshotLauncher PR 59 on Linux (KDE, 125%), against git.magicbean.dev's open PRs. No PR build is published yet and this launcher has no pull request key, so every row says *Not built yet* and none can be picked. *Build another version*, the new choice: ![The version picker with "A pull request"](https://git.magicbean.dev/attachments/c4c3537c-ecab-40b2-b0c5-e0dbf6ed21af) *Testing wanted* on (the default): ![Testing wanted on](https://git.magicbean.dev/attachments/292ca820-46ad-41db-92a7-5206ad5fa89b) *Testing wanted* off: every open PR that is not a draft. The dialog stays inside the window and its choices scroll: ![Testing wanted off](https://git.magicbean.dev/attachments/c85f2a07-bf05-4f24-9bad-012b0f1f9884) A search, `vk`: ![Searching vk](https://git.magicbean.dev/attachments/0590b6be-e486-4bb2-a347-7e435ecc3352) The first mock, for the home with a PR build installed (not built yet; its labels, states and commits are made up): ![Home with a PR build (mock)](https://git.magicbean.dev/attachments/f45acf42-0c6f-4204-9308-c5572d86a98f) ### Anything else Related: [#44](https://git.magicbean.dev/MagicBeanDev/Longshot/issues/44) (local problem reports), the test requests (docs/test-requests.md), docs/releases.md.
Author
Member

Two additions:

  • CI side: PR 283 (WIP) runs the builders on CircleCI for each pull request and keeps the AppImage, the Windows zip and longshot_vk.dll as the run's artifacts. That is step 1 here; what's left is where the launcher downloads them from and how it trusts them.
  • The picker: one search box takes a number (332, #332) or words of the title or author (hud light, dlss), fuzzy. The launcher reads the open PRs once (GET /repos/MagicBeanDev/Longshot/pulls?state=open, no sign-in needed) and matches locally. A Testing wanted filter is on by default, and each PR has a Read button that opens it on git.magicbean.dev. A PR the launcher can't install stays in the list, greyed out, with the reason (no label yet, still building).
Two additions: - **CI side:** [PR 283](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/283) (WIP) runs the builders on CircleCI for each pull request and keeps the AppImage, the Windows zip and `longshot_vk.dll` as the run's artifacts. That is step 1 here; what's left is where the launcher downloads them from and how it trusts them. - **The picker:** one search box takes a number (`332`, `#332`) or words of the title or author (`hud light`, `dlss`), fuzzy. The launcher reads the open PRs once (`GET /repos/MagicBeanDev/Longshot/pulls?state=open`, no sign-in needed) and matches locally. A **Testing wanted** filter is on by default, and each PR has a **Read** button that opens it on git.magicbean.dev. A PR the launcher can't install stays in the list, greyed out, with the reason (no label yet, still building).
Owner

Yes, definitely something we should add!

Yes, definitely something we should add!
Author
Member

For the ci : tester wanted only or non-draft pr ?

For the ci : tester wanted only or non-draft pr ?
Author
Member

Both halves are open:

  • CI: #353 builds pull requests that are not drafts and publishes them signed with the pull request key.
  • Launcher: MagicBeanDev/LongshotLauncher#59 adds Build another version > A pull request, a fuzzy search by number or title, filtered to testing wanted by default, with a Read button on each. It requires 353.
Both halves are open: - CI: https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/353 builds pull requests that are not drafts and publishes them signed with the pull request key. - Launcher: https://git.magicbean.dev/MagicBeanDev/LongshotLauncher/pulls/59 adds *Build another version > A pull request*, a fuzzy search by number or title, filtered to `testing wanted` by default, with a Read button on each. It requires 353.
Member

A concrete case for this idea: co-op (#355) needs many testers before it can be reviewed, and today they have to build it from source. The discussion on how to get it to them is in #463 .

One question for #353 that follows from it: it builds pull requests that are not drafts, and 355 is a draft that will stay one for a while. Could a draft be opted in, for example with a label a maintainer adds, so that long-running work can use the same route?

A concrete case for this idea: co-op (https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/355) needs many testers before it can be reviewed, and today they have to build it from source. The discussion on how to get it to them is in https://git.magicbean.dev/MagicBeanDev/Longshot/issues/463 . One question for https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/353 that follows from it: it builds pull requests that are not drafts, and 355 is a draft that will stay one for a while. Could a draft be opted in, for example with a label a maintainer adds, so that long-running work can use the same route?
Sign in to join this conversation.
No milestone
No project
No assignees
3 participants
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#337
No description provided.