From 85cf4f3b0377e08980cd6e5195411302120292c8 Mon Sep 17 00:00:00 2001 From: Hermes Date: Wed, 3 Jun 2026 23:42:22 +0000 Subject: [PATCH 1/3] chore(hooks): add shared pre-commit-checks script Extrahiert die Pre-Commit-Checks (lint-staged + PHPUnit) in ein gemeinsames Script, das sowohl vom Husky-Hook (.husky/pre-commit) als auch von scripts/safe-commit.sh aufgerufen wird. Logik: - lint-staged laeuft immer (HTML/CSS/JS/JSON/MD/PHP-Syntax) - PHPUnit laeuft nur, wenn PHP-relevante Dateien gestaged sind (*.php, phpunit.xml, composer.json, composer.lock) - Safety-Check: alle gestaged PHP-Dateien muessen auf Disk existieren - Bei Test-Fehler wird der Commit mit Exit-Code != 0 abgebrochen - Composer-Deps werden nur bei Bedarf installiert (Cache-Hit) --- scripts/pre-commit-checks.sh | 77 ++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100755 scripts/pre-commit-checks.sh diff --git a/scripts/pre-commit-checks.sh b/scripts/pre-commit-checks.sh new file mode 100755 index 0000000..86ad475 --- /dev/null +++ b/scripts/pre-commit-checks.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# pre-commit-checks.sh – Pre-Commit Checks (Lint + PHPUnit) +# Wird vom Husky-Hook (.husky/pre-commit) und von scripts/safe-commit.sh aufgerufen. +# +# Abbruch mit Exit-Code != 0 bei Fehler. +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$REPO_ROOT" + +# ───────────────────────────────────────────────────────────── +# 1) lint-staged (HTML, CSS, JS, JSON, MD, PHP-Syntax) +# ───────────────────────────────────────────────────────────── +if command -v npx >/dev/null 2>&1 && [ -f "node_modules/.bin/lint-staged" ]; then + echo "🔍 Pre-Commit: lint-staged laeuft..." + if ! npx lint-staged; then + echo "" + echo "❌ Pre-Commit: lint-staged fehlgeschlagen. Commit abgebrochen." + exit 1 + fi + echo "✅ Pre-Commit: lint-staged OK" +fi + +# ───────────────────────────────────────────────────────────── +# 2) PHPUnit nur, wenn PHP-relevante Dateien gestaged sind +# - *.php Quellcode & Tests +# - phpunit.xml Test-Konfiguration +# - composer.json PHP-Abhaengigkeiten +# - composer.lock Lock-File +# ───────────────────────────────────────────────────────────── +PHP_TOUCHED=$(git diff --cached --name-only --diff-filter=ACMR \ + | grep -E '\.(php)$|^phpunit\.xml$|^composer\.(json|lock)$' || true) + +if [ -n "$PHP_TOUCHED" ]; then + echo "" + echo "==> PHP-Dateien geaendert -> PHPUnit wird ausgefuehrt" + echo " Betroffene Dateien:" + printf ' - %s\n' $PHP_TOUCHED + + # Safety-Check: alle gestaged PHP-Dateien muessen auf der Disk existieren. + # Sonst wuerde PHPUnit eine inkonsistente Codebasis testen (Staged != Working Tree). + MISSING="" + for f in $PHP_TOUCHED; do + [ -f "$f" ] || MISSING="$MISSING $f" + done + if [ -n "$MISSING" ]; then + echo "" + echo "FEHLER: Gestaged PHP-Dateien existieren nicht auf der Disk:" + printf ' - %s\n' $MISSING + echo " Loesung: 'git restore --staged ' oder Working-Tree synchronisieren." + exit 1 + fi + + # Composer-Deps nur installieren, falls noetig (Cache-Hit fuer wiederholte Commits) + if [ ! -f "vendor/bin/phpunit" ]; then + echo "" + echo "==> vendor/ fehlt -> composer install laeuft" + if ! command -v composer >/dev/null 2>&1; then + echo "FEHLER: 'composer' ist nicht installiert." + echo " Installation: https://getcomposer.org/download/" + exit 1 + fi + composer install --no-interaction --prefer-dist --no-progress + fi + + echo "" + echo "==> PHPUnit laeuft..." + if ! vendor/bin/phpunit; then + echo "" + echo "FEHLER: PHPUnit-Tests fehlgeschlagen. Commit abgebrochen." + echo " Behebe die Fehler und versuche es erneut." + exit 1 + fi + + echo "" + echo "==> PHPUnit OK" +fi From b0f769d186ca08a6e80eab10b6b6d45985092ec3 Mon Sep 17 00:00:00 2001 From: Hermes Date: Wed, 3 Jun 2026 23:42:31 +0000 Subject: [PATCH 2/3] feat(hooks): run PHPUnit in pre-commit hook (#67) Erweitert den Husky pre-commit-Hook um einen PHPUnit-Schritt. Ausserdem wird scripts/safe-commit.sh aktualisiert, damit das Safety-Net dieselbe Logik wie der Hook verwendet (kein doppelter Code). Vorher: Hook rief nur 'npx lint-staged' auf. Nachher: Hook ruft scripts/pre-commit-checks.sh auf, das - lint-staged ausfuehrt (unveraendert) - PHPUnit nur dann ausfuehrt, wenn PHP-relevante Dateien gestaged sind (Performance-Optimierung: Issue #67 Anforderung) - Bei Test-Fehler den Commit mit Exit-Code 1 abbricht Closes #67 --- .husky/pre-commit | 4 +++- scripts/safe-commit.sh | 16 ++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index 2312dc5..40620f1 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1,3 @@ -npx lint-staged +# Delegiert an scripts/pre-commit-checks.sh +# (gleiche Logik wie safe-commit.sh-Safety-Net, nur einmalig) +./scripts/pre-commit-checks.sh diff --git a/scripts/safe-commit.sh b/scripts/safe-commit.sh index 6e0c7f7..0f8dacb 100755 --- a/scripts/safe-commit.sh +++ b/scripts/safe-commit.sh @@ -2,7 +2,7 @@ # safe-commit.sh – Commit with pre-commit hooks guaranteed to run # Usage: ./scripts/safe-commit.sh "commit message" # -# This script ensures lint checks always execute, even when committing +# This script ensures lint + PHPUnit checks always execute, even when committing # from non-interactive contexts (CI, AI agents, etc.). set -euo pipefail @@ -21,17 +21,9 @@ if [ -d ".husky" ]; then git config core.hooksPath .husky fi -# Run lint-staged manually as a safety net (in case hook is skipped) -if command -v npx &>/dev/null && [ -f "node_modules/.bin/lint-staged" ]; then - echo "🔍 Running pre-commit lint checks..." - npx lint-staged || { - echo "" - echo "❌ Lint checks failed. Commit aborted." - echo " Fix the errors above and try again." - exit 1 - } - echo "✅ All lint checks passed." -fi +# Run pre-commit checks manually as a safety net (in case hook is skipped) +# Same logic as .husky/pre-commit, just in case the hook is bypassed. +./scripts/pre-commit-checks.sh # Commit with hooks enabled (no --no-verify) git commit -m "$MSG" From 3f1f0f5788cb01b2a1358fefc8e02889c8dde76e Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 4 Jun 2026 00:15:21 +0000 Subject: [PATCH 3/3] fix(hooks): use array-based file iteration for safety check mapfile + array prevents word-splitting issues with filenames containing spaces or other shell-special characters. Affects both the affected-files listing and the stale-index safety check. Without this fix, a filename like 'My Module.php' would be split into 'My' and 'Module.php', causing the disk-existence check to look for wrong paths. --- scripts/pre-commit-checks.sh | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/scripts/pre-commit-checks.sh b/scripts/pre-commit-checks.sh index 86ad475..a651900 100755 --- a/scripts/pre-commit-checks.sh +++ b/scripts/pre-commit-checks.sh @@ -28,25 +28,26 @@ fi # - composer.json PHP-Abhaengigkeiten # - composer.lock Lock-File # ───────────────────────────────────────────────────────────── -PHP_TOUCHED=$(git diff --cached --name-only --diff-filter=ACMR \ +# PHP-relevante Files (Array-basiert, robust gegen Spaces/Newlines in Filenames) +mapfile -t PHP_TOUCHED_ARR < <(git diff --cached --name-only --diff-filter=ACMR \ | grep -E '\.(php)$|^phpunit\.xml$|^composer\.(json|lock)$' || true) -if [ -n "$PHP_TOUCHED" ]; then +if [ "${#PHP_TOUCHED_ARR[@]}" -gt 0 ]; then echo "" echo "==> PHP-Dateien geaendert -> PHPUnit wird ausgefuehrt" echo " Betroffene Dateien:" - printf ' - %s\n' $PHP_TOUCHED + printf ' - %s\n' "${PHP_TOUCHED_ARR[@]}" # Safety-Check: alle gestaged PHP-Dateien muessen auf der Disk existieren. # Sonst wuerde PHPUnit eine inkonsistente Codebasis testen (Staged != Working Tree). - MISSING="" - for f in $PHP_TOUCHED; do - [ -f "$f" ] || MISSING="$MISSING $f" + MISSING=() + for f in "${PHP_TOUCHED_ARR[@]}"; do + [ -f "$f" ] || MISSING+=("$f") done - if [ -n "$MISSING" ]; then + if [ "${#MISSING[@]}" -gt 0 ]; then echo "" echo "FEHLER: Gestaged PHP-Dateien existieren nicht auf der Disk:" - printf ' - %s\n' $MISSING + printf ' - %s\n' "${MISSING[@]}" echo " Loesung: 'git restore --staged ' oder Working-Tree synchronisieren." exit 1 fi