#!/usr/bin/env bash # ============================================================ # Steuerkram Test-Runner mit automatischer Issue-Erstellung # # Verwendung (im Container): # docker compose exec -u www-data web ./scripts/run-tests.sh [ISSUE_NUMMER] # # Parameter: # ISSUE_NUMMER (optional) Nummer des aktuell bearbeiteten Issues, # auf das bei neu erstellten Bug-Issues verwiesen wird. # # Umgebungsvariablen: # CODEBERG_TOKEN Codeberg-API-Token (für Issue-Erstellung) # # Exit-Code: 0 = alle Tests OK, 1 = Fehler gefunden (oder Auswertung fehlgeschlagen) # ============================================================ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" CURRENT_ISSUE="${1:-}" REPO="fds2610/Steuerkram" API_BASE="https://codeberg.org/api/v1" cd "$PROJECT_DIR" # ── PHP als www-data ausführen ─────────────────────────────── # Als root angelegte Dateien unterhalb von data/ sind für Apache/PHP (www-data) # nicht beschreibbar und blockieren später echte Uploads. Deshalb laufen die # Tests mit derselben Kennung wie die Anwendung. if [ "$(id -u)" = "0" ] && id www-data >/dev/null 2>&1; then PHP="setpriv --reuid=www-data --regid=www-data --clear-groups php" else PHP="php" fi # ── Tests ausführen ────────────────────────────────────────── echo "" echo "Führe Tests aus..." # STDERR wird bewusst NICHT mitgefangen: tests/run.php schreibt im --json-Modus # etwaige PHP-Warnungen/-Notices dorthin, damit STDOUT ausschließlich das JSON # enthält (siehe tests/run.php). STDERR landet direkt im Terminal. JSON_OUTPUT=$($PHP tests/run.php --json) && EXIT_CODE=0 || EXIT_CODE=$? # Auch die lesbare Ausgabe zeigen $PHP tests/run.php || true # ── Ergebnis auswerten ─────────────────────────────────────── if [ "$EXIT_CODE" -eq 0 ]; then echo "" echo "✓ Alle Tests bestanden. Commit kann fortgesetzt werden." exit 0 fi # tests/run.php meldet Fehlschläge (oder einen sonstigen Fehler) über den # Exit-Code. Die Details holen wir uns per PHP aus dem JSON – lässt sich die # Ausgabe nicht auswerten, bricht das Skript hier ab (set -e), statt # fälschlich Erfolg zu melden. FAILED=$(echo "$JSON_OUTPUT" | php -r ' $d = json_decode(stream_get_contents(STDIN), true); if (!is_array($d) || !array_key_exists("failed", $d)) { fwrite(STDERR, "Ungültige JSON-Ausgabe von tests/run.php --json\n"); exit(1); } echo $d["failed"]; ') FAILURES_JSON=$(echo "$JSON_OUTPUT" | php -r ' $d = json_decode(stream_get_contents(STDIN), true); if (!is_array($d) || !array_key_exists("failures", $d)) { fwrite(STDERR, "Ungültige JSON-Ausgabe von tests/run.php --json\n"); exit(1); } echo json_encode($d["failures"]); ') echo "" echo "✗ ${FAILED} Test(s) fehlgeschlagen." # ── Issues erstellen (nur wenn Token vorhanden) ────────────── if [ -z "${CODEBERG_TOKEN:-}" ]; then echo "" echo "Hinweis: CODEBERG_TOKEN nicht gesetzt – keine automatischen Issues erstellt." echo "Fehlgeschlagene Tests:" echo "$FAILURES_JSON" | php -r ' $d = json_decode(stream_get_contents(STDIN), true); foreach ((is_array($d) ? $d : []) as $f) { echo " • {$f}\n"; } ' exit 1 fi echo "" echo "Erstelle automatische Bug-Issues auf Codeberg..." CREATED_ISSUES=() # Jede Fehlermeldung als eigenes Issue anlegen while IFS= read -r failure; do [ -z "$failure" ] && continue # Titel kürzen (max. 100 Zeichen) TITLE="[BUG] Test fehlgeschlagen: ${failure:0:80}" # Body zusammenbauen (mit echten Zeilenumbrüchen, kein "\n"-Text) BODY_LINES=( "## Automatisch erkannter Testfehler" "" "**Fehlermeldung:** \`${failure}\`" "" "**Erkannt am:** $(date '+%Y-%m-%d %H:%M:%S')" "" "**Commit:** $(git rev-parse --short HEAD 2>/dev/null || echo 'unbekannt')" "" ) if [ -n "$CURRENT_ISSUE" ]; then BODY_LINES+=("Dieser Fehler wurde beim Bearbeiten von Issue #${CURRENT_ISSUE} entdeckt." "") fi BODY_LINES+=( "### Schritte zur Reproduktion" "1. \`docker compose exec -u www-data web php tests/run.php\` ausführen" "2. Fehler tritt im oben genannten Test auf" "" "_Dieser Issue wurde automatisch durch den Test-Runner erstellt._" "_Das Label 'automate' wurde bewusst NICHT gesetzt (Human-in-the-loop)._" ) BODY=$(printf '%s\n' "${BODY_LINES[@]}") PAYLOAD=$(TITLE="$TITLE" BODY="$BODY" php -r ' echo json_encode([ "title" => getenv("TITLE"), "body" => getenv("BODY"), "labels" => [], ]); ') RESPONSE=$(curl -s -X POST \ -H "Authorization: token $CODEBERG_TOKEN" \ -H "Content-Type: application/json" \ -d "$PAYLOAD" \ "${API_BASE}/repos/${REPO}/issues") ISSUE_NR=$(echo "$RESPONSE" | php -r ' $d = json_decode(stream_get_contents(STDIN), true); echo (is_array($d) && isset($d["number"])) ? $d["number"] : "?"; ') CREATED_ISSUES+=("#${ISSUE_NR}") echo " → Issue #${ISSUE_NR} erstellt: ${failure:0:60}..." done < <(echo "$FAILURES_JSON" | php -r ' $d = json_decode(stream_get_contents(STDIN), true); foreach ((is_array($d) ? $d : []) as $f) { echo $f, "\n"; } ') # ── Kommentar im aktuellen Issue hinterlassen ───────────────── if [ -n "$CURRENT_ISSUE" ] && [ ${#CREATED_ISSUES[@]} -gt 0 ]; then ISSUE_LINKS=$(printf '%s, ' "${CREATED_ISSUES[@]}") ISSUE_LINKS="${ISSUE_LINKS%, }" COMMENT_LINES=( "### Automatische Testläufe" "" "Beim Bearbeiten dieses Issues wurden **${FAILED} Test(s)** fehlgeschlagen." "" "Folgende Bug-Issues wurden automatisch erstellt (ohne 'automate'-Label – bitte manuell prüfen):" "" ) for issue in "${CREATED_ISSUES[@]}"; do COMMENT_LINES+=("- ${issue}") done COMMENT_LINES+=("" "_Commit: $(git rev-parse --short HEAD 2>/dev/null || echo 'unbekannt')_") COMMENT=$(printf '%s\n' "${COMMENT_LINES[@]}") PAYLOAD=$(COMMENT="$COMMENT" php -r ' echo json_encode(["body" => getenv("COMMENT")]); ') curl -s -X POST \ -H "Authorization: token $CODEBERG_TOKEN" \ -H "Content-Type: application/json" \ -d "$PAYLOAD" \ "${API_BASE}/repos/${REPO}/issues/${CURRENT_ISSUE}/comments" > /dev/null echo "" echo "Kommentar mit Links zu Bug-Issues in Issue #${CURRENT_ISSUE} hinterlassen." fi exit 1