#!/bin/bash # # Migration Script: .env → .env.base + .env.local # # This script helps migrate from the legacy single .env file # to the new Base+Override Pattern (.env.base + .env.local) # # Usage: # ./scripts/migrate-env-to-base-override.sh # set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" cd "$PROJECT_ROOT" echo "🔄 Migration: .env → .env.base + .env.local" echo "" # Check if .env exists if [ ! -f .env ]; then echo "❌ .env Datei nicht gefunden" echo "💡 Erstelle zuerst .env aus .env.example" exit 1 fi # Backup existing .env BACKUP_FILE=".env.backup.$(date +%Y%m%d-%H%M%S)" echo "📦 Backup erstellen: $BACKUP_FILE" cp .env "$BACKUP_FILE" echo "✅ Backup erstellt" # Check if .env.base exists if [ -f .env.base ]; then echo "" echo "⚠️ .env.base existiert bereits" echo "💡 .env.base wird als Basis verwendet" USE_EXISTING_BASE=true else USE_EXISTING_BASE=false fi # Check if .env.local exists if [ -f .env.local ]; then echo "" echo "⚠️ .env.local existiert bereits" read -p "Überschreiben? (j/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Jj]$ ]]; then echo "❌ Abgebrochen" exit 1 fi BACKUP_LOCAL=".env.local.backup.$(date +%Y%m%d-%H%M%S)" cp .env.local "$BACKUP_LOCAL" echo "📦 Backup von .env.local erstellt: $BACKUP_LOCAL" fi echo "" echo "📝 Analysiere .env Datei..." # Common variables that should go to .env.base # (These are typically environment-agnostic) BASE_VARS=( "APP_NAME" "APP_TIMEZONE" "APP_LOCALE" "DB_DRIVER" "DB_PORT" "DB_CHARSET" "REDIS_PORT" "CACHE_DRIVER" "SESSION_DRIVER" "SESSION_LIFETIME" "QUEUE_DRIVER" "QUEUE_CONNECTION" "QUEUE_WORKER_SLEEP" "QUEUE_WORKER_TRIES" "QUEUE_WORKER_TIMEOUT" "SECURITY_RATE_LIMIT_PER_MINUTE" "SECURITY_RATE_LIMIT_BURST" "CACHE_PREFIX" ) # Local-specific variables (development overrides) LOCAL_VARS=( "APP_ENV" "APP_DEBUG" "APP_URL" "APP_KEY" "APP_DOMAIN" "DB_HOST" "DB_DATABASE" "DB_USERNAME" "DB_PASSWORD" "REDIS_HOST" "REDIS_PASSWORD" "SECURITY_ALLOWED_HOSTS" "FORCE_HTTPS" "XDEBUG_MODE" "PHP_IDE_CONFIG" ) # Variables that should NOT be in .env.base (secrets) SECRET_PATTERNS=( "PASSWORD" "SECRET" "KEY" "TOKEN" "ENCRYPTION" "VAULT" ) echo "" echo "📋 Trenne Variablen in Base und Local..." # Create temporary files TMP_BASE=$(mktemp) TMP_LOCAL=$(mktemp) # Read .env line by line while IFS= read -r line || [ -n "$line" ]; do # Skip empty lines and comments if [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]]; then echo "$line" >> "$TMP_BASE" echo "$line" >> "$TMP_LOCAL" continue fi # Extract variable name if [[ "$line" =~ ^([A-Za-z_][A-Za-z0-9_]*)= ]]; then VAR_NAME="${BASH_REMATCH[1]}" # Check if it's a secret IS_SECRET=false for pattern in "${SECRET_PATTERNS[@]}"; do if [[ "$VAR_NAME" == *"$pattern"* ]]; then IS_SECRET=true break fi done if [ "$IS_SECRET" = true ]; then # Secrets go to .env.local (or should be in Docker Secrets) echo "# TODO: Möglicherweise in Docker Secrets verschieben" >> "$TMP_LOCAL" echo "$line" >> "$TMP_LOCAL" continue fi # Check if it's a base variable IS_BASE=false for base_var in "${BASE_VARS[@]}"; do if [[ "$VAR_NAME" == "$base_var" ]]; then IS_BASE=true break fi done # Check if it's a local variable IS_LOCAL=false for local_var in "${LOCAL_VARS[@]}"; do if [[ "$VAR_NAME" == "$local_var" ]]; then IS_LOCAL=true break fi done if [ "$IS_BASE" = true ]; then # Go to .env.base echo "$line" >> "$TMP_BASE" elif [ "$IS_LOCAL" = true ]; then # Go to .env.local echo "$line" >> "$TMP_LOCAL" else # Unknown: Ask or put in local as default echo "# TODO: Prüfen ob Base oder Local" >> "$TMP_LOCAL" echo "$line" >> "$TMP_LOCAL" fi else # Non-standard line format: keep in both (shouldn't happen) echo "$line" >> "$TMP_BASE" echo "$line" >> "$TMP_LOCAL" fi done < .env # Create .env.base if it doesn't exist if [ "$USE_EXISTING_BASE" = false ]; then echo "" echo "📝 Erstelle .env.base..." cat > .env.base << 'EOF' # Base Environment Configuration # This file contains shared environment variables for all environments. # Use with environment-specific override files: # - .env.local (local development overrides) # - .env.staging (staging-specific overrides, optional) # - .env.production (production - generated by Ansible) # # Framework automatically loads: .env.base → .env.local (if exists) # See ENV_SETUP.md for details # EOF cat "$TMP_BASE" >> .env.base echo "✅ .env.base erstellt" else echo "" echo "ℹ️ .env.base existiert bereits, wird nicht überschrieben" fi # Create .env.local echo "" echo "📝 Erstelle .env.local..." cat > .env.local << 'EOF' # Local Development Environment Overrides # This file overrides .env.base with local development-specific settings. # This file is gitignored - each developer has their own version. # # Framework loads: .env.base → .env.local (this file) → System ENV vars # See ENV_SETUP.md for details # EOF cat "$TMP_LOCAL" >> .env.local echo "✅ .env.local erstellt" # Cleanup rm -f "$TMP_BASE" "$TMP_LOCAL" echo "" echo "✅ Migration abgeschlossen!" echo "" echo "📋 Nächste Schritte:" echo " 1. Prüfe .env.base - entferne Secrets falls vorhanden" echo " 2. Prüfe .env.local - passe lokale Overrides an" echo " 3. Teste die Anwendung: make up" echo " 4. Optional: .env kann später entfernt werden (wird als Fallback geladen)" echo "" echo "📝 Backup-Dateien:" echo " - $BACKUP_FILE" if [ -n "$BACKUP_LOCAL" ]; then echo " - $BACKUP_LOCAL" fi echo "" echo "💡 Siehe ENV_SETUP.md für Details zur neuen Struktur"