Files
settled-reach/tooling/godot-cold-parse
T
jpmschweitzerandClaude Fable 5 9c990a0733 fix(tooling): cargo fmt + godot-cold-parse cache restore (gate round)
fmt: atlas_data_proxy.rs test code. godot-cold-parse: the cold parse re-seeds the class cache WITHOUT addon classes (gdUnit4's GdUnitTestCIRunner missing), leaving tests/run-godot unable to start (0 tests / 355ms — caught by the pre-push gate running the suite right after this script). The script now restores a full cache via a final --import pass before exiting; the cold verdict is unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 16:29:02 +02:00

97 lines
4.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# tooling/godot-cold-parse [--run-menu] — cold-cache headless parse check.
#
# Used by /pr-process step 1c before push. Deletes the cached script-class
# registry so the parse simulates the cold-start ordering CI / fresh clones
# see: Sprint 36 close caught a new `class_name MetaScreen` base class and
# six extending scripts that parsed fine on warm developer caches but hit
# `Could not find base class "MetaScreen"` post-merge, because the
# autoload-vs-class_name registration order only resolves correctly once the
# class cache is seeded (see CLAUDE.md -> GDScript conventions -> Autoload
# parse-order rule).
#
# Godot's resource scanner emits category errors (e.g. "Export type can only
# be built-in, a resource, a node, or an enum") that do NOT always prefix
# with SCRIPT ERROR — they appear as plain ERROR lines. The filter below
# catches both, then drops known pre-existing noise from the autoload
# class_name parse-order trap. Sprint 36 shipped a scanner error the old
# narrower grep missed; this is why the filter stays wide.
#
# --run-menu: also launch main_menu.tscn briefly (for branches with UI changes).
#
# Exit 0 + "clean" if no matches. Exit 1 + the matched lines if any are found.
set -euo pipefail
REPO_ROOT="$(git rev-parse --show-toplevel)"
RUN_MENU=false
[ "${1:-}" = "--run-menu" ] && RUN_MENU=true
rm -f "$REPO_ROOT/client/.godot/global_script_class_cache.cfg"
# A truly cold checkout (fresh clone or worktree — .godot/ is gitignored) has
# no resource-import cache, and every imported asset (fonts, ogg) then "fails
# loading" during the parse run: a wall of false positives. Seed the cache
# with an import pass first; source assets are tracked, so this is always
# reconstructible. (Found live: first run in a fresh worktree, 2026-07-13.)
if [ ! -d "$REPO_ROOT/client/.godot/imported" ] || [ -z "$(ls -A "$REPO_ROOT/client/.godot/imported" 2>/dev/null)" ]; then
echo "godot-cold-parse: no import cache — running one-time import pass..." >&2
set +e
IMPORT_OUT=$(godot --headless --path "$REPO_ROOT/client" --import 2>&1)
IMPORT_EXIT=$?
set -e
if [ "$IMPORT_EXIT" -ne 0 ]; then
echo "godot-cold-parse: import pass exited $IMPORT_EXIT" >&2
printf '%s\n' "$IMPORT_OUT" | tail -20 >&2
exit "$IMPORT_EXIT"
fi
fi
FILTER='^(SCRIPT )?ERROR|Parse Error|Export type'
# Capture the godot run separately from the filter pipeline: with the
# trailing `|| true` on the greps, a nonzero exit from godot itself (crash,
# missing binary, corrupted install) would otherwise report "clean". Nothing
# downstream re-reads the raw output now that this is scripted, so fail loud.
set +e
RAW=$(godot --headless --path "$REPO_ROOT/client" --quit 2>&1)
GODOT_EXIT=$?
set -e
if [ "$GODOT_EXIT" -ne 0 ]; then
echo "godot-cold-parse: godot itself exited $GODOT_EXIT — not a parse verdict" >&2
printf '%s\n' "$RAW" | tail -20 >&2
exit "$GODOT_EXIT"
fi
MATCHES=$(printf '%s\n' "$RAW" \
| grep -iE "$FILTER" \
| grep -v "Failed loading resource: res://assets" \
| grep -v "Cannot infer the type" \
| grep -vE '(Messagepack|LocalBridge|ServerProcess|Constants)" not declared' || true)
if [ "$RUN_MENU" = true ]; then
# Deliberately no exit-code check here: `timeout` kills the menu after
# 10s by design (exit 124 is the expected shutdown path); only the
# scraped error lines carry signal for this bounded run.
MENU_MATCHES=$(timeout 10 godot --path "$REPO_ROOT/client" res://scenes/main_menu.tscn 2>&1 \
| grep -iE "$FILTER" || true)
if [ -n "$MENU_MATCHES" ]; then
MATCHES="$MATCHES
$MENU_MATCHES"
fi
fi
if [ -n "$MATCHES" ]; then
echo "$MATCHES"
exit 1
fi
# Restore a FULL class cache before exiting: the cold parse run re-seeds
# global_script_class_cache.cfg only partially — addon classes (e.g. gdUnit4's
# GdUnitTestCIRunner) are missing, which leaves tests/run-godot unable to even
# start (0 tests in ~350ms; found live when the pre-push gate ran the suite
# right after this script, 2026-07-14). The cold verdict above is already
# decided; this restore just returns the tree to a runnable state.
godot --headless --path "$REPO_ROOT/client" --import > /dev/null 2>&1 || true
echo "godot-cold-parse: clean"