#!/usr/bin/env sh # pre-commit – Agent Quality Gate # # Prüft bei jeder Code-Änderung ob: # 1. Tests erstellt oder aktualisiert wurden # 2. Mindestens eine Zielgruppen-Dokumentation aktualisiert wurde # 3. Alle 3 Dokumentations-Zielgruppen vorhanden sind (USER/ADMIN/MAINTAINER) # 4. history/summary/PROJECT_CONTEXT.md aktualisiert wurde # 5. docs/requirements/REQUIREMENTS.md keine unstaged Änderungen hat # # Hooks laufen immer – kein --no-verify verwenden. STAGED=$(git diff --cached --name-only --diff-filter=ACMR 2>/dev/null) ERRORS=0 # Quellcode-Dateien (keine Tests, keine Konfiguration, keine Docs, keine Daten) CODE_CHANGED=$(printf '%s\n' "$STAGED" \ | grep -E '\.(py|js|ts|mjs|cjs|go|java|rs|rb|php|c|cpp|h|hpp|cs|kt|swift|sh|bash)$' \ | grep -v -E '(test|spec|__tests__|_test)\.(py|js|ts|mjs|go|java|rs|rb|php|c|cpp|cs|kt|swift)$' \ | grep -v -E '^(docs/|\.github/|\.vscode/|data/|history/)' \ | grep -v -E '_test\.go$') # Keine Code-Änderungen → Hook überspringen if [ -z "$CODE_CHANGED" ]; then exit 0 fi # ── Check 1: Tests ──────────────────────────────────────────────────────────── # Opt-out: Datei '.copilot-no-tests' im Repo-Root deaktiviert diesen Check # (für Repos ohne Test-Framework, z.B. reine Script/Config-Repos) TESTS_CHANGED=$(printf '%s\n' "$STAGED" \ | grep -E '(test|spec|__tests__|_test)\.(py|js|ts|mjs|go|java|rs|rb|php|c|cpp|cs|kt|swift)$|_test\.go$|test_.*\.py$') if [ -z "$TESTS_CHANGED" ] && [ ! -f ".copilot-no-tests" ]; then echo "" echo "✗ AGENT QUALITY GATE [1/4]: Keine Test-Dateien geändert" echo " Code-Änderungen ohne Test-Updates:" printf '%s\n' "$CODE_CHANGED" | sed 's/^/ /' echo "" echo " → Tests fehlen oder nicht als STAGED markiert" echo " → Copilot Chat: /write-tests" echo " → Kein Test-Framework vorhanden? Datei '.copilot-no-tests' anlegen um diesen Check zu deaktivieren" ERRORS=$((ERRORS + 1)) fi # ── Check 2: Dokumentation aktualisiert ─────────────────────────────────────── # Prüfen ob docs/ Verzeichnis überhaupt existiert # Opt-out: Datei '.copilot-no-docs' im Repo-Root deaktiviert diesen Check # (für reine Config/Script-Repos ohne nutzerseitige Dokumentationspflicht) if [ -d "docs" ] && [ ! -f ".copilot-no-docs" ]; then DOCS_CHANGED=$(printf '%s\n' "$STAGED" \ | grep -E '(^docs/USER\.md$|^docs/ADMIN\.md$|^docs/MAINTAINER\.md$|^README\.md$)') if [ -z "$DOCS_CHANGED" ]; then echo "" echo "✗ AGENT QUALITY GATE [2/4]: Keine Dokumentation aktualisiert" echo " Bei Code-Änderungen muss mindestens eine dieser Dateien angepasst werden:" echo " docs/USER.md – Nutzer-Dokumentation" echo " docs/ADMIN.md – Administrator-Dokumentation" echo " docs/MAINTAINER.md – Entwickler/Maintainer-Dokumentation" echo " README.md" echo "" echo " → Copilot Chat: Frage den Agent die relevante Doku zu aktualisieren" ERRORS=$((ERRORS + 1)) fi fi # ── Check 3: Vollständigkeit der 3 Zielgruppen ──────────────────────────────── # Nur prüfen wenn docs/ neu angelegt wird (noch nicht vollständig) oder ein # neues Feature ein neues docs/-File staged hat. DOCS_DIR_STAGED=$(printf '%s\n' "$STAGED" | grep -E '^docs/' | head -1) if [ -n "$DOCS_DIR_STAGED" ] && [ -d "docs" ]; then MISSING="" [ ! -f "docs/USER.md" ] && MISSING="${MISSING}\n docs/USER.md (fehlt – für Endnutzer)" [ ! -f "docs/ADMIN.md" ] && MISSING="${MISSING}\n docs/ADMIN.md (fehlt – für Administratoren)" [ ! -f "docs/MAINTAINER.md" ] && MISSING="${MISSING}\n docs/MAINTAINER.md (fehlt – für Entwickler)" if [ -n "$MISSING" ]; then echo "" echo "✗ AGENT QUALITY GATE [3/4]: Fehlende Zielgruppen-Dokumentation" printf " Nicht vorhanden:%b\n" "$MISSING" echo "" echo " Alle 3 Zielgruppen-Dokumente müssen existieren." echo " Templates: docs/USER.md, docs/ADMIN.md, docs/MAINTAINER.md" ERRORS=$((ERRORS + 1)) fi fi # ── Check 4: PROJECT_CONTEXT.md aktualisiert ────────────────────────────────── if [ -f "history/summary/PROJECT_CONTEXT.md" ]; then CONTEXT_STAGED=$(printf '%s\n' "$STAGED" | grep -F 'history/summary/PROJECT_CONTEXT.md') if [ -z "$CONTEXT_STAGED" ]; then echo "" echo "✗ AGENT QUALITY GATE [4/4]: PROJECT_CONTEXT.md nicht aktualisiert" echo " Bei Code-Änderungen muss der Agent-Kontext aktuell gehalten werden." echo " history/summary/PROJECT_CONTEXT.md" echo "" echo " → Copilot Chat: /history (loggt Session + aktualisiert Kontext)" ERRORS=$((ERRORS + 1)) fi fi # ── Check 5: Requirements-Konsistenz ───────────────────────────────────────── # Wenn docs/requirements/REQUIREMENTS.md existiert und unstaged Änderungen hat, # muss es vor dem Commit gestaged werden. # Opt-out: Datei '.copilot-no-requirements' im Repo-Root deaktiviert diesen Check. if [ -f "docs/requirements/REQUIREMENTS.md" ] && [ ! -f ".copilot-no-requirements" ]; then REQ_UNSTAGED=$(git diff --name-only -- "docs/requirements/REQUIREMENTS.md" 2>/dev/null) if [ -n "$REQ_UNSTAGED" ]; then echo "" echo "✗ AGENT QUALITY GATE [5/5]: Requirements-Datei hat unstaged Änderungen" echo " docs/requirements/REQUIREMENTS.md wurde geändert aber nicht gestaged." echo "" echo " → git add docs/requirements/REQUIREMENTS.md" echo " → Copilot Chat: /requirements (Requirements aktualisieren + konsistenz prüfen)" ERRORS=$((ERRORS + 1)) fi fi # ── Ergebnis ────────────────────────────────────────────────────────────────── if [ "$ERRORS" -gt 0 ]; then echo "" echo "══════════════════════════════════════════════════════════" echo " $ERRORS von 5 Quality Gate(s) nicht bestanden." echo " Behebe die Probleme bevor du committst." echo " ══════════════════════════════════════════════════════════" echo "" exit 1 fi exit 0