From da72ea8264de759ac6f13549ec6b4649215323f7 Mon Sep 17 00:00:00 2001 From: VinPropane Date: Mon, 6 Apr 2026 22:34:43 -0400 Subject: [PATCH] NS-21: fail CI if Godot logs SCRIPT ERROR during GdUnit discovery GdUnit exits 0 when broken suites are skipped; grep log for parse/load errors. --- .github/workflows/gdscript.yml | 17 ++++++++++++++++- client/README.md | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.github/workflows/gdscript.yml b/.github/workflows/gdscript.yml index f3a5276..9331e52 100644 --- a/.github/workflows/gdscript.yml +++ b/.github/workflows/gdscript.yml @@ -70,7 +70,22 @@ jobs: exit 1 } + # GdUnit returns 0 if *executed* tests pass, even when Godot logs SCRIPT ERROR during suite + # discovery (broken test files are skipped). Fail the job if those errors appear in output. - name: GDUnit4 (headless) working-directory: client + shell: bash run: | - ~/godot/Godot_v4.6-stable_linux.x86_64 --headless --path . -s "$GDUNIT_CMDTOOL" --ignoreHeadlessMode -a res://test + set -euo pipefail + LOG="$(mktemp)" + trap 'rm -f "$LOG"' EXIT + ~/godot/Godot_v4.6-stable_linux.x86_64 --headless --path . -s "$GDUNIT_CMDTOOL" --ignoreHeadlessMode -a res://test 2>&1 | tee "$LOG" + godot_ec="${PIPESTATUS[0]}" + if [[ "$godot_ec" -ne 0 ]]; then + echo "::error::Godot/GdUnit exited with code ${godot_ec}" + exit "$godot_ec" + fi + if grep -E 'SCRIPT ERROR:|ERROR: Failed to load script' "$LOG"; then + echo "::error::Godot reported script parse/load errors (suites may have been skipped). Fix the test scripts." + exit 1 + fi diff --git a/client/README.md b/client/README.md index 0a1160c..e0d8df4 100644 --- a/client/README.md +++ b/client/README.md @@ -100,6 +100,8 @@ godot --headless --path . -s res://addons/gdUnit4/bin/GdUnitCmdTool.gd --ignoreH On **Linux** (including GitHub Actions), the path must be **`gdUnit4`** with a capital **`U`**; `gdunit4` does not resolve. +**CI:** The **GDScript** workflow fails the job if Godot prints **`SCRIPT ERROR:`** or **`ERROR: Failed to load script`** while running GdUnit. GdUnit alone can still exit **0** when a test file fails to parse (that suite is skipped); the workflow guards against that. + **Scope:** Unit tests cover **`player.gd`**, **`position_authority_client.gd`**, and **`ground_pick.gd`** (walkable collider check). **`main.gd`**, full **`_input` / ray pick** flows, and scene wiring are **not** automated here—use manual checks above. **Reports:** GdUnit writes under **`reports/`** (gitignored); ignore locally generated HTML/XML when committing.