Deploy-Skript update.sh mit DB-Migrationssystem hinzugefügt
Kopiert den git-Stand nach /var/www/html (config.php bleibt unangetastet), prüft PHP-Syntax vorab und wendet ausstehende Migrationen aus migrations/ über eine schema_migrations-Tracking-Tabelle an. Tests werden ausgeführt, sobald welche existieren. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
d47b84fa22
commit
cf7371fb40
4 changed files with 167 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -3,4 +3,5 @@ html/config.php
|
|||
info.php
|
||||
config.php
|
||||
*.old
|
||||
html/.Trash-1000
|
||||
|
||||
|
|
|
|||
31
migrations/README.md
Normal file
31
migrations/README.md
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Datenbank-Migrationen
|
||||
|
||||
Migrationen liegen hier als `.sql`-Dateien, benannt nach dem Schema:
|
||||
|
||||
```
|
||||
0001_kurze_beschreibung.sql
|
||||
0002_naechste_aenderung.sql
|
||||
```
|
||||
|
||||
`update.sh` ruft `migrations/run_migrations.php <pfad-zur-config.php>` auf. Das Skript:
|
||||
|
||||
- legt bei Bedarf die Tabelle `schema_migrations` an (Spalte `filename` als Primary Key), die protokolliert, welche Dateinamen bereits angewendet wurden
|
||||
- führt alle noch nicht angewendeten `.sql`-Dateien in Dateinamen-Reihenfolge aus
|
||||
- bricht beim ersten Fehler sofort ab (die fehlgeschlagene Datei wird NICHT als angewendet markiert, alle vorherigen bleiben es)
|
||||
|
||||
## Regeln für neue Migrationen
|
||||
|
||||
- Immer die nächste freie, vierstellige Nummer verwenden (`0003_...`). Eine bereits vergebene Nummer nie wiederverwenden, eine bereits angewendete Datei nachträglich nicht mehr ändern (neue Migration statt Änderung der alten).
|
||||
- So schreiben, dass sie **keine Breaking Changes** verursachen, z. B.:
|
||||
- `CREATE TABLE IF NOT EXISTS ...` statt `CREATE TABLE ...`
|
||||
- Neue Spalten nullable oder mit `DEFAULT` anlegen, statt bestehende `NOT NULL`-Constraints nachträglich zu erzwingen
|
||||
- Kein `DROP TABLE` / `DROP COLUMN` ohne vorherige Rücksprache
|
||||
- Migrationen möglichst idempotent halten (`IF NOT EXISTS`), damit ein erneuter Lauf nach einem Teilfehler nicht sofort wieder bricht.
|
||||
|
||||
## Historie
|
||||
|
||||
`init.sql` (Ausgangsschema für Neuinstallationen) und `update.sql` (bereits manuell eingespieltes Aktien-Modul) liegen bewusst außerhalb dieses Verzeichnisses, da beide bereits auf allen bekannten Servern produktiv sind. Ab jetzt werden neue Schema-Änderungen ausschließlich als nummerierte Migration hier abgelegt.
|
||||
|
||||
## Hinweis
|
||||
|
||||
`run_migrations.php` bindet die produktive `config.php` per `require` ein, um die bestehende `$pdo`-Verbindung wiederzuverwenden. Da `config.php` `session_start()` aufruft, legt der CLI-Lauf dabei eine kurzlebige, ungenutzte Session-Datei an — das ist unschädlich, aber erwähnenswert.
|
||||
63
migrations/run_migrations.php
Normal file
63
migrations/run_migrations.php
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
$configPath = $argv[1] ?? '/var/www/html/config.php';
|
||||
$migrationsDir = __DIR__;
|
||||
|
||||
if (!is_file($configPath)) {
|
||||
fwrite(STDERR, "Config nicht gefunden: $configPath\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require $configPath; // stellt $pdo bereit
|
||||
|
||||
if (!isset($pdo) || !($pdo instanceof PDO)) {
|
||||
fwrite(STDERR, "config.php hat keine \$pdo-Verbindung geliefert.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS schema_migrations (
|
||||
filename VARCHAR(255) NOT NULL PRIMARY KEY,
|
||||
applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)"
|
||||
);
|
||||
|
||||
$applied = $pdo->query("SELECT filename FROM schema_migrations")->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
$files = glob($migrationsDir . '/*.sql') ?: [];
|
||||
sort($files, SORT_STRING);
|
||||
|
||||
$pending = array_values(array_filter(
|
||||
$files,
|
||||
fn(string $f): bool => !in_array(basename($f), $applied, true)
|
||||
));
|
||||
|
||||
if (empty($pending)) {
|
||||
echo "Keine neuen Migrationen.\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
foreach ($pending as $file) {
|
||||
$name = basename($file);
|
||||
echo "-> Migration $name ... ";
|
||||
|
||||
$sql = file_get_contents($file);
|
||||
if ($sql === false || trim($sql) === '') {
|
||||
fwrite(STDERR, "\nMigration $name ist leer oder konnte nicht gelesen werden.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo->exec($sql);
|
||||
$stmt = $pdo->prepare("INSERT INTO schema_migrations (filename) VALUES (?)");
|
||||
$stmt->execute([$name]);
|
||||
echo "OK\n";
|
||||
} catch (Throwable $e) {
|
||||
fwrite(STDERR, "\nFEHLER bei $name: " . $e->getMessage() . "\n");
|
||||
fwrite(STDERR, "Abbruch. Bereits erfolgreich angewendete Migrationen bleiben markiert, $name muss manuell geprueft werden.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
echo "Alle Migrationen angewendet.\n";
|
||||
72
update.sh
Executable file
72
update.sh
Executable file
|
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Deployt den aktuellen git-Stand dieses Projektverzeichnisses in den Webroot
|
||||
# und wendet danach ausstehende Datenbank-Migrationen an.
|
||||
#
|
||||
# Aufruf (im Projektverzeichnis):
|
||||
# ./update.sh
|
||||
#
|
||||
# Optional per Umgebungsvariable überschreibbar:
|
||||
# WEBROOT=/anderer/pfad ./update.sh
|
||||
# CONFIG_FILE=/anderer/pfad/config.php ./update.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
WEBROOT="${WEBROOT:-/var/www/html}"
|
||||
CONFIG_FILE="${CONFIG_FILE:-$WEBROOT/config.php}"
|
||||
|
||||
log() { echo "==> $*"; }
|
||||
fail() { echo "FEHLER: $*" >&2; exit 1; }
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
command -v php >/dev/null 2>&1 || fail "php ist nicht installiert bzw. nicht im PATH."
|
||||
[ -d "$WEBROOT" ] || fail "Webroot $WEBROOT existiert nicht."
|
||||
[ -w "$WEBROOT" ] || fail "Keine Schreibrechte auf $WEBROOT."
|
||||
|
||||
# --- 1. Sicherstellen, dass das Projektverzeichnis sauber ist ---
|
||||
if ! git diff --quiet || ! git diff --cached --quiet; then
|
||||
fail "Lokale Änderungen im Projektverzeichnis vorhanden - bitte erst committen oder stashen."
|
||||
fi
|
||||
|
||||
# --- 2. Neuesten Stand holen ---
|
||||
log "git pull..."
|
||||
git pull --ff-only
|
||||
|
||||
# --- 3. PHP-Syntaxcheck als Sicherheitsnetz vor dem Kopieren ---
|
||||
log "Prüfe PHP-Syntax..."
|
||||
while IFS= read -r -d '' file; do
|
||||
php -l "$file" >/dev/null || fail "Syntaxfehler in $file - es wird nichts kopiert."
|
||||
done < <(find html -name '*.php' -print0)
|
||||
|
||||
# --- 4. Dateien kopieren, config.php bleibt unangetastet ---
|
||||
log "Kopiere Dateien nach $WEBROOT..."
|
||||
config_backup=""
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
config_backup="$(mktemp)"
|
||||
cp "$CONFIG_FILE" "$config_backup"
|
||||
fi
|
||||
|
||||
cp -r html/. "$WEBROOT/"
|
||||
|
||||
if [ -n "$config_backup" ]; then
|
||||
cp "$config_backup" "$CONFIG_FILE"
|
||||
rm -f "$config_backup"
|
||||
fi
|
||||
|
||||
# --- 5. Datenbank-Migrationen ---
|
||||
if [ -d migrations ] && [ -f migrations/run_migrations.php ]; then
|
||||
log "Wende Datenbank-Migrationen an..."
|
||||
php migrations/run_migrations.php "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
# --- 6. Tests ---
|
||||
if [ -f tests/run.sh ]; then
|
||||
log "Führe Tests aus..."
|
||||
bash tests/run.sh
|
||||
else
|
||||
log "Noch keine Tests vorhanden - werden später ergänzt."
|
||||
fi
|
||||
|
||||
log "Update abgeschlossen."
|
||||
Loading…
Add table
Reference in a new issue