Files
harheimertc/deploy-production.sh
Torsten Schulz (local) 0deddeca51
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 49s
Enhance deployment script with PM2 process checks and error handling
Update deploy-production.sh to include checks for PM2 installation and process existence before restarting. Implement error messages for failed starts and restarts, improving robustness and user guidance during deployment. Additionally, add useful commands for managing the PM2 process post-deployment.
2026-01-08 11:24:38 +01:00

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 || pm2 start harheimertc.simple.cjs || {
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"