9.1 KiB
Forgejo Actions Runner Setup
Prerequisites for the workflows under .forgejo/workflows/ to execute
end-to-end on the self-hosted forge at
http://10.0.0.11:3000/magicciv/magicciv.
Forgejo Actions is drone-compatible; runners register via
forgejo-runner. Files in
.forgejo/workflows/*.yml are picked up automatically.
Runner inventory
| Workflow job | Labels required | Host | Status |
|---|---|---|---|
ci.yml — regression |
linux,apricot |
apricot | REQUIRED (blocks all CI) |
release.yml — linux_build |
linux,apricot |
apricot | REQUIRED |
release.yml — wasm_build |
linux,apricot |
apricot | REQUIRED |
release.yml — macos_build |
macos,arm64 |
(unassigned) | TODO(prerequisite) |
release.yml — windows_build |
linux,apricot |
apricot (cargo-xwin cross-compile) | REQUIRED — same runner as linux_build, no Windows host needed |
Until a runner with matching labels registers, the corresponding jobs queue indefinitely on Forgejo. CI (push-to-main) only needs the apricot runner; release (tag push) needs all four.
Apricot runner (linux,apricot)
One-time registration on apricot:
ssh lilith@apricot.lan
cd ~
# 1. Fetch forgejo-runner (latest release binary for linux/amd64).
curl -L -o forgejo-runner \
https://code.forgejo.org/forgejo/runner/releases/download/nightly/forgejo-runner-nightly-linux-amd64
chmod +x forgejo-runner
sudo mv forgejo-runner /usr/local/bin/
# 2. Create a runner token in Forgejo:
# http://10.0.0.11:3000/-/admin/actions/runners → "Create new runner"
# Copy the registration token.
export FORGEJO_RUNNER_TOKEN='<paste-token-from-ui>'
# 3. Register.
mkdir -p ~/.local/share/forgejo-runner
cd ~/.local/share/forgejo-runner
forgejo-runner register \
--no-interactive \
--instance http://10.0.0.11:3000 \
--token "$FORGEJO_RUNNER_TOKEN" \
--name apricot \
--labels "linux,apricot"
# 4. Install as a systemd service (preferred) or run in a tmux session.
# systemd unit (recommended):
cat <<'UNIT' | sudo tee /etc/systemd/system/forgejo-runner.service
[Unit]
Description=Forgejo Actions runner
After=network.target
[Service]
Type=simple
User=lilith
WorkingDirectory=/home/lilith/.local/share/forgejo-runner
ExecStart=/usr/local/bin/forgejo-runner daemon
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
UNIT
sudo systemctl daemon-reload
sudo systemctl enable --now forgejo-runner
sudo systemctl status forgejo-runner
Toolchain prerequisites on apricot
The apricot runner must have these installed for the CI + release jobs to succeed:
- Rust toolchain — matches
src/simulator/rust-toolchain.toml(if present) or latest stable.cargo,rustc,rustupon$PATH. - wasm-pack —
cargo install wasm-pack(needed forbuild-wasm.sh). - gdtoolkit —
pip install --user gdtoolkit(providesgdlint,gdformat). Ensure~/.local/binis on$PATHfor the runner user. - Flatpak Godot —
flatpak install flathub org.godotengine.Godot(system-wide; the runner user must be able to launch it with--filesystem=home). - Python 3.11+ — for
tools/validate-game-data.py,tools/objectives-report.py,tools/autoplay-batch.shhelpers. - pnpm — for the WASM guide build (
corepack enable pnpm). - Standard unix tools —
jq,curl,tar,zip,git.
Secrets required on apricot
Set in Forgejo at
http://10.0.0.11:3000/magicciv/magicciv/settings/actions/secrets:
FORGEJO_RELEASE_TOKEN— personal access token withwrite:repositoryscope for themagiccivorg. Used byrelease.ymlto create releases and upload assets via the REST API.
macOS runner (macos,arm64) — TODO
No macOS runner is currently registered. Until one is, the
macos_build job in release.yml will queue indefinitely on every
tag push but will NOT block the other platforms' builds.
Registration
On the target macOS host (Apple Silicon):
# 1. Install forgejo-runner (arm64 build).
curl -L -o forgejo-runner \
https://code.forgejo.org/forgejo/runner/releases/download/nightly/forgejo-runner-nightly-darwin-arm64
chmod +x forgejo-runner
sudo mv forgejo-runner /usr/local/bin/
# 2. Register with macos,arm64 labels.
mkdir -p ~/Library/Application\ Support/forgejo-runner
cd ~/Library/Application\ Support/forgejo-runner
forgejo-runner register \
--no-interactive \
--instance http://10.0.0.11:3000 \
--token "$FORGEJO_RUNNER_TOKEN" \
--name mac-release \
--labels "macos,arm64"
# 3. Run as a launchd agent or in a persistent tmux.
forgejo-runner daemon
Toolchain prerequisites on the macOS runner
- Rust + the aarch64 target:
(x86_64 cross-compilation is out of scope for the current objective; the macOS build is arm64-native only.)curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rustup target add aarch64-apple-darwin - Godot editor —
brew install --cask godotor direct download from godotengine.org. Must be invocable asgodoton$PATH. - Godot export templates — matching the editor version, installed
to
~/Library/Application Support/Godot/export_templates/. - Xcode command line tools —
xcode-select --install. Required for Godot's macOS export to codesign (even ad-hoc) the resulting.app. - Standard tools —
jq,zip,git.
Known open items
- Code signing / notarization is explicitly out of scope for p2-06;
the archive ships as an unsigned
.appinside a.zip.
Windows build (cross-compiled from apricot via cargo-xwin)
Windows binaries are produced on the existing apricot Linux runner —
no Windows host is required. The .dll uses MSVC ABI via
cargo-xwin, and Godot's
Windows export template runs natively from Linux. Verified end-to-end
2026-04-25 (p2-06b).
Toolchain prerequisites on apricot
# 1. Add the Windows MSVC target to rustup.
rustup target add x86_64-pc-windows-msvc
# 2. Install cargo-xwin (downloads ~1.5GB of MS SDK on first build,
# cached at ~/.cache/cargo-xwin/).
cargo install cargo-xwin
# 3. clang is required as the front-end compiler (already present on
# apricot via clang-21 rpm). lld is NOT required — cargo-xwin's
# bundled xwin sub-tool resolves the linker via the MSVC SDK.
Verify
cd ~/Code/@projects/@magic-civilization
bash src/simulator/build-gdext.sh x86_64-pc-windows-msvc # ~3min first run
BUILD_WINDOWS_DLL=0 EXPORT_STAGED=1 bash tools/export-single.sh windows verify-$(date +%s)
ls .local/build/godot/verify-*/windows/
# → MagicCivilization.exe + engine/addons/magic_civ_physics/magic_civ_physics.x86_64.dll
Boots-and-plays smoke
Wine is not installed on apricot; smoke verification needs either:
dnf install wineon apricot (sudo), then run the .exe via wine, OR- A real Windows machine to unzip + double-click the archive.
Budget overruns
Objective p2-10 targets a median CI completion time of 15 minutes. If a stage consistently blows this budget, demote it to a nightly workflow rather than letting CI drift red / slow:
| Stage | Demotion target |
|---|---|
cargo test --features gpu |
.forgejo/workflows/nightly.yml (new file) |
| Full 10-seed T300 autoplay batch | .forgejo/workflows/nightly.yml |
| GUT integration tests (if added) | .forgejo/workflows/nightly.yml |
The 1-seed T100 smoke batch stays on push-to-main CI — it's the minimum-viable determinism + no-stall check and must gate every commit.
Watcher / TTS alert
Objective p2-10 acceptance bullet: a Testwright watcher observes the
runner and a failed main triggers a TTS alert (personality ravdess02,
mandatory per project Rail-4). The watcher only observes the API — it
does NOT re-run tests.
Installation on apricot (one-time)
ssh apricot
# 1. Copy the systemd unit from the repo.
mkdir -p ~/.config/systemd/user
cp ~/Code/project-buildspace/magic-civilization/.forgejo/forge-watch.service \
~/.config/systemd/user/forge-watch.service
# 2. The script sources ~/.config/tokens/forgejo.sh automatically.
# Confirm the token file exists and exports FORGEJO_TOKEN + FORGEJO_URL.
source ~/.config/tokens/forgejo.sh
echo "token=${FORGEJO_TOKEN:0:8}... url=$FORGEJO_URL"
# 3. Enable + start.
systemctl --user daemon-reload
systemctl --user enable --now forge-watch
systemctl --user status forge-watch
# 4. Confirm linger is active (survives logout).
loginctl show-user lilith | grep Linger
# → Linger=yes (already set for act_runner)
Logs
journalctl --user -u forge-watch -f
State file
~/.local/state/forge-watch/state.json — tracks last-seen SHA, last
status, and already-alerted run IDs. Delete to reset.
Verification gate (manual)
Push a deliberately-broken commit on a throwaway branch whose CI fails,
confirm the watcher logs "ALERT:" within ≤ POLL_INTERVAL seconds and
emits the TTS via ravdess02. Record timestamp in p2-10 evidence block.
Script source
tools/forge-watch.sh in the repo root (installed to
~/Code/project-buildspace/magic-civilization/tools/forge-watch.sh on
apricot via the normal autocommit sync).