chore: run gdlint/gdformat on pre-push only when client .gd changes.

pull/149/head
VinPropane 2026-05-31 19:42:23 -04:00
parent c8d475670c
commit 24d598e0a2
3 changed files with 70 additions and 3 deletions

View File

@ -59,7 +59,7 @@ CI also enforces **`gdlint`** and **`gdformat`** (see `gdlintrc` and `.github/wo
`gdformat --check client/scripts client/test` `gdformat --check client/scripts client/test`
- If formatting fails, run: - If formatting fails, run:
`gdformat client/scripts client/test` `gdformat client/scripts client/test`
- Install the repos local **pre-push** hook from the repo root to enforce those checks automatically: - Install the repos local **pre-push** hook from the repo root to enforce those checks when **`client/scripts/`** or **`client/test/`** `.gd` files change in the push:
`./scripts/install-git-hooks.sh` `./scripts/install-git-hooks.sh`
## GdUnit test layout (AAA) ## GdUnit test layout (AAA)

View File

@ -353,9 +353,9 @@ pwsh -File scripts/install-git-hooks.ps1
This installs: This installs:
- **pre-commit**: blocks commits when `client/scripts/*.gd` changes lack matching `client/test/*_test.gd` updates, or when server route/contract files change without corresponding `server/NeonSprawl.Server.Tests/` and `bruno/neon-sprawl-server/**/*.bru` updates. - **pre-commit**: blocks commits when `client/scripts/*.gd` changes lack matching `client/test/*_test.gd` updates, or when server route/contract files change without corresponding `server/NeonSprawl.Server.Tests/` and `bruno/neon-sprawl-server/**/*.bru` updates.
- **pre-push**: runs **`gdlint client/scripts client/test`** and **`gdformat --check client/scripts client/test`**. - **pre-push**: when **`client/scripts/*.gd`** or **`client/test/*.gd`** changed in the commits being pushed, runs **`gdlint client/scripts client/test`** and **`gdformat --check client/scripts client/test`** (same scope as CI). Otherwise skips lint/format. Still requires a **clean working tree** on every push.
The pre-push hook prefers **`.venv-gd/bin/`** (Unix) or **`.venv-gd/Scripts/`** (Windows venv) when present; without that venv or a global install, the hook **fails** and blocks the push — same as CI. The pre-push hook prefers **`.venv-gd/bin/`** (Unix) or **`.venv-gd/Scripts/`** (Windows venv) when present; without that venv or a global install, the hook **fails** when GDScript changed — same as CI. Pushes with no client `.gd` changes do not require gdtoolkit installed.
**If CI fails gdlint but your push succeeded:** the hook was not installed, **`gdlint`/`gdformat` were missing** when the hook ran, or push bypassed hooks (`--no-verify`). **If CI fails gdlint but your push succeeded:** the hook was not installed, **`gdlint`/`gdformat` were missing** when the hook ran, or push bypassed hooks (`--no-verify`).

View File

@ -11,6 +11,70 @@ if [[ -n "$(git status --porcelain)" ]]; then
exit 1 exit 1
fi fi
zero_sha="0000000000000000000000000000000000000000"
gd_changed_files=()
collect_gd_changes_in_range() {
local range="$1"
while IFS= read -r -d '' path; do
gd_changed_files+=("$path")
done < <(
git diff --name-only -z --diff-filter=ACMR "$range" -- \
'client/scripts/*.gd' 'client/test/*.gd' 2>/dev/null || true
)
}
read_any_ref=false
while read -r local_ref local_sha remote_ref remote_sha; do
read_any_ref=true
if [[ "$local_sha" == "$zero_sha" ]]; then
continue
fi
local range=""
if [[ "$remote_sha" == "$zero_sha" ]]; then
local base=""
if git show-ref --verify --quiet refs/remotes/origin/main; then
base="$(git merge-base origin/main "$local_sha" 2>/dev/null || true)"
fi
if [[ -z "$base" ]] && git show-ref --verify --quiet refs/heads/main; then
base="$(git merge-base main "$local_sha" 2>/dev/null || true)"
fi
if [[ -n "$base" ]]; then
range="${base}..${local_sha}"
else
range="$local_sha"
fi
else
range="${remote_sha}..${local_sha}"
fi
collect_gd_changes_in_range "$range"
done
# Fallback when stdin is empty (non-standard invocations).
if [[ "$read_any_ref" == false ]]; then
local head_sha
head_sha="$(git rev-parse HEAD)"
local base=""
if git show-ref --verify --quiet refs/remotes/origin/main; then
base="$(git merge-base origin/main "$head_sha" 2>/dev/null || true)"
fi
if [[ -z "$base" ]] && git show-ref --verify --quiet refs/heads/main; then
base="$(git merge-base main "$head_sha" 2>/dev/null || true)"
fi
if [[ -n "$base" ]]; then
collect_gd_changes_in_range "${base}..${head_sha}"
else
collect_gd_changes_in_range "$head_sha"
fi
fi
if [[ ${#gd_changed_files[@]} -eq 0 ]]; then
echo "pre-push: no client/scripts or client/test .gd changes in push — skipping gdlint/gdformat"
exit 0
fi
gdlint_bin="" gdlint_bin=""
gdformat_bin="" gdformat_bin=""
@ -38,6 +102,9 @@ if [[ -z "$gdlint_bin" || -z "$gdformat_bin" ]]; then
exit 1 exit 1
fi fi
echo "pre-push: client .gd changes detected — running gdlint and gdformat --check"
printf ' %s\n' "${gd_changed_files[@]}"
echo "pre-push: running gdlint on client/scripts and client/test" echo "pre-push: running gdlint on client/scripts and client/test"
"$gdlint_bin" client/scripts client/test "$gdlint_bin" client/scripts client/test