fix: harden cross-platform quality tooling
This commit is contained in:
@@ -17,23 +17,28 @@ Set up the local tools with `uv`:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
uv venv .venv
|
uv venv .venv
|
||||||
uv pip install --python .venv/bin/python -r requirements-dev.txt
|
uv pip install -r requirements-dev.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`uv` discovers the project-local `.venv` on both macOS and Windows, so the
|
||||||
|
same setup commands work in a shell or PowerShell.
|
||||||
|
|
||||||
Open `project.godot` in Godot 4.7 and run the main scene.
|
Open `project.godot` in Godot 4.7 and run the main scene.
|
||||||
|
|
||||||
## Quality gate
|
## Quality gate
|
||||||
|
|
||||||
Run the complete local gate before committing:
|
Run the complete local gate before committing.
|
||||||
|
|
||||||
|
macOS:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./tools/quality.sh
|
./tools/quality.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
On Windows:
|
Windows PowerShell:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell -ExecutionPolicy Bypass -File .\tools\quality.ps1
|
powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\quality.ps1
|
||||||
```
|
```
|
||||||
|
|
||||||
For a faster changed-GDScript formatting and lint pass, while still running
|
For a faster changed-GDScript formatting and lint pass, while still running
|
||||||
@@ -43,6 +48,17 @@ the Godot checks and scenarios:
|
|||||||
./tools/quality.sh --changed
|
./tools/quality.sh --changed
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\quality.ps1 -Changed
|
||||||
|
```
|
||||||
|
|
||||||
|
Auto-format all game-owned GDScript with `./tools/fix_format.sh` on macOS. On
|
||||||
|
Windows:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\fix_format.ps1
|
||||||
|
```
|
||||||
|
|
||||||
The gate enforces Godot 4.7, the pinned formatter and linter, headless project
|
The gate enforces Godot 4.7, the pinned formatter and linter, headless project
|
||||||
scenarios, and the vendored GUT suite. See
|
scenarios, and the vendored GUT suite. See
|
||||||
[`docs/local_quality_gate.md`](docs/local_quality_gate.md) for setup and
|
[`docs/local_quality_gate.md`](docs/local_quality_gate.md) for setup and
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ func _ready() -> void:
|
|||||||
# Setup Display Scale
|
# Setup Display Scale
|
||||||
# 0 auto, 1 75%, 2 100%, 3 125%, 4 150%, 5 175%, 6 200%, 7 custom
|
# 0 auto, 1 75%, 2 100%, 3 125%, 4 150%, 5 175%, 6 200%, 7 custom
|
||||||
var es: EditorSettings = EditorInterface.get_editor_settings()
|
var es: EditorSettings = EditorInterface.get_editor_settings()
|
||||||
var ds: int = es.get_setting("interface/editor/display_scale")
|
var ds: int = es.get_setting("interface/editor/appearance/display_scale")
|
||||||
if ds == 0:
|
if ds == 0:
|
||||||
ds = 2
|
ds = 2
|
||||||
elif ds == 7:
|
elif ds == 7:
|
||||||
display_scale = es.get_setting("interface/editor/custom_display_scale")
|
display_scale = es.get_setting("interface/editor/appearance/custom_display_scale")
|
||||||
else:
|
else:
|
||||||
display_scale = float(ds + 2) * .25
|
display_scale = float(ds + 2) * .25
|
||||||
|
|
||||||
|
|||||||
@@ -6,38 +6,64 @@ parser errors, and LLM-generated garbage before committing.
|
|||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- **Python 3** with the pinned `gdtoolkit` (gdscript-toolkit). The recommended
|
- **Python 3** with the pinned `gdtoolkit` (gdscript-toolkit). The recommended
|
||||||
setup uses `uv` and a project-local environment:
|
setup uses `uv` and a project-local environment. These commands are the same
|
||||||
|
in macOS shells and Windows PowerShell:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
uv venv .venv
|
uv venv .venv
|
||||||
uv pip install --python .venv/bin/python -r requirements-dev.txt
|
uv pip install -r requirements-dev.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
On Windows, use `.venv/Scripts/python.exe` for the `--python` value.
|
|
||||||
- **Godot 4.7.x** binary on `PATH`, or set the `GODOT_BIN` environment
|
- **Godot 4.7.x** binary on `PATH`, or set the `GODOT_BIN` environment
|
||||||
variable. The gate rejects other engine series before importing or testing.
|
variable. The gate rejects other engine series before importing or testing.
|
||||||
- **GUT 9.7.1** is vendored under `addons/gut` for Godot 4.7. No separate
|
- **GUT 9.7.1** is vendored under `addons/gut` for Godot 4.7. No separate
|
||||||
package-manager install is needed.
|
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
|
The vendored addon comes from the official
|
||||||
[`bitwes/Gut` v9.7.1 release](https://github.com/bitwes/Gut/releases/tag/v9.7.1).
|
[`bitwes/Gut` v9.7.1 release](https://github.com/bitwes/Gut/releases/tag/v9.7.1).
|
||||||
The downloaded release archive SHA-256 is
|
The downloaded release archive SHA-256 is
|
||||||
`14969aa46adc84aa08cdd21b9f6d1a64addd92ae60b36f02d0521ed305aa4086`.
|
`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
|
The quality and format scripts discover `.venv` automatically; activating it
|
||||||
is optional. Missing `gdformat` or `gdlint` is a gate failure rather than a
|
is optional. Missing `gdformat` or `gdlint` is a gate failure rather than a
|
||||||
silent skip.
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export GODOT_BIN="/Applications/Godot.app/Contents/MacOS/Godot"
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:GODOT_BIN = "C:\Tools\Godot\Godot_v4.7-stable_win64_console.exe"
|
||||||
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Full project check
|
### Full project check
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Linux / macOS / Git Bash
|
|
||||||
./tools/quality.sh
|
./tools/quality.sh
|
||||||
|
```
|
||||||
|
|
||||||
# Windows PowerShell
|
```powershell
|
||||||
& ./tools/quality.ps1
|
powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\quality.ps1
|
||||||
```
|
```
|
||||||
|
|
||||||
### Fast changed-files mode
|
### Fast changed-files mode
|
||||||
@@ -47,7 +73,10 @@ files. The Godot dependency check and all project scenarios still run.
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
./tools/quality.sh --changed
|
./tools/quality.sh --changed
|
||||||
& ./tools/quality.ps1 -Changed
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\quality.ps1 -Changed
|
||||||
```
|
```
|
||||||
|
|
||||||
### Auto-format (not part of the gate)
|
### Auto-format (not part of the gate)
|
||||||
@@ -56,10 +85,27 @@ files. The Godot dependency check and all project scenarios still run.
|
|||||||
./tools/fix_format.sh
|
./tools/fix_format.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
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
|
## What it checks
|
||||||
|
|
||||||
| Check | Tool | What it detects |
|
| 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 |
|
| **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 |
|
| **gdformat** | Game-owned GDScript roots | Formatting without rewriting addons or demos |
|
||||||
| **gdlint** | Game-owned GDScript roots | Lint violations such as unused arguments and naming |
|
| **gdlint** | Game-owned GDScript roots | Lint violations such as unused arguments and naming |
|
||||||
@@ -75,6 +121,7 @@ If everything passes:
|
|||||||
QUALITY RESULT: PASS
|
QUALITY RESULT: PASS
|
||||||
Godot: 4.7.stable.official.5b4e0cb0f
|
Godot: 4.7.stable.official.5b4e0cb0f
|
||||||
|
|
||||||
|
platform-assets PASS
|
||||||
godot-import PASS
|
godot-import PASS
|
||||||
gdformat PASS
|
gdformat PASS
|
||||||
gdlint PASS
|
gdlint PASS
|
||||||
@@ -92,6 +139,7 @@ On failure, only relevant errors and fix suggestions are shown:
|
|||||||
QUALITY RESULT: FAIL
|
QUALITY RESULT: FAIL
|
||||||
Godot: 4.7.stable.official.5b4e0cb0f
|
Godot: 4.7.stable.official.5b4e0cb0f
|
||||||
|
|
||||||
|
platform-assets PASS
|
||||||
godot-import PASS
|
godot-import PASS
|
||||||
gdformat FAIL
|
gdformat FAIL
|
||||||
gdlint FAIL
|
gdlint FAIL
|
||||||
@@ -132,7 +180,7 @@ python -m pip install -r requirements-dev.txt
|
|||||||
The script exits non-zero on any failure, including a wrong Godot series or
|
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.
|
missing pinned formatter/linter, so it will fail the CI step.
|
||||||
|
|
||||||
The shell gate isolates Godot's cross-platform user-data paths under
|
Both gates isolate Godot's cross-platform user-data paths under
|
||||||
`logs/quality/godot_profile`. Before running scenarios it imports project and
|
`logs/quality/godot_profile`. Before running scenarios it imports project and
|
||||||
GUT global classes whenever GDScript changes, so fresh, renamed, and deleted
|
GUT global classes whenever GDScript changes, so fresh, renamed, and deleted
|
||||||
`class_name` scripts cannot leave the ignored cache stale. Godot/GUT script
|
`class_name` scripts cannot leave the ignored cache stale. Godot/GUT script
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
# fix_format.ps1 — Auto-format all game-owned GDScript files with gdformat.
|
||||||
|
# Usage: & ./tools/fix_format.ps1
|
||||||
|
|
||||||
|
$ROOT = Split-Path -Parent $PSScriptRoot
|
||||||
|
$previousLocation = Get-Location
|
||||||
|
$exitCode = 0
|
||||||
|
|
||||||
|
function Resolve-GdFormat {
|
||||||
|
$localTool = Join-Path $ROOT ".venv/Scripts/gdformat.exe"
|
||||||
|
if (Test-Path $localTool) {
|
||||||
|
return [pscustomobject]@{ Command = $localTool; Prefix = @() }
|
||||||
|
}
|
||||||
|
|
||||||
|
$directTool = Get-Command gdformat -ErrorAction SilentlyContinue
|
||||||
|
if ($directTool) {
|
||||||
|
return [pscustomobject]@{ Command = $directTool.Source; Prefix = @() }
|
||||||
|
}
|
||||||
|
|
||||||
|
$localPython = Join-Path $ROOT ".venv/Scripts/python.exe"
|
||||||
|
$pythonCandidates = @(
|
||||||
|
[pscustomobject]@{ Command = $localPython; Prefix = @() },
|
||||||
|
[pscustomobject]@{ Command = "python"; Prefix = @() },
|
||||||
|
[pscustomobject]@{ Command = "python3"; Prefix = @() },
|
||||||
|
[pscustomobject]@{ Command = "py"; Prefix = @("-3") }
|
||||||
|
)
|
||||||
|
foreach ($candidate in $pythonCandidates) {
|
||||||
|
$isLocalPython = $candidate.Command -eq $localPython
|
||||||
|
if ($isLocalPython) {
|
||||||
|
if (-not (Test-Path $candidate.Command)) { continue }
|
||||||
|
$command = $candidate.Command
|
||||||
|
} else {
|
||||||
|
$resolved = Get-Command $candidate.Command -ErrorAction SilentlyContinue
|
||||||
|
if (-not $resolved) { continue }
|
||||||
|
$command = $resolved.Source
|
||||||
|
}
|
||||||
|
|
||||||
|
$prefix = @($candidate.Prefix)
|
||||||
|
$null = @(& $command @prefix -m gdtoolkit.formatter --help 2>&1)
|
||||||
|
if ($LASTEXITCODE -eq 0) {
|
||||||
|
return [pscustomobject]@{ Command = $command; Prefix = $prefix + @("-m", "gdtoolkit.formatter") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Set-Location $ROOT
|
||||||
|
$formatter = Resolve-GdFormat
|
||||||
|
if (-not $formatter) {
|
||||||
|
throw "gdformat not found. Install requirements-dev.txt; see docs/local_quality_gate.md."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Formatting all game-owned .gd files in $ROOT ..."
|
||||||
|
$command = $formatter.Command
|
||||||
|
$prefix = @($formatter.Prefix)
|
||||||
|
& $command @prefix player simulation tests tools world
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "gdformat exited with code $LASTEXITCODE."
|
||||||
|
}
|
||||||
|
Write-Host "Done."
|
||||||
|
} catch {
|
||||||
|
Write-Host "ERROR: $($_.Exception.Message)"
|
||||||
|
$exitCode = 1
|
||||||
|
} finally {
|
||||||
|
Set-Location $previousLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
exit $exitCode
|
||||||
+14
-2
@@ -6,14 +6,26 @@ set -euo pipefail
|
|||||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
cd "$ROOT"
|
cd "$ROOT"
|
||||||
|
|
||||||
|
python_formatter() {
|
||||||
|
local python_command
|
||||||
|
for python_command in python python3; do
|
||||||
|
if command -v "$python_command" &>/dev/null &&
|
||||||
|
"$python_command" -m gdtoolkit.formatter --help &>/dev/null 2>&1; then
|
||||||
|
echo "$python_command"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
# detect gdformat
|
# detect gdformat
|
||||||
FMT=()
|
FMT=()
|
||||||
if [[ -x "$ROOT/.venv/bin/gdformat" ]]; then
|
if [[ -x "$ROOT/.venv/bin/gdformat" ]]; then
|
||||||
FMT=("$ROOT/.venv/bin/gdformat")
|
FMT=("$ROOT/.venv/bin/gdformat")
|
||||||
elif command -v gdformat &>/dev/null; then
|
elif command -v gdformat &>/dev/null; then
|
||||||
FMT=(gdformat)
|
FMT=(gdformat)
|
||||||
elif python -m gdtoolkit.formatter --help &>/dev/null 2>&1; then
|
elif PYTHON_FORMATTER="$(python_formatter)"; then
|
||||||
FMT=(python -m gdtoolkit.formatter)
|
FMT=("$PYTHON_FORMATTER" -m gdtoolkit.formatter)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${#FMT[@]} -eq 0 ]]; then
|
if [[ ${#FMT[@]} -eq 0 ]]; then
|
||||||
|
|||||||
+138
-64
@@ -5,6 +5,7 @@ param([switch]$Changed)
|
|||||||
if ($args -contains '--changed') { $Changed = $true }
|
if ($args -contains '--changed') { $Changed = $true }
|
||||||
|
|
||||||
$ROOT = Split-Path -Parent $PSScriptRoot
|
$ROOT = Split-Path -Parent $PSScriptRoot
|
||||||
|
$script:PreviousLocation = Get-Location
|
||||||
Set-Location $ROOT
|
Set-Location $ROOT
|
||||||
|
|
||||||
$LOG = "logs/quality/latest"
|
$LOG = "logs/quality/latest"
|
||||||
@@ -16,12 +17,26 @@ $OVERALL = $false
|
|||||||
$ERRORS = @()
|
$ERRORS = @()
|
||||||
$FIXES = @()
|
$FIXES = @()
|
||||||
$OWNED_GDSCRIPT_ROOTS = @("player", "simulation", "tests", "tools", "world")
|
$OWNED_GDSCRIPT_ROOTS = @("player", "simulation", "tests", "tools", "world")
|
||||||
|
$CROSS_PLATFORM_PLUGIN_FILES = @(
|
||||||
|
"addons/terrain_3d/terrain.gdextension",
|
||||||
|
"addons/terrain_3d/bin/libterrain.macos.debug.framework/libterrain.macos.debug",
|
||||||
|
"addons/terrain_3d/bin/libterrain.macos.release.framework/libterrain.macos.release",
|
||||||
|
"addons/terrain_3d/bin/libterrain.windows.debug.x86_64.dll",
|
||||||
|
"addons/terrain_3d/bin/libterrain.windows.release.x86_64.dll"
|
||||||
|
)
|
||||||
$REQUIRED_GODOT_SERIES = "4.7"
|
$REQUIRED_GODOT_SERIES = "4.7"
|
||||||
|
|
||||||
|
function Exit-Quality {
|
||||||
|
param([int]$ExitCode)
|
||||||
|
Set-Location $script:PreviousLocation
|
||||||
|
exit $ExitCode
|
||||||
|
}
|
||||||
|
|
||||||
# -- tool detection -----------------------------------------------------------
|
# -- tool detection -----------------------------------------------------------
|
||||||
function ConvertTo-ConsoleGodotPath($Path) {
|
function ConvertTo-ConsoleGodotPath($Path) {
|
||||||
if (-not $Path) { return $null }
|
if (-not $Path) { return $null }
|
||||||
$normalized = $Path.Replace('/', '\').Trim('"')
|
$separator = [IO.Path]::DirectorySeparatorChar
|
||||||
|
$normalized = $Path.Replace([char]47, $separator).Replace([char]92, $separator).Trim('"')
|
||||||
if ($normalized.EndsWith(".exe")) {
|
if ($normalized.EndsWith(".exe")) {
|
||||||
$consolePath = $normalized -replace '\.exe$', '_console.exe'
|
$consolePath = $normalized -replace '\.exe$', '_console.exe'
|
||||||
if (Test-Path $consolePath) { return $consolePath }
|
if (Test-Path $consolePath) { return $consolePath }
|
||||||
@@ -43,75 +58,110 @@ function Find-Godot {
|
|||||||
if ($env:GODOT_BIN) { return (ConvertTo-ConsoleGodotPath $env:GODOT_BIN) }
|
if ($env:GODOT_BIN) { return (ConvertTo-ConsoleGodotPath $env:GODOT_BIN) }
|
||||||
$projectGodot = Find-ProjectGodot
|
$projectGodot = Find-ProjectGodot
|
||||||
if ($projectGodot) { return $projectGodot }
|
if ($projectGodot) { return $projectGodot }
|
||||||
try { return (Get-Command godot -ErrorAction Stop).Source } catch {}
|
foreach ($name in @("godot", "godot4")) {
|
||||||
try { return (Get-Command godot4 -ErrorAction Stop).Source } catch {}
|
$command = Get-Command $name -ErrorAction SilentlyContinue
|
||||||
$common = @(
|
if (-not $command) { continue }
|
||||||
"$env:ProgramFiles\Godot\godot.exe",
|
$candidate = ConvertTo-ConsoleGodotPath $command.Source
|
||||||
"${env:ProgramFiles(x86)}\Godot\godot.exe",
|
if ($candidate) { return $candidate }
|
||||||
"$env:LOCALAPPDATA\Godot\godot.exe",
|
}
|
||||||
"$env:USERPROFILE\AppData\Local\Godot\godot.exe"
|
|
||||||
)
|
$common = @()
|
||||||
foreach ($p in $common) { if (Test-Path $p) { return $p } }
|
if ($env:ProgramFiles) { $common += Join-Path $env:ProgramFiles "Godot/godot.exe" }
|
||||||
$bundled = Get-ChildItem "${env:ProgramFiles(x86)}\Godot" -Filter "Godot*_console.exe" -ErrorAction SilentlyContinue |
|
if (${env:ProgramFiles(x86)}) { $common += Join-Path ${env:ProgramFiles(x86)} "Godot/godot.exe" }
|
||||||
|
if ($env:LOCALAPPDATA) {
|
||||||
|
$common += Join-Path $env:LOCALAPPDATA "Godot/godot.exe"
|
||||||
|
$common += Join-Path $env:LOCALAPPDATA "Programs/Godot/godot.exe"
|
||||||
|
}
|
||||||
|
if ($env:USERPROFILE) { $common += Join-Path $env:USERPROFILE "scoop/apps/godot/current/godot.exe" }
|
||||||
|
foreach ($path in $common) {
|
||||||
|
$candidate = ConvertTo-ConsoleGodotPath $path
|
||||||
|
if ($candidate) { return $candidate }
|
||||||
|
}
|
||||||
|
|
||||||
|
$searchRoots = @()
|
||||||
|
if ($env:ProgramFiles) { $searchRoots += Join-Path $env:ProgramFiles "Godot" }
|
||||||
|
if (${env:ProgramFiles(x86)}) { $searchRoots += Join-Path ${env:ProgramFiles(x86)} "Godot" }
|
||||||
|
if ($env:LOCALAPPDATA) {
|
||||||
|
$searchRoots += Join-Path $env:LOCALAPPDATA "Godot"
|
||||||
|
$searchRoots += Join-Path $env:LOCALAPPDATA "Programs/Godot"
|
||||||
|
}
|
||||||
|
foreach ($searchRoot in $searchRoots) {
|
||||||
|
$bundled = Get-ChildItem $searchRoot -Filter "Godot*_console.exe" -File -ErrorAction SilentlyContinue |
|
||||||
Sort-Object Name -Descending |
|
Sort-Object Name -Descending |
|
||||||
Select-Object -First 1
|
Select-Object -First 1
|
||||||
if ($bundled) { return $bundled.FullName }
|
if ($bundled) { return $bundled.FullName }
|
||||||
|
}
|
||||||
return $null
|
return $null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Resolve-GdTool {
|
||||||
|
param(
|
||||||
|
[string]$ExecutableName,
|
||||||
|
[string]$ModuleName
|
||||||
|
)
|
||||||
|
$localTool = Join-Path $ROOT ".venv/Scripts/$ExecutableName.exe"
|
||||||
|
if (Test-Path $localTool) {
|
||||||
|
return [pscustomobject]@{ Command = $localTool; Prefix = @() }
|
||||||
|
}
|
||||||
|
|
||||||
|
$directTool = Get-Command $ExecutableName -ErrorAction SilentlyContinue
|
||||||
|
if ($directTool) {
|
||||||
|
return [pscustomobject]@{ Command = $directTool.Source; Prefix = @() }
|
||||||
|
}
|
||||||
|
|
||||||
|
$localPython = Join-Path $ROOT ".venv/Scripts/python.exe"
|
||||||
|
$pythonCandidates = @(
|
||||||
|
[pscustomobject]@{ Command = $localPython; Prefix = @() },
|
||||||
|
[pscustomobject]@{ Command = "python"; Prefix = @() },
|
||||||
|
[pscustomobject]@{ Command = "python3"; Prefix = @() },
|
||||||
|
[pscustomobject]@{ Command = "py"; Prefix = @("-3") }
|
||||||
|
)
|
||||||
|
foreach ($candidate in $pythonCandidates) {
|
||||||
|
$isLocalPython = $candidate.Command -eq $localPython
|
||||||
|
if ($isLocalPython) {
|
||||||
|
if (-not (Test-Path $candidate.Command)) { continue }
|
||||||
|
$command = $candidate.Command
|
||||||
|
} else {
|
||||||
|
$resolved = Get-Command $candidate.Command -ErrorAction SilentlyContinue
|
||||||
|
if (-not $resolved) { continue }
|
||||||
|
$command = $resolved.Source
|
||||||
|
}
|
||||||
|
|
||||||
|
$prefix = @($candidate.Prefix)
|
||||||
|
$null = @(& $command @prefix -m $ModuleName --help 2>&1)
|
||||||
|
if ($LASTEXITCODE -eq 0) {
|
||||||
|
return [pscustomobject]@{ Command = $command; Prefix = $prefix + @("-m", $ModuleName) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
$script:GdFormatRunner = $null
|
||||||
|
$script:GdLintRunner = $null
|
||||||
|
|
||||||
function Test-GdFormat {
|
function Test-GdFormat {
|
||||||
if (Test-Path "$ROOT/.venv/Scripts/gdformat.exe") { return $true }
|
$script:GdFormatRunner = Resolve-GdTool "gdformat" "gdtoolkit.formatter"
|
||||||
if (Get-Command gdformat -ErrorAction SilentlyContinue) { return $true }
|
return $null -ne $script:GdFormatRunner
|
||||||
try {
|
|
||||||
$null = & python -m gdtoolkit.formatter --help 2>&1
|
|
||||||
if ($LASTEXITCODE -eq 0) { return $true }
|
|
||||||
} catch {}
|
|
||||||
try {
|
|
||||||
$null = & python3 -m gdtoolkit.formatter --help 2>&1
|
|
||||||
if ($LASTEXITCODE -eq 0) { return $true }
|
|
||||||
} catch {}
|
|
||||||
return $false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Test-GdLint {
|
function Test-GdLint {
|
||||||
if (Test-Path "$ROOT/.venv/Scripts/gdlint.exe") { return $true }
|
$script:GdLintRunner = Resolve-GdTool "gdlint" "gdtoolkit.linter"
|
||||||
if (Get-Command gdlint -ErrorAction SilentlyContinue) { return $true }
|
return $null -ne $script:GdLintRunner
|
||||||
try {
|
|
||||||
$null = & python -m gdtoolkit.linter --help 2>&1
|
|
||||||
if ($LASTEXITCODE -eq 0) { return $true }
|
|
||||||
} catch {}
|
|
||||||
try {
|
|
||||||
$null = & python3 -m gdtoolkit.linter --help 2>&1
|
|
||||||
if ($LASTEXITCODE -eq 0) { return $true }
|
|
||||||
} catch {}
|
|
||||||
return $false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$script:GdToolExitCode = 0
|
$script:GdToolExitCode = 0
|
||||||
|
|
||||||
function Invoke-GdFormat {
|
function Invoke-GdFormat {
|
||||||
$args = $args
|
$command = $script:GdFormatRunner.Command
|
||||||
$localTool = "$ROOT/.venv/Scripts/gdformat.exe"
|
$prefix = @($script:GdFormatRunner.Prefix)
|
||||||
if (Test-Path $localTool) {
|
& $command @prefix @args 2>&1
|
||||||
& $localTool @args 2>&1
|
|
||||||
} elseif (Get-Command gdformat -ErrorAction SilentlyContinue) {
|
|
||||||
& gdformat @args 2>&1
|
|
||||||
} else {
|
|
||||||
& python -m gdtoolkit.formatter @args 2>&1
|
|
||||||
}
|
|
||||||
$script:GdToolExitCode = $LASTEXITCODE
|
$script:GdToolExitCode = $LASTEXITCODE
|
||||||
}
|
}
|
||||||
|
|
||||||
function Invoke-GdLint {
|
function Invoke-GdLint {
|
||||||
$args = $args
|
$command = $script:GdLintRunner.Command
|
||||||
$localTool = "$ROOT/.venv/Scripts/gdlint.exe"
|
$prefix = @($script:GdLintRunner.Prefix)
|
||||||
if (Test-Path $localTool) {
|
& $command @prefix @args 2>&1
|
||||||
& $localTool @args 2>&1
|
|
||||||
} elseif (Get-Command gdlint -ErrorAction SilentlyContinue) {
|
|
||||||
& gdlint @args 2>&1
|
|
||||||
} else {
|
|
||||||
& python -m gdtoolkit.linter @args 2>&1
|
|
||||||
}
|
|
||||||
$script:GdToolExitCode = $LASTEXITCODE
|
$script:GdToolExitCode = $LASTEXITCODE
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +173,11 @@ function Get-ChangedGd {
|
|||||||
|
|
||||||
function To-ResPath($p) {
|
function To-ResPath($p) {
|
||||||
$p = $p.Replace('\', '/')
|
$p = $p.Replace('\', '/')
|
||||||
if ($p.StartsWith($ROOT)) { $p = $p.Substring($ROOT.Length + 1) }
|
$normalizedRoot = $ROOT.Replace('\', '/').TrimEnd('/')
|
||||||
|
$rootPrefix = "$normalizedRoot/"
|
||||||
|
if ($p.StartsWith($rootPrefix, [StringComparison]::OrdinalIgnoreCase)) {
|
||||||
|
$p = $p.Substring($rootPrefix.Length)
|
||||||
|
}
|
||||||
if ($p.StartsWith('./')) { $p = $p.Substring(2) }
|
if ($p.StartsWith('./')) { $p = $p.Substring(2) }
|
||||||
return "res://$p"
|
return "res://$p"
|
||||||
}
|
}
|
||||||
@@ -146,6 +200,8 @@ function Invoke-GodotWithTimeout {
|
|||||||
$env:LOCALAPPDATA = $GODOT_PROFILE
|
$env:LOCALAPPDATA = $GODOT_PROFILE
|
||||||
try {
|
try {
|
||||||
$p = [Diagnostics.Process]::Start($psi)
|
$p = [Diagnostics.Process]::Start($psi)
|
||||||
|
} catch {
|
||||||
|
return "Failed to start Godot: $($_.Exception.Message)", $null
|
||||||
} finally {
|
} finally {
|
||||||
$env:APPDATA = $previousAppData
|
$env:APPDATA = $previousAppData
|
||||||
$env:LOCALAPPDATA = $previousLocalAppData
|
$env:LOCALAPPDATA = $previousLocalAppData
|
||||||
@@ -158,7 +214,7 @@ function Invoke-GodotWithTimeout {
|
|||||||
$p.WaitForExit()
|
$p.WaitForExit()
|
||||||
$output = $outputTask.Result
|
$output = $outputTask.Result
|
||||||
$err = $errorTask.Result
|
$err = $errorTask.Result
|
||||||
return $output + $err, $null
|
return ($output + $err), $null
|
||||||
}
|
}
|
||||||
$output = $outputTask.Result
|
$output = $outputTask.Result
|
||||||
$err = $errorTask.Result
|
$err = $errorTask.Result
|
||||||
@@ -169,22 +225,36 @@ function Invoke-GodotWithTimeout {
|
|||||||
$GODOT = Find-Godot
|
$GODOT = Find-Godot
|
||||||
if (-not $GODOT) {
|
if (-not $GODOT) {
|
||||||
Write-Host "ERROR: Godot binary not found. Set GODOT_BIN or add godot/godot4 to PATH."
|
Write-Host "ERROR: Godot binary not found. Set GODOT_BIN or add godot/godot4 to PATH."
|
||||||
exit 1
|
Exit-Quality 1
|
||||||
}
|
}
|
||||||
$godotVersionOutput = @(& $GODOT --version 2>&1)
|
$godotVersionOutput = @(& $GODOT --version 2>&1)
|
||||||
$godotVersionExit = $LASTEXITCODE
|
$godotVersionExit = $LASTEXITCODE
|
||||||
if ($godotVersionExit -ne 0 -or $godotVersionOutput.Count -eq 0) {
|
if ($godotVersionExit -ne 0 -or $godotVersionOutput.Count -eq 0) {
|
||||||
Write-Host "ERROR: Could not query the Godot version from '$GODOT'."
|
Write-Host "ERROR: Could not query the Godot version from '$GODOT'."
|
||||||
exit 1
|
Exit-Quality 1
|
||||||
}
|
}
|
||||||
$GODOT_VERSION = ([string]$godotVersionOutput[0]).Trim()
|
$GODOT_VERSION = ([string]$godotVersionOutput[0]).Trim()
|
||||||
$requiredVersionPattern = '^' + [regex]::Escape($REQUIRED_GODOT_SERIES) + '([.-]|$)'
|
$requiredVersionPattern = '^' + [regex]::Escape($REQUIRED_GODOT_SERIES) + '([.-]|$)'
|
||||||
if ($GODOT_VERSION -notmatch $requiredVersionPattern) {
|
if ($GODOT_VERSION -notmatch $requiredVersionPattern) {
|
||||||
Write-Host "ERROR: Godot $REQUIRED_GODOT_SERIES.x is required; found '$GODOT_VERSION'."
|
Write-Host "ERROR: Godot $REQUIRED_GODOT_SERIES.x is required; found '$GODOT_VERSION'."
|
||||||
exit 1
|
Exit-Quality 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# -- 0. Godot import bootstrap ------------------------------------------------
|
# -- 0. Cross-platform plugin payload -----------------------------------------
|
||||||
|
$platformAssetsResult = "PASS"
|
||||||
|
Set-Content -Path "$LOG/platform-assets.log" -Value "" -Encoding utf8
|
||||||
|
foreach ($pluginFile in $CROSS_PLATFORM_PLUGIN_FILES) {
|
||||||
|
if (-not (Test-Path $pluginFile -PathType Leaf)) {
|
||||||
|
$platformAssetsResult = "FAIL"
|
||||||
|
Add-Content -Path "$LOG/platform-assets.log" -Value "Missing $pluginFile" -Encoding utf8
|
||||||
|
$ERRORS += "platform-assets: missing res://$pluginFile"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($platformAssetsResult -eq "FAIL") {
|
||||||
|
$FIXES += "Restore the complete pinned Terrain3D 1.0.2 package"
|
||||||
|
}
|
||||||
|
|
||||||
|
# -- 1. Godot import bootstrap ------------------------------------------------
|
||||||
$importResult = "PASS"
|
$importResult = "PASS"
|
||||||
Set-Content -Path "$LOG/godot-import.log" -Value "" -Encoding utf8
|
Set-Content -Path "$LOG/godot-import.log" -Value "" -Encoding utf8
|
||||||
$classCache = Join-Path $ROOT ".godot/global_script_class_cache.cfg"
|
$classCache = Join-Path $ROOT ".godot/global_script_class_cache.cfg"
|
||||||
@@ -223,7 +293,7 @@ if ($importResult -eq "FAIL") {
|
|||||||
$FIXES += "Fix Godot import errors before running headless checks"
|
$FIXES += "Fix Godot import errors before running headless checks"
|
||||||
}
|
}
|
||||||
|
|
||||||
# -- 1. gdformat --------------------------------------------------------------
|
# -- 2. gdformat --------------------------------------------------------------
|
||||||
$fmtAvail = Test-GdFormat
|
$fmtAvail = Test-GdFormat
|
||||||
$fmtResult = "PASS"
|
$fmtResult = "PASS"
|
||||||
$fmtFailed = $false
|
$fmtFailed = $false
|
||||||
@@ -275,7 +345,7 @@ if ($formatDiagnostics) {
|
|||||||
$FIXES += "Fix the gdformat error before continuing"
|
$FIXES += "Fix the gdformat error before continuing"
|
||||||
}
|
}
|
||||||
|
|
||||||
# -- 2. gdlint ----------------------------------------------------------------
|
# -- 3. gdlint ----------------------------------------------------------------
|
||||||
$lintAvail = Test-GdLint
|
$lintAvail = Test-GdLint
|
||||||
$lintResult = "PASS"
|
$lintResult = "PASS"
|
||||||
$lintFailed = $false
|
$lintFailed = $false
|
||||||
@@ -328,7 +398,7 @@ if ($lintLines) {
|
|||||||
$FIXES += "Fix the gdlint error before continuing"
|
$FIXES += "Fix the gdlint error before continuing"
|
||||||
}
|
}
|
||||||
|
|
||||||
# -- 3. godot headless check --------------------------------------------------
|
# -- 4. godot headless check --------------------------------------------------
|
||||||
$godotResult = "PASS"
|
$godotResult = "PASS"
|
||||||
Set-Content -Path "$LOG/godot-check.log" -Value "" -Encoding utf8
|
Set-Content -Path "$LOG/godot-check.log" -Value "" -Encoding utf8
|
||||||
$godotArgs = "--headless --path `"$ROOT`" --script res://tests/simulation_definitions_test.gd"
|
$godotArgs = "--headless --path `"$ROOT`" --script res://tests/simulation_definitions_test.gd"
|
||||||
@@ -353,7 +423,7 @@ if ($godotLoadError) {
|
|||||||
$FIXES += "Fix Godot parser errors"
|
$FIXES += "Fix Godot parser errors"
|
||||||
}
|
}
|
||||||
|
|
||||||
# -- 4. project scenario tests ------------------------------------------------
|
# -- 5. project scenario tests ------------------------------------------------
|
||||||
$scenarioResult = "PASS"
|
$scenarioResult = "PASS"
|
||||||
Set-Content -Path "$LOG/scenarios.log" -Value "" -Encoding utf8
|
Set-Content -Path "$LOG/scenarios.log" -Value "" -Encoding utf8
|
||||||
$scenarioTests = Get-ChildItem "tests" -Filter "*_test.gd" | Sort-Object Name
|
$scenarioTests = Get-ChildItem "tests" -Filter "*_test.gd" | Sort-Object Name
|
||||||
@@ -376,7 +446,7 @@ if ($scenarioResult -eq "FAIL") {
|
|||||||
$FIXES += "Fix failing project scenario tests"
|
$FIXES += "Fix failing project scenario tests"
|
||||||
}
|
}
|
||||||
|
|
||||||
# -- 5. GUT -------------------------------------------------------------------
|
# -- 6. GUT -------------------------------------------------------------------
|
||||||
$gutResult = "PASS"
|
$gutResult = "PASS"
|
||||||
Set-Content -Path "$LOG/gut.log" -Value "" -Encoding utf8
|
Set-Content -Path "$LOG/gut.log" -Value "" -Encoding utf8
|
||||||
if (-not (Test-Path "addons/gut/gut_cmdln.gd")) {
|
if (-not (Test-Path "addons/gut/gut_cmdln.gd")) {
|
||||||
@@ -410,7 +480,9 @@ if (-not (Test-Path "addons/gut/gut_cmdln.gd")) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# -- summary ------------------------------------------------------------------
|
# -- summary ------------------------------------------------------------------
|
||||||
if ($importResult -eq 'FAIL' -or $fmtResult -eq 'FAIL' -or $lintResult -eq 'FAIL' -or $godotResult -eq 'FAIL' -or $scenarioResult -eq 'FAIL' -or $gutResult -eq 'FAIL') {
|
if ($platformAssetsResult -eq 'FAIL' -or $importResult -eq 'FAIL' -or
|
||||||
|
$fmtResult -eq 'FAIL' -or $lintResult -eq 'FAIL' -or $godotResult -eq 'FAIL' -or
|
||||||
|
$scenarioResult -eq 'FAIL' -or $gutResult -eq 'FAIL') {
|
||||||
$OVERALL = $true
|
$OVERALL = $true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,6 +490,7 @@ Write-Host ""
|
|||||||
if ($OVERALL) { Write-Host "QUALITY RESULT: FAIL" } else { Write-Host "QUALITY RESULT: PASS" }
|
if ($OVERALL) { Write-Host "QUALITY RESULT: FAIL" } else { Write-Host "QUALITY RESULT: PASS" }
|
||||||
Write-Host "Godot: $GODOT_VERSION"
|
Write-Host "Godot: $GODOT_VERSION"
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
|
Write-Host " platform-assets $platformAssetsResult"
|
||||||
Write-Host " godot-import $importResult"
|
Write-Host " godot-import $importResult"
|
||||||
Write-Host " gdformat $fmtResult"
|
Write-Host " gdformat $fmtResult"
|
||||||
Write-Host " gdlint $lintResult"
|
Write-Host " gdlint $lintResult"
|
||||||
@@ -456,6 +529,7 @@ $summary = @"
|
|||||||
QUALITY RESULT: $resultText
|
QUALITY RESULT: $resultText
|
||||||
Godot: $GODOT_VERSION
|
Godot: $GODOT_VERSION
|
||||||
|
|
||||||
|
platform-assets $platformAssetsResult
|
||||||
godot-import $importResult
|
godot-import $importResult
|
||||||
gdformat $fmtResult
|
gdformat $fmtResult
|
||||||
gdlint $lintResult
|
gdlint $lintResult
|
||||||
@@ -465,4 +539,4 @@ Godot: $GODOT_VERSION
|
|||||||
"@
|
"@
|
||||||
Set-Content -Path "$LOG/summary.txt" -Value $summary -Encoding utf8
|
Set-Content -Path "$LOG/summary.txt" -Value $summary -Encoding utf8
|
||||||
|
|
||||||
if ($OVERALL) { exit 1 } else { exit 0 }
|
if ($OVERALL) { Exit-Quality 1 } else { Exit-Quality 0 }
|
||||||
|
|||||||
+68
-12
@@ -18,6 +18,13 @@ OVERALL=false
|
|||||||
ERRORS=()
|
ERRORS=()
|
||||||
FIXES=()
|
FIXES=()
|
||||||
OWNED_GDSCRIPT_ROOTS=(player simulation tests tools world)
|
OWNED_GDSCRIPT_ROOTS=(player simulation tests tools world)
|
||||||
|
CROSS_PLATFORM_PLUGIN_FILES=(
|
||||||
|
addons/terrain_3d/terrain.gdextension
|
||||||
|
addons/terrain_3d/bin/libterrain.macos.debug.framework/libterrain.macos.debug
|
||||||
|
addons/terrain_3d/bin/libterrain.macos.release.framework/libterrain.macos.release
|
||||||
|
addons/terrain_3d/bin/libterrain.windows.debug.x86_64.dll
|
||||||
|
addons/terrain_3d/bin/libterrain.windows.release.x86_64.dll
|
||||||
|
)
|
||||||
REQUIRED_GODOT_SERIES="4.7"
|
REQUIRED_GODOT_SERIES="4.7"
|
||||||
|
|
||||||
# -- tool detection -----------------------------------------------------------
|
# -- tool detection -----------------------------------------------------------
|
||||||
@@ -48,17 +55,47 @@ find_project_godot() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
find_godot() {
|
find_godot() {
|
||||||
if [[ -n "${GODOT_BIN:-}" ]]; then console_godot_path "$GODOT_BIN" && return 0; echo "$GODOT_BIN"; return 0; fi
|
if [[ -n "${GODOT_BIN:-}" ]]; then
|
||||||
|
if console_godot_path "$GODOT_BIN"; then return 0; fi
|
||||||
|
echo "ERROR: GODOT_BIN does not point to a Godot executable: $GODOT_BIN" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
find_project_godot && return 0
|
find_project_godot && return 0
|
||||||
for c in godot godot4; do command -v "$c" &>/dev/null && echo "$c" && return 0; done
|
for c in godot godot4; do command -v "$c" &>/dev/null && echo "$c" && return 0; done
|
||||||
console_godot_path "/Applications/Godot.app/Contents/MacOS/Godot" && return 0
|
console_godot_path "/Applications/Godot.app/Contents/MacOS/Godot" && return 0
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
has_python_module() {
|
||||||
|
local module="$1"
|
||||||
|
local python_command
|
||||||
|
for python_command in python python3; do
|
||||||
|
if command -v "$python_command" &>/dev/null &&
|
||||||
|
"$python_command" -m "$module" --help &>/dev/null 2>&1; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
run_python_module() {
|
||||||
|
local module="$1"
|
||||||
|
shift
|
||||||
|
local python_command
|
||||||
|
for python_command in python python3; do
|
||||||
|
if command -v "$python_command" &>/dev/null &&
|
||||||
|
"$python_command" -m "$module" --help &>/dev/null 2>&1; then
|
||||||
|
"$python_command" -m "$module" "$@"
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 127
|
||||||
|
}
|
||||||
|
|
||||||
has_gdformat() {
|
has_gdformat() {
|
||||||
[[ -x "$ROOT/.venv/bin/gdformat" ]] && return 0
|
[[ -x "$ROOT/.venv/bin/gdformat" ]] && return 0
|
||||||
command -v gdformat &>/dev/null && return 0
|
command -v gdformat &>/dev/null && return 0
|
||||||
python -m gdtoolkit.formatter --help &>/dev/null 2>&1
|
has_python_module gdtoolkit.formatter
|
||||||
}
|
}
|
||||||
|
|
||||||
run_gdformat() {
|
run_gdformat() {
|
||||||
@@ -67,14 +104,14 @@ run_gdformat() {
|
|||||||
elif command -v gdformat &>/dev/null; then
|
elif command -v gdformat &>/dev/null; then
|
||||||
gdformat "$@"
|
gdformat "$@"
|
||||||
else
|
else
|
||||||
python -m gdtoolkit.formatter "$@"
|
run_python_module gdtoolkit.formatter "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
has_gdlint() {
|
has_gdlint() {
|
||||||
[[ -x "$ROOT/.venv/bin/gdlint" ]] && return 0
|
[[ -x "$ROOT/.venv/bin/gdlint" ]] && return 0
|
||||||
command -v gdlint &>/dev/null && return 0
|
command -v gdlint &>/dev/null && return 0
|
||||||
python -m gdtoolkit.linter --help &>/dev/null 2>&1
|
has_python_module gdtoolkit.linter
|
||||||
}
|
}
|
||||||
|
|
||||||
run_gdlint() {
|
run_gdlint() {
|
||||||
@@ -83,7 +120,7 @@ run_gdlint() {
|
|||||||
elif command -v gdlint &>/dev/null; then
|
elif command -v gdlint &>/dev/null; then
|
||||||
gdlint "$@"
|
gdlint "$@"
|
||||||
else
|
else
|
||||||
python -m gdtoolkit.linter "$@"
|
run_python_module gdtoolkit.linter "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +198,21 @@ case "$GODOT_VERSION" in
|
|||||||
esac
|
esac
|
||||||
GODOT_ENV=(env "HOME=$GODOT_PROFILE" "APPDATA=$GODOT_PROFILE" "LOCALAPPDATA=$GODOT_PROFILE")
|
GODOT_ENV=(env "HOME=$GODOT_PROFILE" "APPDATA=$GODOT_PROFILE" "LOCALAPPDATA=$GODOT_PROFILE")
|
||||||
|
|
||||||
# -- 0. Godot import bootstrap ------------------------------------------------
|
# -- 0. Cross-platform plugin payload -----------------------------------------
|
||||||
|
platform_assets_result="PASS"
|
||||||
|
: > "$LOG/platform-assets.log"
|
||||||
|
for plugin_file in "${CROSS_PLATFORM_PLUGIN_FILES[@]}"; do
|
||||||
|
if [[ ! -f "$plugin_file" ]]; then
|
||||||
|
platform_assets_result="FAIL"
|
||||||
|
echo "Missing $plugin_file" >> "$LOG/platform-assets.log"
|
||||||
|
ERRORS+=("platform-assets: missing res://$plugin_file")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ "$platform_assets_result" == "FAIL" ]]; then
|
||||||
|
FIXES+=("Restore the complete pinned Terrain3D 1.0.2 package")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# -- 1. Godot import bootstrap ------------------------------------------------
|
||||||
import_result="PASS"
|
import_result="PASS"
|
||||||
: > "$LOG/godot-import.log"
|
: > "$LOG/godot-import.log"
|
||||||
class_cache="$ROOT/.godot/global_script_class_cache.cfg"
|
class_cache="$ROOT/.godot/global_script_class_cache.cfg"
|
||||||
@@ -195,7 +246,7 @@ if [[ "$import_result" == "FAIL" ]]; then
|
|||||||
FIXES+=("Fix Godot import errors before running headless checks")
|
FIXES+=("Fix Godot import errors before running headless checks")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# -- 1. gdformat --------------------------------------------------------------
|
# -- 2. gdformat --------------------------------------------------------------
|
||||||
fmt_result="PASS"
|
fmt_result="PASS"
|
||||||
fmt_failed=false
|
fmt_failed=false
|
||||||
: > "$LOG/gdformat.log"
|
: > "$LOG/gdformat.log"
|
||||||
@@ -243,7 +294,7 @@ elif $fmt_failed; then
|
|||||||
FIXES+=("Fix the gdformat error before continuing")
|
FIXES+=("Fix the gdformat error before continuing")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# -- 2. gdlint ----------------------------------------------------------------
|
# -- 3. gdlint ----------------------------------------------------------------
|
||||||
lint_result="PASS"
|
lint_result="PASS"
|
||||||
lint_failed=false
|
lint_failed=false
|
||||||
: > "$LOG/gdlint.log"
|
: > "$LOG/gdlint.log"
|
||||||
@@ -297,7 +348,7 @@ elif $lint_failed; then
|
|||||||
FIXES+=("Fix the gdlint error before continuing")
|
FIXES+=("Fix the gdlint error before continuing")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# -- 3. godot headless check --------------------------------------------------
|
# -- 4. godot headless check --------------------------------------------------
|
||||||
godot_result="PASS"
|
godot_result="PASS"
|
||||||
: > "$LOG/godot-check.log"
|
: > "$LOG/godot-check.log"
|
||||||
if run_with_timeout 30 "${GODOT_ENV[@]}" "$GODOT" --headless --path "$ROOT" --script res://tests/simulation_definitions_test.gd >> "$LOG/godot-check.log" 2>&1; then
|
if run_with_timeout 30 "${GODOT_ENV[@]}" "$GODOT" --headless --path "$ROOT" --script res://tests/simulation_definitions_test.gd >> "$LOG/godot-check.log" 2>&1; then
|
||||||
@@ -319,7 +370,7 @@ if [[ "$godot_result" == "FAIL" ]]; then
|
|||||||
FIXES+=("Fix Godot parser errors")
|
FIXES+=("Fix Godot parser errors")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# -- 4. project scenario tests ------------------------------------------------
|
# -- 5. project scenario tests ------------------------------------------------
|
||||||
scenario_result="PASS"
|
scenario_result="PASS"
|
||||||
: > "$LOG/scenarios.log"
|
: > "$LOG/scenarios.log"
|
||||||
for test in tests/*_test.gd; do
|
for test in tests/*_test.gd; do
|
||||||
@@ -337,7 +388,7 @@ if [[ "$scenario_result" == "FAIL" ]]; then
|
|||||||
FIXES+=("Fix failing project scenario tests")
|
FIXES+=("Fix failing project scenario tests")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# -- 5. GUT -------------------------------------------------------------------
|
# -- 6. GUT -------------------------------------------------------------------
|
||||||
gut_result="PASS"
|
gut_result="PASS"
|
||||||
: > "$LOG/gut.log"
|
: > "$LOG/gut.log"
|
||||||
if [[ ! -f "addons/gut/gut_cmdln.gd" ]]; then
|
if [[ ! -f "addons/gut/gut_cmdln.gd" ]]; then
|
||||||
@@ -365,7 +416,10 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# -- summary ------------------------------------------------------------------
|
# -- summary ------------------------------------------------------------------
|
||||||
if [[ "$import_result" == "FAIL" || "$fmt_result" == "FAIL" || "$lint_result" == "FAIL" || "$godot_result" == "FAIL" || "$scenario_result" == "FAIL" || "$gut_result" == "FAIL" ]]; then
|
if [[ "$platform_assets_result" == "FAIL" || "$import_result" == "FAIL" ||
|
||||||
|
"$fmt_result" == "FAIL" || "$lint_result" == "FAIL" ||
|
||||||
|
"$godot_result" == "FAIL" || "$scenario_result" == "FAIL" ||
|
||||||
|
"$gut_result" == "FAIL" ]]; then
|
||||||
OVERALL=true
|
OVERALL=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -377,6 +431,7 @@ else
|
|||||||
fi
|
fi
|
||||||
echo "Godot: $GODOT_VERSION"
|
echo "Godot: $GODOT_VERSION"
|
||||||
echo ""
|
echo ""
|
||||||
|
echo " platform-assets $platform_assets_result"
|
||||||
echo " godot-import $import_result"
|
echo " godot-import $import_result"
|
||||||
echo " gdformat $fmt_result"
|
echo " gdformat $fmt_result"
|
||||||
echo " gdlint $lint_result"
|
echo " gdlint $lint_result"
|
||||||
@@ -415,6 +470,7 @@ echo ""
|
|||||||
echo "QUALITY RESULT: $($OVERALL && echo FAIL || echo PASS)"
|
echo "QUALITY RESULT: $($OVERALL && echo FAIL || echo PASS)"
|
||||||
echo "Godot: $GODOT_VERSION"
|
echo "Godot: $GODOT_VERSION"
|
||||||
echo ""
|
echo ""
|
||||||
|
echo " platform-assets $platform_assets_result"
|
||||||
echo " godot-import $import_result"
|
echo " godot-import $import_result"
|
||||||
echo " gdformat $fmt_result"
|
echo " gdformat $fmt_result"
|
||||||
echo " gdlint $lint_result"
|
echo " gdlint $lint_result"
|
||||||
|
|||||||
Reference in New Issue
Block a user