magicciv/.forgejo/RUNNER_SETUP.md
Natalie c88e136469 fix(@projects): 🐛 update deployment and guide workflows
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-10 03:38:03 -07:00

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, rustup on $PATH.
  • wasm-packcargo install wasm-pack (needed for build-wasm.sh).
  • gdtoolkitpip install --user gdtoolkit (provides gdlint, gdformat). Ensure ~/.local/bin is on $PATH for the runner user.
  • Flatpak Godotflatpak 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 toolsjq, 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):

# 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:
    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 editorbrew install --cask godot or direct download from godotengine.org. 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 toolsxcode-select --install. Required for Godot's macOS export to codesign (even ad-hoc) the resulting .app.
  • Standard toolsjq, 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, 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 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)

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).