CI - astrosteveo/gdh GitHub Wiki
CI
.github/workflows/ci.yml runs two jobs on every pull request and every push to main. A newer push to the same pull request, or to main, cancels the run in progress for it.
| Job | Runs on | What it runs |
|---|---|---|
| Band tests | ubuntu-latest (GitHub's runners) |
claude plugin test ., with Claude Code 2.1.296 from npm. It needs no Claude login. |
| pytest (GPU and Xvfb displays) | andromeda-gpu, the self-hosted runner on the development machine |
uv sync --locked, then uv run pytest -ra |
The band is the row gdh's mod shows above Claude Code's prompt in a Godot project. Its tests are hooks/band.test.tsx.
Why the suite runs on a self-hosted runner
gdh runs each game on an X display of its own, of one of two kinds: the GPU display (weston and Xwayland, drawing on the GPU) and the Xvfb display (a virtual X server, drawing through the CPU). See docs/displays.md. The suite runs every test on both. The GPU display needs a GPU that weston can composite on, and GitHub's hosted runners have none, so the suite runs on the development machine (RTX 5080, Arch Linux, Godot 4.7.2). The machine stays on, so the runner is always available.
tests/conftest.py skips every test when godot or Xvfb is missing, and pytest then reports success although no test ran. So the job checks for godot, Xvfb, weston, Xwayland and uv first, and fails when one is missing.
Only one gdh test run uses the machine at a time (conftest.py takes a lock), so a CI run waits while a local uv run pytest runs, and the other way round.
Fork pull requests
The repository is public, so code from a fork's pull request must never run on the development machine. Two settings prevent it:
- The pytest job runs only for pushes and for pull requests whose branch is in this repository (
github.event.pull_request.head.repo.full_name == github.repository). A fork's pull request skips it and still runs the band tests. - The repository requires approval before workflows run for any outside contributor's pull request (Settings > Actions > General, "Require approval for all external contributors").
Keep both when changing the workflow. A new job that should run on the machine needs the same if:.
The runner
| Name and labels | andromeda-gpu: self-hosted, Linux, X64, gpu |
| Folder | ~/.local/share/actions-runner/gdh (runner 2.338.0) |
| Service | systemd user unit ~/.config/systemd/user/actions-runner-gdh.service, enabled for default.target |
| Jobs' working folder | ~/.local/share/actions-runner/gdh/_work |
systemd lingering is on for the account (loginctl show-user $USER -p Linger prints Linger=yes), which means systemd starts the account's user services at boot and keeps them running with nobody logged in. So the runner is up whenever the machine is. The runner runs as the user, so jobs get XDG_RUNTIME_DIR (weston needs it) and the same Godot, GPU and caches as a local run. The runner updates itself when GitHub releases a new version.
When it was registered, the runner saved its PATH and environment in .path and .env in its folder, and jobs get those. After installing a tool in a folder that isn't on that PATH, add the folder to .path and restart the service.
Commands
systemctl --user status actions-runner-gdh # is it running
journalctl --user -u actions-runner-gdh -f # its log
systemctl --user restart actions-runner-gdh
The runner's status on GitHub: gh api repos/astrosteveo/gdh/actions/runners.
Registering it again
To move the runner to another machine, or after removing it:
cd ~/.local/share/actions-runner/gdh
systemctl --user stop actions-runner-gdh
./config.sh remove --token "$(gh api -X POST repos/astrosteveo/gdh/actions/runners/remove-token --jq .token)"
./config.sh --unattended --url https://github.com/astrosteveo/gdh --name andromeda-gpu --labels gpu --work _work \
--token "$(gh api -X POST repos/astrosteveo/gdh/actions/runners/registration-token --jq .token)"
systemctl --user start actions-runner-gdh