PC3 Phase 3.1: hermetic backend tests + fresh-clone boot check + CI workflow
- backend/tests/conftest.py: pytest_configure brings up an ephemeral Postgres via docker compose + runs migrations when DATABASE_URL isn't already reachable, and tears it down after. `cd backend && pytest` now works from a clean checkout with zero manual setup (72 passed in ~28s); no docker and no DB -> the whole suite skips with a clear message instead of erroring 60+ times. - scripts/verify_fresh_clone.sh: exports a pristine tree (git archive, so no .godot), imports from scratch, headless-boots the main menu + game scene, fails on any SCRIPT ERROR / failed autoload. Catches the stale-class-cache class of bug. PASS. - run_checkpoint_tests.py runs both the 2p multiplayer test and the fresh-clone check. - .forgejo/workflows/checkpoint.yml + docs/ci.md: the CI workflow (runs the checkpoint suite on push/PR) and how to enable it -- it needs a Forgejo Actions `host` runner registered on the AGP box, a one-time operator step. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jtxAiu5dAW4WxCNdGkrkJ
This commit is contained in:
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
# Prove the game boots cleanly from a bare checkout -- no committed .godot
|
||||
# cache, no prior editor scan. Catches the class-of-bug where cross-file
|
||||
# `class_name` references only resolve because a stale cache happened to list
|
||||
# the old classes (which is exactly how the avatar system broke pre-PC3).
|
||||
#
|
||||
# Usage: scripts/verify_fresh_clone.sh
|
||||
# Exit 0 iff a from-scratch import + headless boot of the main menu produces
|
||||
# zero SCRIPT ERROR / failed-autoload lines.
|
||||
set -uo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
GODOT_BIN="${GODOT_BIN:-godot}"
|
||||
command -v "$GODOT_BIN" >/dev/null 2>&1 || GODOT_BIN="$HOME/godot/godot"
|
||||
command -v "$GODOT_BIN" >/dev/null 2>&1 || { echo "godot binary not found"; exit 1; }
|
||||
|
||||
WORK="$(mktemp -d)"
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
|
||||
echo "=== exporting a pristine tree (tracked files only, no .godot) ==="
|
||||
git archive --format=tar HEAD | tar -x -C "$WORK"
|
||||
[ -f "$WORK/project.godot" ] || { echo "export produced no project.godot"; exit 1; }
|
||||
[ -d "$WORK/.godot" ] && { echo "FAIL: .godot/ is tracked in git -- it must not be"; exit 1; }
|
||||
|
||||
LOG="$WORK/_boot.log"
|
||||
|
||||
echo "=== import pass (builds the class cache from scratch) ==="
|
||||
"$GODOT_BIN" --headless --path "$WORK" --import >"$LOG" 2>&1 || true
|
||||
|
||||
echo "=== headless boot: main menu ==="
|
||||
"$GODOT_BIN" --headless --path "$WORK" scenes/main_menu.tscn --quit-after 150 >>"$LOG" 2>&1 || true
|
||||
|
||||
echo "=== headless boot: game scene ==="
|
||||
"$GODOT_BIN" --headless --path "$WORK" scenes/game.tscn --quit-after 90 >>"$LOG" 2>&1 || true
|
||||
|
||||
BAD=$(grep -nE 'SCRIPT ERROR|Failed to instantiate an autoload|does not inherit from|Failed to load script' "$LOG" || true)
|
||||
if [ -n "$BAD" ]; then
|
||||
echo
|
||||
echo "FAIL: fresh clone does not boot clean --"
|
||||
echo "$BAD"
|
||||
echo "=== SMOKE RESULT: FAIL ==="
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== SMOKE RESULT: PASS ==="
|
||||
Reference in New Issue
Block a user