Fix #169: update.sh bricht bei rotem Testergebnis ab statt nur zu warnen

Schritt 9/9 setzte bisher nur eine Warnung ab und lief mit Exit-Code 0
weiter, obwohl die neue Version bereits live war. Jetzt zählt auch
tests/e2e/run.sh zum Gate (überspringt sich selbst mit Exit 0 ohne
Runner), ein Fehlschlag setzt UPDATE_FAILED=true und beendet das
Script mit Exit-Code 1. Kein automatischer Rollback – stattdessen ein
lauter Hinweis auf das Backup aus Schritt 3 und ./scripts/restore.sh.
--no-tests bleibt als Notausstieg bestehen.
This commit is contained in:
fds2610-bot 2026-08-02 23:03:23 +02:00
parent 00e1ae5bfb
commit d753ff11a7
3 changed files with 93 additions and 17 deletions

View file

@ -2,6 +2,11 @@
--- ---
## 2026-08-02 – Testsuite als echtes Gate in update.sh (#169)
- Schritt 9/9 von `scripts/update.sh` gab bei rotem Testergebnis nur eine Warnung aus – Exit-Code 0, kein Abbruch. Ein Update mit fehlgeschlagenen Tests galt damit als erfolgreich, obwohl die neue Version zu diesem Zeitpunkt bereits live war.
- **`scripts/update.sh`:** Schritt 9 führt jetzt zusätzlich zur PHP-Suite `tests/e2e/run.sh` aus und wertet beide Ergebnisse als Gate: Schlägt eine der beiden Suiten fehl, setzt `UPDATE_FAILED=true` und der Lauf endet mit Exit-Code 1. `tests/e2e/run.sh` überspringt sich selbst mit Exit-Code 0, wenn kein e2e-runner-Projekt bzw. kein Playwright-Image vorhanden ist (Normalfall auf Produktivmaschinen) – das zählt als bestanden, nicht als Fehler; nachgeladen wird nichts. Kein automatischer Rollback (Migrationen sind ggf. nicht rückwärtskompatibel): bei rotem Ergebnis nennt das Script stattdessen laut die Pfade des in Schritt 3 erstellten Backups und den Befehl `./scripts/restore.sh`. `--no-tests` bleibt als dokumentierter Notausstieg bestehen.
## 2026-08-02 – Aufräumen des verwaisten data/uploads-Verzeichnisses (#173) ## 2026-08-02 – Aufräumen des verwaisten data/uploads-Verzeichnisses (#173)
- Rest aus dem Umzug der Nutzdaten nach `data/` (#150): Ein root-eigenes, leeres `data/uploads` blieb auf Produktivsystemen zurück und lenkte bei der Suche nach Rechteproblemen unter `data/` ab. Weder `docker-compose.yml` noch `docker-entrypoint.sh` legen es an – aktuell wird ausschließlich `data/legacy-uploads` verwendet. - Rest aus dem Umzug der Nutzdaten nach `data/` (#150): Ein root-eigenes, leeres `data/uploads` blieb auf Produktivsystemen zurück und lenkte bei der Suche nach Rechteproblemen unter `data/` ab. Weder `docker-compose.yml` noch `docker-entrypoint.sh` legen es an – aktuell wird ausschließlich `data/legacy-uploads` verwendet.

View file

@ -62,14 +62,31 @@ Das Script erledigt in dieser Reihenfolge:
5. **Container-Neustart** – `docker compose down --remove-orphans` + `up -d` 5. **Container-Neustart** – `docker compose down --remove-orphans` + `up -d`
6. **Healthcheck** – Wartet bis die Datenbank `healthy` meldet (max. 120 s) 6. **Healthcheck** – Wartet bis die Datenbank `healthy` meldet (max. 120 s)
7. **Migrationen** – `scripts/migrate.php` wird explizit ausgeführt (idempotent) 7. **Migrationen** – `scripts/migrate.php` wird explizit ausgeführt (idempotent)
8. **Tests** – Die Test-Suite wird ausgeführt und das Ergebnis angezeigt 8. **Tests als Gate** – PHP-Suite und `tests/e2e/run.sh` werden ausgeführt; schlägt eine der beiden fehl, endet `update.sh` mit Exit-Code 1
### Tests als Gate
Ein Fehlschlag in Schritt 9 ist kein bloßer Hinweis mehr, sondern bricht das Update
mit Exit-Code 1 ab – die zuvor als „erfolgreich" gemeldete, aber ungeprüfte Version
lief sonst bereits live weiter. Geprüft werden zwei Suiten:
- **PHP-Suite** (`tests/run.php`) – läuft immer.
- **E2E-Suite** (`tests/e2e/run.sh`) – läuft nur, wenn auf der Maschine ein
e2e-runner-Projekt samt gepulltem Playwright-Image vorhanden ist. Fehlt eines
davon (Normalfall auf Produktivmaschinen), überspringt sich `run.sh` selbst mit
Exit-Code 0 – das zählt als bestanden, `update.sh` lädt dabei nichts nach.
Es gibt **keinen automatischen Rollback** – Migrationen sind unter Umständen nicht
rückwärtskompatibel. Bei rotem Ergebnis nennt `update.sh` stattdessen laut die
Pfade des in Schritt 3 erstellten Backups und verweist auf `./scripts/restore.sh`
zum manuellen Zurückspielen.
### Optionen ### Optionen
| Option | Bedeutung | | Option | Bedeutung |
|---|---| |---|---|
| `--no-backup` | Backup überspringen (z. B. wenn gerade erst gesichert) | | `--no-backup` | Backup überspringen (z. B. wenn gerade erst gesichert) |
| `--no-tests` | Tests nicht ausführen (schnellerer Ablauf) | | `--no-tests` | Tests nicht ausführen – dokumentierter Notausstieg; die laufende Version bleibt dann ungeprüft |
| `--force-rebuild` | Docker-Image immer neu bauen, unabhängig von Dateiänderungen | | `--force-rebuild` | Docker-Image immer neu bauen, unabhängig von Dateiänderungen |
### Migrationen ### Migrationen
@ -99,6 +116,9 @@ docker compose logs db # Datenbank-Log
Falls ein Update fehlschlägt und ein Rollback nötig ist, das letzte Backup einspielen: Falls ein Update fehlschlägt und ein Rollback nötig ist, das letzte Backup einspielen:
```bash ```bash
docker compose exec -T db mariadb -u steuerkram -psteuerkram steuerkram \ ./scripts/restore.sh
< backups/steuerkram_db_YYYYMMDD_HHMM.sql
``` ```
Spielt automatisch das neueste vollständige Backup-Paar (DB + Uploads) ein und
führt anschließend ausstehende Migrationen aus. Ein bestimmter Zeitstempel lässt
sich explizit angeben: `./scripts/restore.sh 20260517_134945`.

View file

@ -9,7 +9,9 @@
# • Docker-Image-Rebuild (bei Änderungen an Dockerfile, composer.json, etc.) # • Docker-Image-Rebuild (bei Änderungen an Dockerfile, composer.json, etc.)
# • Datenbank-Migrationen # • Datenbank-Migrationen
# • Berechtigungen und Upload-Verzeichnisse # • Berechtigungen und Upload-Verzeichnisse
# • Optionale Testausführung # • Testsuite als Gate: schlägt sie fehl, endet update.sh mit Exit-Code 1
# und weist laut auf das Backup aus Schritt 3 hin (kein automatischer
# Rollback – Migrationen sind ggf. nicht rückwärtskompatibel)
# #
# Usage: # Usage:
# ./update.sh [--no-backup] [--no-tests] [--force-rebuild] # ./update.sh [--no-backup] [--no-tests] [--force-rebuild]
@ -151,6 +153,11 @@ fi
# ════════════════════════════════════════════════════════════════════════════ # ════════════════════════════════════════════════════════════════════════════
step "3/9 Backup erstellen" step "3/9 Backup erstellen"
# Pfade des in diesem Lauf erstellten Backups – falls Schritt 9 die Test-Suite
# rot meldet, werden sie dort als manueller Rollback-Hinweis ausgegeben.
BACKUP_DB_PATH=""
BACKUP_UPLOADS_PATH=""
if [[ "$OPT_NO_BACKUP" == "true" ]]; then if [[ "$OPT_NO_BACKUP" == "true" ]]; then
warn "Backup übersprungen (--no-backup)" warn "Backup übersprungen (--no-backup)"
else else
@ -159,6 +166,8 @@ else
info "Erstelle Backup vor dem Update..." info "Erstelle Backup vor dem Update..."
if bash "$PROJECT_DIR/scripts/backup.sh"; then if bash "$PROJECT_DIR/scripts/backup.sh"; then
ok "Backup erfolgreich erstellt" ok "Backup erfolgreich erstellt"
BACKUP_DB_PATH=$(ls -t "$PROJECT_DIR/backups/steuerkram_db_"*.sql 2>/dev/null | head -1)
BACKUP_UPLOADS_PATH=$(ls -t "$PROJECT_DIR/backups/steuerkram_uploads_"*.tar.gz 2>/dev/null | head -1)
else else
warn "Backup fehlgeschlagen – Update wird trotzdem fortgesetzt" warn "Backup fehlgeschlagen – Update wird trotzdem fortgesetzt"
warn "Prüfe den Backup-Fehler manuell: ./scripts/backup.sh" warn "Prüfe den Backup-Fehler manuell: ./scripts/backup.sh"
@ -351,25 +360,67 @@ if [[ "$UPDATE_FAILED" == "false" ]]; then
fi fi
# ════════════════════════════════════════════════════════════════════════════ # ════════════════════════════════════════════════════════════════════════════
# SCHRITT 9: Tests ausführen # SCHRITT 9: Tests als Gate
# ════════════════════════════════════════════════════════════════════════════ # ════════════════════════════════════════════════════════════════════════════
step "9/9 Tests" # Ein Fehlschlag hier bricht das Update nicht mehr nur mit einer Warnung ab –
# UPDATE_FAILED=true sorgt über die Zusammenfassung unten für Exit-Code 1.
# Kein automatischer Rollback: Migrationen sind ggf. nicht rückwärtskompatibel,
# darum nur ein lauter Hinweis auf das Backup aus Schritt 3 (siehe #169).
step "9/9 Tests (Gate)"
if [[ "$OPT_NO_TESTS" == "true" ]]; then if [[ "$OPT_NO_TESTS" == "true" ]]; then
warn "Tests übersprungen (--no-tests)" warn "Tests übersprungen (--no-tests) – die laufende Version ist UNGEPRÜFT"
else else
info "Führe Test-Suite aus..." TEST_FAILED=false
if TEST_OUTPUT=$(docker compose exec -T -u www-data web php /var/www/html/tests/run.php 2>&1); then
TEST_EXIT=0
else
TEST_EXIT=$?
fi
info "Führe PHP-Test-Suite aus..."
if TEST_OUTPUT=$(docker compose exec -T -u www-data web php /var/www/html/tests/run.php 2>&1); then
PHP_TEST_EXIT=0
else
PHP_TEST_EXIT=$?
fi
echo "$TEST_OUTPUT" | while read -r line; do info "$line"; done echo "$TEST_OUTPUT" | while read -r line; do info "$line"; done
if [[ "$TEST_EXIT" -ne 0 ]]; then if [[ "$PHP_TEST_EXIT" -ne 0 ]]; then
warn "Einige Tests sind fehlgeschlagen – bitte prüfen" fail "PHP-Test-Suite fehlgeschlagen"
warn "Vollständiger Testlauf: docker compose exec -u www-data web php tests/run.php" TEST_FAILED=true
else
ok "PHP-Test-Suite bestanden"
fi
# E2E-Suite ist bewusst optional: Ohne e2e-runner-Projekt oder Playwright-
# Image (Normalfall auf einer Produktionsmaschine) überspringt run.sh sich
# selbst mit Exit-Code 0 – das zählt hier als bestanden, nicht als Fehler.
# run.sh lädt dabei nichts nach; das Gate darf das ebenfalls nicht tun.
info "Führe E2E-Test-Suite aus (übersprungen, falls kein Runner vorhanden)..."
if E2E_OUTPUT=$("$PROJECT_DIR/tests/e2e/run.sh" 2>&1); then
E2E_TEST_EXIT=0
else
E2E_TEST_EXIT=$?
fi
echo "$E2E_OUTPUT" | while read -r line; do info "$line"; done
if [[ "$E2E_TEST_EXIT" -ne 0 ]]; then
fail "E2E-Test-Suite fehlgeschlagen"
TEST_FAILED=true
else
ok "E2E-Test-Suite bestanden oder übersprungen"
fi
if [[ "$TEST_FAILED" == "true" ]]; then
UPDATE_FAILED=true
fail "Tests fehlgeschlagen – die aktuell laufende Version ist UNGEPRÜFT"
info "Kein automatischer Rollback (Migrationen sind ggf. nicht rückwärtskompatibel)."
if [[ -n "$BACKUP_DB_PATH" ]]; then
info "Backup von vor diesem Update:"
info " DB: $BACKUP_DB_PATH"
[[ -n "$BACKUP_UPLOADS_PATH" ]] && info " Uploads: $BACKUP_UPLOADS_PATH"
info "Manuell zurückspielen: ./scripts/restore.sh"
else
warn "Kein Backup aus Schritt 3/9 vorhanden (--no-backup gesetzt oder DB war inaktiv)."
fi
info "Vollständiger PHP-Testlauf: docker compose exec -u www-data web php tests/run.php"
info "Vollständiger E2E-Testlauf: tests/e2e/run.sh"
else else
ok "Alle Tests bestanden" ok "Alle Tests bestanden"
fi fi