#!/bin/bash # Server-side Deployment Script für Custom PHP Framework # Läuft auf dem Production-Server (94.16.110.151) set -euo pipefail # Exit on any error DEPLOY_TAG="$1" DEPLOY_PATH="$2" BACKUP_PATH="${DEPLOY_PATH}-backup-$(date +%Y%m%d-%H%M%S)" TEMP_PATH="${DEPLOY_PATH}-deploying" # Farben GREEN="\e[32m" YELLOW="\e[33m" RED="\e[31m" BLUE="\e[34m" RESET="\e[0m" log() { echo -e "${BLUE}[SERVER $(date +'%H:%M:%S')]${RESET} $1" } success() { echo -e "${GREEN}✅ $1${RESET}" } error() { echo -e "${RED}❌ $1${RESET}" cleanup_on_error exit 1 } cleanup_on_error() { log "Cleanup nach Fehler..." [[ -d "$TEMP_PATH" ]] && rm -rf "$TEMP_PATH" [[ -d "$BACKUP_PATH" ]] && { log "Stelle vorherige Version wieder her..." [[ -d "$DEPLOY_PATH" ]] && rm -rf "$DEPLOY_PATH" mv "$BACKUP_PATH" "$DEPLOY_PATH" cd "$DEPLOY_PATH" && docker compose restart } } # Atomic Deployment mit Git atomic_git_deployment() { log "Starte atomic git deployment..." # 1. Backup der aktuellen Version erstellen if [[ -d "$DEPLOY_PATH" ]]; then log "Erstelle Backup der aktuellen Version..." cp -r "$DEPLOY_PATH" "$BACKUP_PATH" success "Backup erstellt: $BACKUP_PATH" fi # 2. Neue Version in temporäres Verzeichnis clonen log "Clone neue Version mit Tag: $DEPLOY_TAG" if [[ -d "$TEMP_PATH" ]]; then rm -rf "$TEMP_PATH" fi # Git Repository klonen oder pullen if [[ -d "$DEPLOY_PATH/.git" ]]; then # Existierendes Repository - fetch und checkout log "Update existierendes Repository..." cd "$DEPLOY_PATH" git fetch --tags origin git checkout "$DEPLOY_TAG" success "Git checkout zu $DEPLOY_TAG erfolgreich" else # Neues Repository klonen log "Klone Repository neu..." git clone --depth 1 --branch "$DEPLOY_TAG" "$(git -C . remote get-url origin)" "$TEMP_PATH" || { error "Git clone fehlgeschlagen" } # Atomic Switch: Temp → Live if [[ -d "$DEPLOY_PATH" ]]; then mv "$DEPLOY_PATH" "${DEPLOY_PATH}-old" fi mv "$TEMP_PATH" "$DEPLOY_PATH" fi } # Framework-spezifische Deployment-Schritte framework_deployment() { log "Führe Framework-Deployment durch..." cd "$DEPLOY_PATH" # 1. Environment Setup if [[ ! -f .env ]]; then if [[ -f .env.production ]]; then log "Kopiere .env.production zu .env" cp .env.production .env else error ".env.production nicht gefunden" fi fi # 2. Composer Dependencies (Production) log "Installiere Composer Dependencies..." if ! composer install --no-dev --optimize-autoloader --no-interaction; then error "Composer Install fehlgeschlagen" fi # 3. Framework Cache warming (falls implementiert) if [[ -f console.php ]] && php console.php list | grep -q "cache:warm"; then log "Wärme Framework Caches auf..." php console.php cache:warm || warning "Cache warming fehlgeschlagen" fi # 4. Database Migrations log "Führe Database Migrations durch..." if php console.php list | grep -q "db:migrate"; then php console.php db:migrate || error "Database Migration fehlgeschlagen" else warning "Keine Database Migrations gefunden" fi # 5. Framework optimizations if php console.php list | grep -q "framework:optimize"; then log "Optimiere Framework..." php console.php framework:optimize || warning "Framework Optimization fehlgeschlagen" fi success "Framework-Deployment abgeschlossen" } # Docker Services Management manage_docker_services() { log "Manage Docker Services..." cd "$DEPLOY_PATH" # Prüfe ob docker-compose.yml existiert if [[ ! -f docker-compose.yml ]]; then error "docker-compose.yml nicht gefunden" fi # Services neu starten mit minimaler Downtime log "Starte Services neu..." # Rolling Update Strategy docker compose pull --quiet || warning "Docker Pull Warnings (nicht kritisch)" # Restart mit Health Checks if docker compose up -d --force-recreate --remove-orphans; then success "Docker Services erfolgreich neu gestartet" else error "Docker Restart fehlgeschlagen" fi # Warte auf Service-Start log "Warte auf Service-Start..." sleep 10 } # Health Checks health_checks() { log "Führe Health Checks durch..." cd "$DEPLOY_PATH" # 1. Framework Health Check if php console.php health:check; then success "Framework Health Check OK" else error "Framework Health Check fehlgeschlagen" fi # 2. Docker Services Check if ! docker compose ps | grep -q "Up"; then error "Docker Services nicht verfügbar" fi success "Docker Services OK" # 3. MCP Server Test (optional) if timeout 5 php console.php mcp:server --test 2>/dev/null; then success "MCP Server OK" else log "MCP Server Test übersprungen (optional)" fi # 4. Web Response Test sleep 5 if curl -f -s -H "User-Agent: Mozilla/5.0 (Deployment Health Check)" "http://localhost" > /dev/null; then success "HTTP Response OK" else warning "HTTP Response Test fehlgeschlagen (möglicherweise nginx-Problem)" fi } # Cleanup alte Backups (behalte nur die letzten 5) cleanup_old_backups() { log "Räume alte Backups auf..." # Finde alle Backup-Ordner und behalte nur die 5 neuesten find "$(dirname "$DEPLOY_PATH")" -maxdepth 1 -name "*-backup-*" -type d | \ sort -r | \ tail -n +6 | \ xargs -r rm -rf success "Backup-Cleanup abgeschlossen" } # Deployment-Summary deployment_summary() { echo -e "${GREEN}" echo "🎉 Server-Deployment erfolgreich!" echo "📋 Tag: $DEPLOY_TAG" echo "📁 Path: $DEPLOY_PATH" echo "💾 Backup: $BACKUP_PATH" echo "⏰ Zeit: $(date)" echo -e "${RESET}" } # Hauptprogramm main() { log "🚀 Server-side Deployment gestartet" log "📦 Tag: $DEPLOY_TAG" log "📁 Path: $DEPLOY_PATH" atomic_git_deployment framework_deployment manage_docker_services health_checks cleanup_old_backups deployment_summary # Cleanup erfolgreicher Deployment [[ -d "${DEPLOY_PATH}-old" ]] && rm -rf "${DEPLOY_PATH}-old" } # Error Handling trap cleanup_on_error ERR # Script ausführen main "$@"