feat(@projects/@magic-civilization): ✨ add runner script support
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
d3a63abe90
commit
819f33ed38
7 changed files with 265 additions and 17 deletions
|
|
@ -3,7 +3,6 @@
|
|||
"includes": [
|
||||
"iron_axe",
|
||||
"dwarven_plate",
|
||||
"healing_draught",
|
||||
"direwolf_alpha_pelt",
|
||||
"golem_core",
|
||||
"phase_gauntlet",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { useEffect, type ReactElement } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
import type { ObjectiveRecord } from './types'
|
||||
import { STATUS_ICON, STATUS_LABEL } from './types'
|
||||
import {
|
||||
|
|
@ -31,7 +32,7 @@ export function ObjectiveModal({ objective, onClose }: ObjectiveModalProps): Rea
|
|||
if (e.target === e.currentTarget) onClose()
|
||||
}
|
||||
|
||||
return (
|
||||
return createPortal(
|
||||
<ModalBackdrop onClick={handleBackdrop} role="dialog" aria-modal="true">
|
||||
<ModalPanel>
|
||||
<ModalHeader>
|
||||
|
|
@ -57,6 +58,7 @@ export function ObjectiveModal({ objective, onClose }: ObjectiveModalProps): Rea
|
|||
{objective.summary || 'No summary recorded for this objective.'}
|
||||
</ModalSummary>
|
||||
</ModalPanel>
|
||||
</ModalBackdrop>
|
||||
</ModalBackdrop>,
|
||||
document.body,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,19 +44,25 @@ REQUIRED_PACKAGES=(
|
|||
)
|
||||
|
||||
CHECK_ONLY=false
|
||||
WITH_RUNNER=false
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--check) CHECK_ONLY=true ;;
|
||||
--with-runner) WITH_RUNNER=true ;;
|
||||
--help|-h)
|
||||
echo "Usage: $0 [--check]"
|
||||
echo " (no args) Install missing packages via rpm-ostree --apply-live"
|
||||
echo " --check Exit 0 if all packages are installed, 1 otherwise"
|
||||
echo "Usage: $0 [--check] [--with-runner]"
|
||||
echo " (no args) Install missing packages via rpm-ostree --apply-live"
|
||||
echo " --check Exit 0 if all packages are installed, 1 otherwise"
|
||||
echo " --with-runner Also install + register a forgejo-runner"
|
||||
echo " (requires FORGEJO_* env — see .env.example)"
|
||||
exit 0
|
||||
;;
|
||||
*) echo "Unknown argument: $arg"; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
|
||||
# ── Preconditions ────────────────────────────────────────────────────
|
||||
if ! command -v rpm-ostree &>/dev/null; then
|
||||
echo -e "${RED}This script targets bootc / rpm-ostree systems (Bluefin, Silverblue, Kinoite).${NC}"
|
||||
|
|
@ -162,3 +168,48 @@ echo -e " layer — typically at:"
|
|||
echo -e " ${DIM}~/Code/bootc-bluefin/containerfiles/Containerfile.desktop-core${NC}"
|
||||
echo -e " Rebuild + redeploy via ${DIM}~/Code/bootc-bluefin/rebuild-with-parser.sh${NC}"
|
||||
echo -e " (or equivalent build.sh / deploy.sh)."
|
||||
|
||||
# ── Optional: forgejo-runner install + register + persist ──────────
|
||||
if $WITH_RUNNER; then
|
||||
echo ""
|
||||
echo -e "${BLUE}─────────────────────────────────────────────────${NC}"
|
||||
echo -e "${BLUE} Forgejo runner (Linux / amd64 / $(hostname -s))${NC}"
|
||||
echo -e "${BLUE}─────────────────────────────────────────────────${NC}"
|
||||
# shellcheck source=../run/common.sh
|
||||
source "$REPO_ROOT/scripts/run/common.sh"
|
||||
# shellcheck source=./lib/runner.sh
|
||||
source "$REPO_ROOT/scripts/dev-setup/lib/runner.sh"
|
||||
export RUNNER_OS=linux
|
||||
export RUNNER_ARCH=amd64
|
||||
export RUNNER_NAME="$(hostname -s)"
|
||||
export RUNNER_LABELS="self-hosted,linux,${RUNNER_NAME}"
|
||||
runner_install_binary
|
||||
runner_register
|
||||
# systemd-user persistence (survives reboot thanks to `loginctl enable-linger`).
|
||||
UNIT="$HOME/.config/systemd/user/forgejo-runner.service"
|
||||
mkdir -p "$(dirname "$UNIT")"
|
||||
cat > "$UNIT" <<UNITFILE
|
||||
[Unit]
|
||||
Description=Forgejo Actions runner (${RUNNER_NAME})
|
||||
Documentation=https://code.forgejo.org/forgejo/runner
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=%h/.local/bin/forgejo-runner daemon --config %h/.local/share/forgejo-runner/config.yaml
|
||||
WorkingDirectory=%h/.local/share/forgejo-runner
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
UNITFILE
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable --now forgejo-runner.service
|
||||
loginctl enable-linger "$USER" 2>/dev/null || true
|
||||
echo " runner: systemd user unit enabled (linger=on, persists across reboot)"
|
||||
runner_verify_online || true
|
||||
fi
|
||||
|
|
|
|||
101
scripts/dev-setup/lib/runner.sh
Normal file
101
scripts/dev-setup/lib/runner.sh
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
#!/usr/bin/env bash
|
||||
# Shared forgejo-runner install/register/persist helpers for the
|
||||
# per-OS dev-setup scripts. Sourced, never executed directly.
|
||||
#
|
||||
# Callers provide:
|
||||
# - RUNNER_OS (darwin | linux)
|
||||
# - RUNNER_ARCH (arm64 | amd64)
|
||||
# - RUNNER_LABELS (comma-separated, e.g. "self-hosted,macos,arm64")
|
||||
# - RUNNER_NAME (display name, e.g. $(hostname -s))
|
||||
# Env required (load via scripts/run/common.sh cascade):
|
||||
# - FORGEJO_HOST e.g. http://forge.black.local
|
||||
# - FORGEJO_ORG org the runner registers against
|
||||
# - FORGEJO_RUNNER_TOKEN org-scoped registration token
|
||||
#
|
||||
# Callers (osx.sh / bluefin.sh / linux.sh) also decide the persistence
|
||||
# layer — these helpers only handle the binary + registration step;
|
||||
# each OS file installs its own launchd plist or systemd user unit.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
RUNNER_BIN="$HOME/.local/bin/forgejo-runner"
|
||||
RUNNER_DIR="$HOME/.local/share/forgejo-runner"
|
||||
RUNNER_URL_BASE="https://code.forgejo.org/forgejo/runner/releases/download/nightly"
|
||||
|
||||
runner_require_env() {
|
||||
local missing=()
|
||||
for v in FORGEJO_HOST FORGEJO_ORG FORGEJO_RUNNER_TOKEN; do
|
||||
[[ -z "${!v:-}" ]] && missing+=("$v")
|
||||
done
|
||||
if (( ${#missing[@]} > 0 )); then
|
||||
echo " runner: missing required env: ${missing[*]}" >&2
|
||||
echo " runner: set in .env.local — see .env.example" >&2
|
||||
return 2
|
||||
fi
|
||||
}
|
||||
|
||||
runner_install_binary() {
|
||||
mkdir -p "$(dirname "$RUNNER_BIN")" "$RUNNER_DIR"
|
||||
if [[ -x "$RUNNER_BIN" ]]; then
|
||||
echo " runner: binary already present at $RUNNER_BIN"
|
||||
return 0
|
||||
fi
|
||||
local url="$RUNNER_URL_BASE/forgejo-runner-nightly-$RUNNER_OS-$RUNNER_ARCH"
|
||||
echo " runner: downloading $url"
|
||||
curl -fsSL -o "$RUNNER_BIN.tmp" "$url"
|
||||
chmod +x "$RUNNER_BIN.tmp"
|
||||
mv "$RUNNER_BIN.tmp" "$RUNNER_BIN"
|
||||
echo " runner: installed → $RUNNER_BIN"
|
||||
}
|
||||
|
||||
# Register (or re-register) at org scope. Removes .runner file if the
|
||||
# existing registration has different labels or a different name — this
|
||||
# rebinds the runner to the org without manual DB intervention.
|
||||
runner_register() {
|
||||
runner_require_env || return $?
|
||||
cd "$RUNNER_DIR"
|
||||
|
||||
if [[ -f .runner ]]; then
|
||||
local existing_name existing_labels
|
||||
existing_name=$(jq -r '.name // ""' .runner 2>/dev/null || echo "")
|
||||
existing_labels=$(jq -c '.labels // []' .runner 2>/dev/null || echo "[]")
|
||||
if [[ "$existing_name" == "$RUNNER_NAME" ]] && \
|
||||
[[ "$existing_labels" == "[\"${RUNNER_LABELS//,/\",\"}\"]" ]]; then
|
||||
echo " runner: already registered as '$RUNNER_NAME' with labels [$RUNNER_LABELS]"
|
||||
return 0
|
||||
fi
|
||||
echo " runner: existing registration ($existing_name, labels=$existing_labels) differs — re-registering"
|
||||
rm -f .runner
|
||||
fi
|
||||
|
||||
"$RUNNER_BIN" register \
|
||||
--no-interactive \
|
||||
--instance "$FORGEJO_HOST" \
|
||||
--token "$FORGEJO_RUNNER_TOKEN" \
|
||||
--name "$RUNNER_NAME" \
|
||||
--labels "$RUNNER_LABELS" >/dev/null
|
||||
echo " runner: registered as '$RUNNER_NAME' at $FORGEJO_HOST/$FORGEJO_ORG (labels: $RUNNER_LABELS)"
|
||||
}
|
||||
|
||||
# Verify the runner appears online via the Forgejo API within a short
|
||||
# polling window. Uses FORGEJO_RUNNER_TOKEN only if also passed as a
|
||||
# personal access token; otherwise requires FORGEJO_ADMIN_TOKEN to read
|
||||
# /api/v1/user/actions/runners.
|
||||
runner_verify_online() {
|
||||
local tok="${FORGEJO_ADMIN_TOKEN:-${FORGEJO_TOKEN:-}}"
|
||||
if [[ -z "$tok" ]]; then
|
||||
echo " runner: skipping online-verify (no admin/personal token — set FORGEJO_ADMIN_TOKEN to enable)"
|
||||
return 0
|
||||
fi
|
||||
local tries=0 online=""
|
||||
while (( tries < 12 )); do
|
||||
online=$(curl -fsS -H "Authorization: token $tok" \
|
||||
"$FORGEJO_HOST/api/v1/orgs/$FORGEJO_ORG/actions/runners" 2>/dev/null \
|
||||
| jq -r ".runners[] | select(.name==\"$RUNNER_NAME\") | .status" 2>/dev/null || echo "")
|
||||
[[ "$online" == "online" ]] && { echo " runner: online"; return 0; }
|
||||
tries=$((tries + 1))
|
||||
sleep 2
|
||||
done
|
||||
echo " runner: NOT online after 24s; check service logs" >&2
|
||||
return 1
|
||||
}
|
||||
|
|
@ -459,3 +459,47 @@ echo -e " ${DIM}./run verify${NC} — full lint + test pipeline"
|
|||
echo -e " ${DIM}./run test:golden${NC} — cross-language golden-vector parity"
|
||||
echo -e " ${DIM}./run autoplay 1${NC} — single-seed 500-turn simulation"
|
||||
echo ""
|
||||
|
||||
# ── Optional: forgejo-runner install + register + persist ──────────
|
||||
if $WITH_RUNNER; then
|
||||
echo ""
|
||||
echo -e "${BLUE}─────────────────────────────────────────────────${NC}"
|
||||
echo -e "${BLUE} Forgejo runner (Linux / amd64 / $(hostname -s))${NC}"
|
||||
echo -e "${BLUE}─────────────────────────────────────────────────${NC}"
|
||||
# shellcheck source=../run/common.sh
|
||||
source "$REPO_ROOT/scripts/run/common.sh"
|
||||
# shellcheck source=./lib/runner.sh
|
||||
source "$REPO_ROOT/scripts/dev-setup/lib/runner.sh"
|
||||
export RUNNER_OS=linux
|
||||
export RUNNER_ARCH=amd64
|
||||
export RUNNER_NAME="$(hostname -s)"
|
||||
export RUNNER_LABELS="self-hosted,linux,${RUNNER_NAME}"
|
||||
runner_install_binary
|
||||
runner_register
|
||||
UNIT="$HOME/.config/systemd/user/forgejo-runner.service"
|
||||
mkdir -p "$(dirname "$UNIT")"
|
||||
cat > "$UNIT" <<UNITFILE
|
||||
[Unit]
|
||||
Description=Forgejo Actions runner (${RUNNER_NAME})
|
||||
Documentation=https://code.forgejo.org/forgejo/runner
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=%h/.local/bin/forgejo-runner daemon --config %h/.local/share/forgejo-runner/config.yaml
|
||||
WorkingDirectory=%h/.local/share/forgejo-runner
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
UNITFILE
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable --now forgejo-runner.service
|
||||
loginctl enable-linger "$USER" 2>/dev/null || true
|
||||
echo " runner: systemd user unit enabled (linger=on, persists across reboot)"
|
||||
runner_verify_online || true
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
# macOS dev environment setup for Magic Civilization
|
||||
# Usage: ./scripts/dev-setup/osx.sh [--skip-godot] [--skip-rust]
|
||||
# Usage: ./scripts/dev-setup/osx.sh [--skip-godot] [--skip-rust] [--with-runner]
|
||||
set -euo pipefail
|
||||
|
||||
RED='\033[0;31m'
|
||||
|
|
@ -12,14 +12,18 @@ NC='\033[0m'
|
|||
|
||||
SKIP_GODOT=false
|
||||
SKIP_RUST=false
|
||||
WITH_RUNNER=false
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--skip-godot) SKIP_GODOT=true ;;
|
||||
--skip-rust) SKIP_RUST=true ;;
|
||||
--with-runner) WITH_RUNNER=true ;;
|
||||
--help|-h)
|
||||
echo "Usage: $0 [--skip-godot] [--skip-rust]"
|
||||
echo " --skip-godot Skip Godot 4 installation"
|
||||
echo " --skip-rust Skip Rust toolchain installation"
|
||||
echo "Usage: $0 [--skip-godot] [--skip-rust] [--with-runner]"
|
||||
echo " --skip-godot Skip Godot 4 installation"
|
||||
echo " --skip-rust Skip Rust toolchain installation"
|
||||
echo " --with-runner Also install + register a forgejo-runner"
|
||||
echo " (requires FORGEJO_* env — see .env.example)"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
|
@ -262,9 +266,56 @@ if [ ${#FAILED[@]} -gt 0 ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
if $WITH_RUNNER; then
|
||||
echo ""
|
||||
echo -e "${BLUE}─────────────────────────────────────────────────${NC}"
|
||||
echo -e "${BLUE} Forgejo runner (macOS / arm64 / plum)${NC}"
|
||||
echo -e "${BLUE}─────────────────────────────────────────────────${NC}"
|
||||
source "$REPO_ROOT/scripts/run/common.sh"
|
||||
source "$REPO_ROOT/scripts/dev-setup/lib/runner.sh"
|
||||
export RUNNER_OS=darwin
|
||||
export RUNNER_ARCH=arm64
|
||||
export RUNNER_NAME="$(hostname -s)"
|
||||
export RUNNER_LABELS="self-hosted,macos,arm64"
|
||||
runner_install_binary
|
||||
runner_register
|
||||
# launchd persistence — user-agent, no root needed.
|
||||
PLIST="$HOME/Library/LaunchAgents/com.forgejo.runner.plist"
|
||||
if [[ ! -f "$PLIST" ]]; then
|
||||
mkdir -p "$(dirname "$PLIST")"
|
||||
cat > "$PLIST" <<PLIST
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key><string>com.forgejo.runner</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>$HOME/.local/bin/forgejo-runner</string>
|
||||
<string>daemon</string>
|
||||
<string>--config</string>
|
||||
<string>$HOME/.local/share/forgejo-runner/config.yaml</string>
|
||||
</array>
|
||||
<key>WorkingDirectory</key><string>$HOME/.local/share/forgejo-runner</string>
|
||||
<key>RunAtLoad</key><true/>
|
||||
<key>KeepAlive</key><true/>
|
||||
<key>StandardOutPath</key><string>$HOME/.local/share/forgejo-runner/runner.out.log</string>
|
||||
<key>StandardErrorPath</key><string>$HOME/.local/share/forgejo-runner/runner.err.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
PLIST
|
||||
echo " runner: wrote $PLIST"
|
||||
fi
|
||||
launchctl unload "$PLIST" 2>/dev/null || true
|
||||
launchctl load "$PLIST"
|
||||
echo " runner: launchd agent loaded (RunAtLoad + KeepAlive)"
|
||||
runner_verify_online || true
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e " ${GREEN}Ready to go.${NC} Try:"
|
||||
echo -e " ${DIM}./run verify${NC} — full lint + test pipeline"
|
||||
echo -e " ${DIM}./run play${NC} — launch the game"
|
||||
echo -e " ${DIM}./run guide${NC} — start guide dev server"
|
||||
$WITH_RUNNER && echo -e " ${DIM}launchctl list | grep forgejo${NC} — verify runner daemon"
|
||||
echo ""
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
# Variables already set in the shell ALWAYS win (never clobber). Lines
|
||||
# are plain `KEY=VALUE`; inline comments (`#`) are stripped; surrounding
|
||||
# single/double quotes on values are stripped.
|
||||
_load_envfile() {
|
||||
load_envfile() {
|
||||
local f="$1"
|
||||
[[ -r "$f" ]] || return 0
|
||||
local line key val
|
||||
|
|
@ -36,12 +36,12 @@ _load_envfile() {
|
|||
done < "$f"
|
||||
}
|
||||
|
||||
_load_env_cascade() {
|
||||
load_env_cascade() {
|
||||
local mode="${NODE_ENV:-development}"
|
||||
_load_envfile "$REPO_ROOT/.env"
|
||||
_load_envfile "$REPO_ROOT/.env.local"
|
||||
_load_envfile "$REPO_ROOT/.env.${mode}"
|
||||
_load_envfile "$REPO_ROOT/.env.${mode}.local"
|
||||
load_envfile "$REPO_ROOT/.env"
|
||||
load_envfile "$REPO_ROOT/.env.local"
|
||||
load_envfile "$REPO_ROOT/.env.${mode}"
|
||||
load_envfile "$REPO_ROOT/.env.${mode}.local"
|
||||
}
|
||||
|
||||
# Require one or more env vars; fail the current command with a helpful
|
||||
|
|
@ -60,7 +60,7 @@ require_env() {
|
|||
}
|
||||
|
||||
# Run cascade at source time so every subcommand has vars available.
|
||||
_load_env_cascade
|
||||
load_env_cascade
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue