361 lines
11 KiB
Bash
Executable File
361 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
# Immer im Repo-Verzeichnis arbeiten (wichtig für Backup/Restore mit relativen Pfaden)
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
cd "$SCRIPT_DIR"
|
|
|
|
# Deployment Script für Harheimer TC Website
|
|
# Sichert Produktivdaten vor dem Build und stellt sie danach wieder her
|
|
|
|
echo "=== Harheimer TC Deployment ==="
|
|
echo ""
|
|
echo "Working directory: $(pwd)"
|
|
echo ""
|
|
|
|
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
echo "ERROR: Dieses Script muss im Git-Repository ausgeführt werden (kein .git gefunden)."
|
|
exit 1
|
|
fi
|
|
|
|
# Optional (empfohlen): Persistente Daten außerhalb des Git-Repos halten und per Symlink einbinden.
|
|
# Das verhindert zuverlässig, dass Git jemals Produktivdaten überschreibt.
|
|
DEPLOY_HOME="${DEPLOY_HOME:-${HOME:-/tmp}}"
|
|
DATA_ROOT="${DATA_ROOT:-$DEPLOY_HOME/harheimertc-data}"
|
|
BACKUP_ROOT="${BACKUP_ROOT:-$DEPLOY_HOME/harheimertc-backups}"
|
|
|
|
mkdir -p "$DATA_ROOT" "$BACKUP_ROOT"
|
|
|
|
ensure_symlink_dir() {
|
|
local src="$1" # z.B. server/data
|
|
local target="$2" # z.B. /var/lib/harheimertc/server-data
|
|
|
|
mkdir -p "$(dirname "$src")"
|
|
mkdir -p "$target"
|
|
|
|
if [ -L "$src" ]; then
|
|
return 0
|
|
fi
|
|
|
|
if [ -d "$src" ]; then
|
|
echo " Moving $src -> $target (first-time migration)"
|
|
# Merge existing content into target
|
|
cp -a "$src/." "$target/" || true
|
|
rm -rf "$src"
|
|
fi
|
|
|
|
ln -s "$target" "$src"
|
|
echo " Linked $src -> $target"
|
|
}
|
|
|
|
has_tracked_files_under() {
|
|
local prefix="$1" # e.g. public/data
|
|
# If any file is tracked under this path, symlinking the directory will break git operations
|
|
git ls-files "$prefix" | head -n 1 | grep -q .
|
|
}
|
|
|
|
echo "0. Ensuring persistent data directories (recommended)..."
|
|
# IMPORTANT: Only symlink server/data if it's not tracked by git.
|
|
if has_tracked_files_under "server/data"; then
|
|
echo " Skipping symlink for server/data (tracked files detected in git)."
|
|
echo " Recommendation: remove server/data/** from git history and keep them only as production data."
|
|
else
|
|
ensure_symlink_dir "server/data" "$DATA_ROOT/server-data"
|
|
fi
|
|
|
|
# IMPORTANT: Only symlink public/data if it's not tracked by git.
|
|
# Otherwise git will error with "path is beyond a symbolic link".
|
|
if has_tracked_files_under "public/data"; then
|
|
echo " Skipping symlink for public/data (tracked files detected in git)."
|
|
echo " Recommendation: remove public/data/*.csv from git history and keep them only as production data."
|
|
else
|
|
ensure_symlink_dir "public/data" "$DATA_ROOT/public-data"
|
|
fi
|
|
|
|
ensure_symlink_dir "public/uploads" "$DATA_ROOT/public-uploads"
|
|
echo ""
|
|
|
|
# 1. BACKUP: Laufende Produktivdaten VOR allen Git-Operationen sichern
|
|
echo "1. Backing up current production data (pre-git)..."
|
|
|
|
# Human readable timestamp (lokal)
|
|
BACKUP_TS="$(date +"%Y-%m-%d_%H-%M-%S")"
|
|
BACKUP_DIR="$BACKUP_ROOT/backup_$BACKUP_TS"
|
|
mkdir -p "$BACKUP_DIR"
|
|
echo " Backup directory: $BACKUP_DIR"
|
|
|
|
# Backup server data (JSON) und CSVs immer vom Dateisystem, nicht aus 'stash'
|
|
if [ -d server/data ]; then
|
|
cp -a server/data "$BACKUP_DIR/server-data"
|
|
echo " Backed up server/data -> $BACKUP_DIR/server-data"
|
|
else
|
|
echo "ERROR: server/data existiert nicht. Abbruch, damit wir keine Repo-Defaults ausrollen."
|
|
exit 1
|
|
fi
|
|
|
|
if ls public/data/*.csv >/dev/null 2>&1; then
|
|
mkdir -p "$BACKUP_DIR/public-data"
|
|
cp -a public/data/*.csv "$BACKUP_DIR/public-data/"
|
|
echo " Backed up public/data/*.csv -> $BACKUP_DIR/public-data/"
|
|
else
|
|
echo " No public CSVs to backup (public/data/*.csv not found)"
|
|
fi
|
|
|
|
# 2. Handle local changes and Git Pull
|
|
echo "2. Handling local changes and pulling latest from git..."
|
|
|
|
# Check if there are merge conflicts first
|
|
if [ -n "$(git status --porcelain | grep '^UU\|^AA\|^DD')" ]; then
|
|
echo " Resolving existing merge conflicts..."
|
|
git reset --hard HEAD
|
|
fi
|
|
|
|
# Ensure git operations can run even if we have untracked local artifacts (e.g. backups/)
|
|
# We avoid `git stash` (breaks with symlinked tracked paths). Instead, hard-reset and clean safely.
|
|
echo " Resetting working tree to HEAD (production data will be restored from backup)..."
|
|
git reset --hard HEAD
|
|
|
|
echo " Cleaning untracked files (excluding data dirs/backups/.env)..."
|
|
git clean -fd \
|
|
-e server/data \
|
|
-e public/data \
|
|
-e public/uploads \
|
|
-e backups \
|
|
-e .env || true
|
|
|
|
# Pull latest changes
|
|
echo " Pulling latest changes..."
|
|
git pull
|
|
|
|
# Reset any accidental changes from stash restore (should be none now)
|
|
git reset --hard HEAD >/dev/null 2>&1
|
|
|
|
# 3. Install dependencies
|
|
echo ""
|
|
echo "3. Installing dependencies..."
|
|
npm install
|
|
|
|
# 4. Remove old build (but keep data!)
|
|
echo ""
|
|
echo "4. Cleaning build artifacts..."
|
|
# Sicherstellen, dass .output vollständig gelöscht wird
|
|
if [ -d ".output" ]; then
|
|
echo " Removing .output directory..."
|
|
rm -rf .output
|
|
# Prüfen, ob wirklich gelöscht wurde
|
|
if [ -d ".output" ]; then
|
|
echo "WARNING: .output konnte nicht vollständig gelöscht werden. Versuche erneut..."
|
|
sleep 2
|
|
rm -rf .output
|
|
if [ -d ".output" ]; then
|
|
echo "ERROR: .output konnte auch nach erneutem Versuch nicht gelöscht werden!"
|
|
echo "Bitte manuell prüfen und löschen: rm -rf .output"
|
|
exit 1
|
|
fi
|
|
fi
|
|
echo " ✓ .output gelöscht"
|
|
fi
|
|
|
|
# Auch .nuxt Cache löschen für sauberen Build
|
|
if [ -d ".nuxt" ]; then
|
|
echo " Removing .nuxt cache..."
|
|
rm -rf .nuxt
|
|
echo " ✓ .nuxt gelöscht"
|
|
fi
|
|
|
|
# Prüfe, ob node_modules vorhanden ist (für npm run build)
|
|
if [ ! -d "node_modules" ]; then
|
|
echo ""
|
|
echo "WARNING: node_modules fehlt. Installiere Dependencies..."
|
|
npm install
|
|
fi
|
|
|
|
# 5. Build
|
|
echo ""
|
|
echo "5. Building application..."
|
|
echo " Running: npm run build"
|
|
echo " (This may take a few minutes...)"
|
|
|
|
# Clean-Build: Stelle sicher, dass node_modules aktuell ist
|
|
echo " Checking dependencies..."
|
|
if [ ! -f "node_modules/.package-lock.json" ] && [ ! -f "package-lock.json" ]; then
|
|
echo " WARNING: package-lock.json fehlt. Führe npm install aus..."
|
|
npm install
|
|
fi
|
|
|
|
# Build mit expliziter Fehlerbehandlung und Output-Capture
|
|
BUILD_OUTPUT=$(npm run build 2>&1)
|
|
BUILD_EXIT_CODE=$?
|
|
|
|
# Zeige Build-Output
|
|
echo "$BUILD_OUTPUT"
|
|
|
|
if [ "$BUILD_EXIT_CODE" -ne 0 ]; then
|
|
echo ""
|
|
echo "ERROR: Build fehlgeschlagen mit Exit-Code $BUILD_EXIT_CODE"
|
|
echo "Bitte prüfen Sie die Build-Ausgabe oben auf Fehler."
|
|
exit 1
|
|
fi
|
|
|
|
# Prüfe auf Warnungen im Build-Output, die auf Probleme hinweisen
|
|
if echo "$BUILD_OUTPUT" | grep -qi "error\|failed\|missing"; then
|
|
echo ""
|
|
echo "WARNING: Build-Output enthält möglicherweise Fehler oder Warnungen."
|
|
echo "Bitte prüfen Sie die Ausgabe oben."
|
|
fi
|
|
|
|
# Prüfe, ob der Build erfolgreich war - mehrere Checks
|
|
echo ""
|
|
echo " Verifying build output..."
|
|
|
|
BUILD_FAILED=0
|
|
|
|
# Check 1: _nuxt Verzeichnis
|
|
if [ ! -d ".output/public/_nuxt" ]; then
|
|
echo "ERROR: .output/public/_nuxt Verzeichnis fehlt!"
|
|
BUILD_FAILED=1
|
|
else
|
|
NUXT_FILES=$(find .output/public/_nuxt -type f 2>/dev/null | wc -l)
|
|
echo " ✓ .output/public/_nuxt vorhanden ($NUXT_FILES Dateien)"
|
|
if [ "$NUXT_FILES" -eq 0 ]; then
|
|
echo "ERROR: .output/public/_nuxt ist leer!"
|
|
BUILD_FAILED=1
|
|
else
|
|
# Prüfe, ob wichtige Dateien vorhanden sind
|
|
JS_FILES=$(find .output/public/_nuxt -name "*.js" 2>/dev/null | wc -l)
|
|
CSS_FILES=$(find .output/public/_nuxt -name "*.css" 2>/dev/null | wc -l)
|
|
echo " ✓ JS-Dateien: $JS_FILES, CSS-Dateien: $CSS_FILES"
|
|
if [ "$JS_FILES" -eq 0 ]; then
|
|
echo "ERROR: Keine JS-Dateien in .output/public/_nuxt gefunden!"
|
|
BUILD_FAILED=1
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Check 1b: _nuxt/builds Verzeichnis (für Meta-Dateien)
|
|
if [ -d ".output/public/_nuxt/builds" ]; then
|
|
BUILD_META_FILES=$(find .output/public/_nuxt/builds -type f 2>/dev/null | wc -l)
|
|
echo " ✓ .output/public/_nuxt/builds vorhanden ($BUILD_META_FILES Meta-Dateien)"
|
|
else
|
|
echo "WARNING: .output/public/_nuxt/builds fehlt (kann in manchen Nuxt-Versionen normal sein)"
|
|
fi
|
|
|
|
# Check 2: Server index.mjs
|
|
if [ ! -f ".output/server/index.mjs" ]; then
|
|
echo "ERROR: .output/server/index.mjs fehlt!"
|
|
BUILD_FAILED=1
|
|
else
|
|
echo " ✓ .output/server/index.mjs vorhanden"
|
|
fi
|
|
|
|
# Check 3: Public Verzeichnis
|
|
if [ ! -d ".output/public" ]; then
|
|
echo "ERROR: .output/public Verzeichnis fehlt!"
|
|
BUILD_FAILED=1
|
|
else
|
|
echo " ✓ .output/public vorhanden"
|
|
fi
|
|
|
|
# Check 4: Server Verzeichnis
|
|
if [ ! -d ".output/server" ]; then
|
|
echo "ERROR: .output/server Verzeichnis fehlt!"
|
|
BUILD_FAILED=1
|
|
else
|
|
echo " ✓ .output/server vorhanden"
|
|
fi
|
|
|
|
if [ "$BUILD_FAILED" -eq 1 ]; then
|
|
echo ""
|
|
echo "ERROR: Build-Verifikation fehlgeschlagen!"
|
|
echo "Bitte führen Sie manuell aus:"
|
|
echo " rm -rf .output .nuxt"
|
|
echo " npm run build"
|
|
exit 1
|
|
fi
|
|
|
|
echo " ✓ Build erfolgreich verifiziert"
|
|
|
|
# 6. Restore Production Data (überschreibe Repo-Defaults mit Backup)
|
|
echo ""
|
|
echo "6. Restoring production data..."
|
|
|
|
# Stelle server/data vollständig wieder her (inkl. config.json, users.json, news.json, sessions.json, members.json, membership-applications)
|
|
if [ ! -d "$BACKUP_DIR/server-data" ]; then
|
|
echo "ERROR: Backup-Verzeichnis $BACKUP_DIR/server-data fehlt. Abbruch."
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p server/data
|
|
cp -a "$BACKUP_DIR/server-data/." server/data/
|
|
echo " Restored server/data from backup ($BACKUP_DIR/server-data)."
|
|
|
|
# Stelle alle CSVs wieder her
|
|
if ls "$BACKUP_DIR/public-data"/*.csv >/dev/null 2>&1; then
|
|
mkdir -p public/data
|
|
cp -a "$BACKUP_DIR/public-data"/*.csv public/data/
|
|
echo " Restored public/data/*.csv from backup ($BACKUP_DIR/public-data)."
|
|
else
|
|
echo "No public CSVs to restore"
|
|
fi
|
|
|
|
# Sanity Check: users.json muss existieren und darf nicht leer sein
|
|
if [ ! -s server/data/users.json ]; then
|
|
echo "ERROR: server/data/users.json fehlt oder ist leer nach Restore. Abbruch."
|
|
exit 1
|
|
fi
|
|
|
|
# 7. Cleanup (Backups werden bewusst behalten)
|
|
echo ""
|
|
echo "7. Keeping backups in $BACKUP_ROOT (no git stash used)."
|
|
|
|
# 8. Restart PM2
|
|
echo ""
|
|
echo "8. Restarting PM2..."
|
|
|
|
# Prüfe, ob PM2 installiert ist
|
|
if ! command -v pm2 &> /dev/null; then
|
|
echo "ERROR: PM2 ist nicht installiert oder nicht im PATH!"
|
|
echo "Bitte installieren Sie PM2: npm install -g pm2"
|
|
exit 1
|
|
fi
|
|
|
|
# Prüfe, ob der Prozess existiert
|
|
if ! pm2 describe harheimertc &> /dev/null; then
|
|
echo "WARNING: PM2-Prozess 'harheimertc' existiert nicht."
|
|
echo "Versuche, den Prozess zu starten..."
|
|
pm2 start harheimertc.config.cjs --update-env || pm2 start harheimertc.simple.cjs --update-env || {
|
|
echo "ERROR: Konnte PM2-Prozess nicht starten."
|
|
echo "Bitte manuell starten: pm2 start harheimertc.config.cjs"
|
|
exit 1
|
|
}
|
|
echo " ✓ PM2-Prozess gestartet"
|
|
else
|
|
# Restart mit --update-env, um Umgebungsvariablen zu aktualisieren
|
|
echo " Restarting harheimertc with --update-env..."
|
|
if pm2 restart harheimertc --update-env; then
|
|
echo " ✓ PM2-Prozess neu gestartet"
|
|
else
|
|
echo "ERROR: PM2-Restart fehlgeschlagen!"
|
|
echo "Bitte manuell prüfen: pm2 logs harheimertc"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Prüfe, ob der Prozess läuft
|
|
sleep 2
|
|
if pm2 describe harheimertc | grep -q "online"; then
|
|
echo " ✓ PM2-Prozess läuft (online)"
|
|
else
|
|
echo "WARNING: PM2-Prozess ist nicht online. Prüfe Logs: pm2 logs harheimertc"
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== Deployment completed successfully! ==="
|
|
echo "The application is now running with the latest code and your production data preserved."
|
|
echo ""
|
|
echo "Useful commands:"
|
|
echo " pm2 logs harheimertc # View logs"
|
|
echo " pm2 status # View status"
|
|
echo " pm2 restart harheimertc # Restart manually"
|
|
|