7.0 KiB
Local Quality Gate
A single command to detect broken GDScript, formatting issues, lint problems, parser errors, and LLM-generated garbage before committing.
Requirements
-
Python 3 with the pinned
gdtoolkit(gdscript-toolkit). The recommended setup usesuvand a project-local environment. These commands are the same in macOS shells and Windows PowerShell:uv venv .venv uv pip install -r requirements-dev.txt -
Godot 4.7.x binary on
PATH, or set theGODOT_BINenvironment variable. The gate rejects other engine series before importing or testing. -
GUT 9.7.1 is vendored under
addons/gutfor Godot 4.7. No separate package-manager install is needed. -
Terrain3D 1.0.2 is vendored with macOS and Windows x86-64 debug and release binaries. No separate native build is needed on either development platform.
The vendored addon comes from the official
bitwes/Gut v9.7.1 release.
The downloaded release archive SHA-256 is
14969aa46adc84aa08cdd21b9f6d1a64addd92ae60b36f02d0521ed305aa4086.
Terrain3D carries one intentional local Godot 4.7 compatibility patch in
addons/terrain_3d/src/double_slider.gd: its editor display-scale lookups use
the 4.7 interface/editor/appearance/* setting paths. Preserve or re-evaluate
that patch when upgrading the vendored addon; without it, the first isolated
import fails before a class cache exists.
The quality and format scripts discover .venv automatically; activating it
is optional. Missing gdformat or gdlint is a gate failure rather than a
silent skip.
Finding Godot
The macOS gate checks project metadata, godot/godot4 on PATH, and the
standard /Applications/Godot.app location. The Windows gate checks project
metadata, PATH, common Program Files and Local AppData locations, and a
standard Scoop install. It prefers Godot's console executable when available.
For a downloaded or custom install, set the executable explicitly:
export GODOT_BIN="/Applications/Godot.app/Contents/MacOS/Godot"
$env:GODOT_BIN = "C:\Tools\Godot\Godot_v4.7-stable_win64_console.exe"
Usage
Full project check
./tools/quality.sh
powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\quality.ps1
Fast changed-files mode
Only runs gdformat / gdlint on tracked changes and new untracked .gd
files. The Godot dependency check and all project scenarios still run.
./tools/quality.sh --changed
powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\quality.ps1 -Changed
Auto-format (not part of the gate)
./tools/fix_format.sh
powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\fix_format.ps1
Both gates and both formatter entry points operate on the same game-owned
roots: player, simulation, tests, tools, and world. Third-party
addons and demos remain outside automatic formatting.
Add-on policy
Add an editor or runtime add-on only for a current gameplay or diagnostic
consumer. Pin its exact release, retain its license and source provenance, and
avoid auto-updates. Native add-ons must vendor macOS and Windows x86-64 debug
and release payloads; add those paths to the platform-assets manifest in both
quality scripts so either development platform detects an incomplete package.
What it checks
| Check | Tool | What it detects |
|---|---|---|
| platform-assets | File manifest | Missing Terrain3D macOS or Windows native payloads |
| godot-import | Godot 4.7 headless importer | Missing or stale global class_name cache on fresh clones |
| gdformat | Game-owned GDScript roots | Formatting without rewriting addons or demos |
| gdlint | Game-owned GDScript roots | Lint violations such as unused arguments and naming |
| godot-check | Headless definitions scenario | Parser errors and missing dependencies |
| scenarios | Every tests/*_test.gd script |
Simulation, persistence, navigation, and presentation regressions |
| gut | Vendored GUT 9.7.1 CLI | Focused unit regressions under tests/unit/ |
Output
If everything passes:
QUALITY RESULT: PASS
Godot: 4.7.stable.official.5b4e0cb0f
platform-assets PASS
godot-import PASS
gdformat PASS
gdlint PASS
godot-check PASS
scenarios PASS
gut PASS
Full logs:
logs/quality/latest/
On failure, only relevant errors and fix suggestions are shown:
QUALITY RESULT: FAIL
Godot: 4.7.stable.official.5b4e0cb0f
platform-assets PASS
godot-import PASS
gdformat FAIL
gdlint FAIL
godot-check PASS
scenarios PASS
gut PASS
res://simulation/SimNPC.gd:42 Unused argument 'delta'
res://simulation/task_manager.gd:88 Line too long (120 > 100)
NEXT FIX:
1. Fix unused-argument in SimNPC.gd
2. Run gdformat to auto-format files
Full logs:
logs/quality/latest/
Full logs are always written to logs/quality/latest/ and never dumped
to the terminal.
Environment variables
| Variable | Description |
|---|---|
GODOT_BIN |
Path to the Godot 4.7.x executable (auto-detected if unset) |
CI setup
To add this to CI, provide a Godot 4.7.x executable, install the dependencies, and run:
python -m pip install -r requirements-dev.txt
./tools/quality.sh
The script exits non-zero on any failure, including a wrong Godot series or missing pinned formatter/linter, so it will fail the CI step.
Both gates isolate Godot's cross-platform user-data paths under
logs/quality/godot_profile. Before running scenarios it imports project and
GUT global classes whenever GDScript changes, so fresh, renamed, and deleted
class_name scripts cannot leave the ignored cache stale. Godot/GUT script
parse or load markers are failures because headless Godot can report those
errors while returning a zero process exit code. Every Godot subprocess has a
portable watchdog on stock macOS as well as Linux/Windows, and nonzero
gdformat/gdlint exits fail the gate even when their output is not a familiar
diagnostic string. Import receives a 60-second timeout on both shell and
PowerShell; the focused checks retain their 30-second timeout.
Scenario logs are also classified after successful process exits. Unexpected
ERROR:, SCRIPT ERROR:, and WARNING: headers fail the gate and name their
originating scenario. The only narrow platform/vendor exceptions are the
isolated-profile macOS certificate-store condition, Terrain3D 1.0.2's Godot 4.7
interpolation deprecation, and the dummy renderer's exact one-DummyShader RID
exit report. Different warning text, leak counts, or RID types remain failures;
the full unfiltered output stays in logs/quality/latest/scenarios.log.
The scenario stage also runs the presentation-quality contract once with
--rendering-method gl_compatibility. This catches unsupported feature toggles
and profile-selection regressions; because the gate is headless, it is not a
substitute for a rendered OpenGL frame-time capture on representative hardware.