# 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`](https://code.forgejo.org/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: ```bash ssh lilith@apricot.local 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='' # 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`, `rustup` on `$PATH`. - **wasm-pack** — `cargo install wasm-pack` (needed for `build-wasm.sh`). - **gdtoolkit** — `pip install --user gdtoolkit` (provides `gdlint`, `gdformat`). Ensure `~/.local/bin` is on `$PATH` for 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.sh` helpers. - **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 with `write:repository` scope for the `magicciv` org. Used by `release.yml` to 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): ```bash # 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**: ```bash curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rustup target add aarch64-apple-darwin ``` (x86_64 cross-compilation is out of scope for the current objective; the macOS build is arm64-native only.) - **Godot editor** — `brew install --cask godot` or direct download from [godotengine.org](https://godotengine.org/download/macos/). Must be invocable as `godot` on `$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 `.app` inside 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`](https://github.com/rust-cross/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 ```bash # 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 ```bash 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 wine` on 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) ```bash 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 ```bash 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).