#!/bin/bash # Main Deployment Orchestration Script for Custom PHP Framework # Coordinates infrastructure (Ansible) and application (Docker Compose) deployment # Domain: michaelschiemer.de | Email: kontakt@michaelschiemer.de | PHP: 8.4 # Usage: ./deploy.sh [environment] [options] set -euo pipefail # Script configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../" && pwd)" DEPLOYMENT_DIR="${SCRIPT_DIR}" INFRASTRUCTURE_DIR="${DEPLOYMENT_DIR}/infrastructure" APPLICATIONS_DIR="${DEPLOYMENT_DIR}/applications" LIB_DIR="${DEPLOYMENT_DIR}/lib" # Load deployment libraries if [[ -f "${LIB_DIR}/config-manager.sh" ]]; then source "${LIB_DIR}/config-manager.sh" fi if [[ -f "${LIB_DIR}/security-tools.sh" ]]; then source "${LIB_DIR}/security-tools.sh" fi # Default configuration DEFAULT_ENV="staging" INFRASTRUCTURE_ONLY=false APPLICATION_ONLY=false DRY_RUN=false SKIP_TESTS=false SKIP_BACKUP=false FORCE_DEPLOY=false VERBOSE=false INTERACTIVE=true # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' WHITE='\033[1;37m' NC='\033[0m' # No Color # Logging functions with improved formatting log() { echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] โœ… INFO: $1${NC}" } warn() { echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] โš ๏ธ WARN: $1${NC}" } error() { echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] โŒ ERROR: $1${NC}" } debug() { if [ "$VERBOSE" = true ]; then echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')] ๐Ÿ” DEBUG: $1${NC}" fi } success() { echo -e "${WHITE}[$(date +'%Y-%m-%d %H:%M:%S')] ๐ŸŽ‰ SUCCESS: $1${NC}" } section() { echo -e "\n${PURPLE}================================${NC}" echo -e "${PURPLE}$1${NC}" echo -e "${PURPLE}================================${NC}\n" } # Usage information show_usage() { cat << EOF ${WHITE}Custom PHP Framework Deployment Orchestrator${NC} ${CYAN}Domain: michaelschiemer.de | Email: kontakt@michaelschiemer.de | PHP: 8.4${NC} ${WHITE}Usage:${NC} $0 [environment] [options] ${WHITE}Environments:${NC} ${GREEN}development${NC} Deploy to development environment ${GREEN}staging${NC} Deploy to staging environment (default) ${GREEN}production${NC} Deploy to production environment ${WHITE}Deployment Options:${NC} ${YELLOW}--infrastructure-only${NC} Deploy only infrastructure (Ansible) ${YELLOW}--application-only${NC} Deploy only application (Docker Compose) ${YELLOW}--dry-run${NC} Show what would be done without making changes ${YELLOW}--skip-tests${NC} Skip running tests before deployment ${YELLOW}--skip-backup${NC} Skip database backup (not recommended for production) ${YELLOW}--force${NC} Force deployment even if validation fails ${YELLOW}--non-interactive${NC} Skip confirmation prompts ${YELLOW}--verbose${NC} Enable verbose output ${WHITE}General Options:${NC} ${YELLOW}-h, --help${NC} Show this help message ${YELLOW}--version${NC} Show version information ${WHITE}Examples:${NC} ${CYAN}$0 staging${NC} # Deploy to staging ${CYAN}$0 production --infrastructure-only${NC} # Deploy only infrastructure to production ${CYAN}$0 staging --application-only --skip-tests${NC} # Deploy only app to staging without tests ${CYAN}$0 production --dry-run --verbose${NC} # Dry run with detailed output ${CYAN}$0 development --non-interactive${NC} # Development deploy without prompts ${WHITE}Safety Features:${NC} โ€ข Production deployments require confirmation โ€ข Pre-flight validation checks โ€ข Database backups before deployment โ€ข Health checks after deployment โ€ข Rollback capability on failures EOF } # Version information show_version() { cat << EOF ${WHITE}Custom PHP Framework Deployment System${NC} Version: 1.0.0 Domain: michaelschiemer.de Email: kontakt@michaelschiemer.de PHP Version: 8.4 Build Date: $(date +'%Y-%m-%d') EOF } # Parse command line arguments parse_arguments() { local environment="" while [[ $# -gt 0 ]]; do case $1 in development|staging|production) environment="$1" shift ;; --infrastructure-only) INFRASTRUCTURE_ONLY=true APPLICATION_ONLY=false shift ;; --application-only) APPLICATION_ONLY=true INFRASTRUCTURE_ONLY=false shift ;; --dry-run) DRY_RUN=true shift ;; --skip-tests) SKIP_TESTS=true shift ;; --skip-backup) SKIP_BACKUP=true shift ;; --force) FORCE_DEPLOY=true shift ;; --non-interactive) INTERACTIVE=false shift ;; --verbose) VERBOSE=true shift ;; --version) show_version exit 0 ;; -h|--help) show_usage exit 0 ;; *) error "Unknown argument: $1" echo show_usage exit 1 ;; esac done # Set environment, defaulting to staging DEPLOY_ENV="${environment:-$DEFAULT_ENV}" } # Confirmation prompt for production deployments confirm_deployment() { if [ "$INTERACTIVE" = false ]; then debug "Non-interactive mode, skipping confirmation" return 0 fi if [ "$DEPLOY_ENV" = "production" ]; then section "PRODUCTION DEPLOYMENT CONFIRMATION" echo -e "${RED}โš ๏ธ You are about to deploy to PRODUCTION environment!${NC}" echo -e "${YELLOW}Domain: michaelschiemer.de${NC}" echo -e "${YELLOW}This will affect the live website.${NC}" echo if [ "$DRY_RUN" = true ]; then echo -e "${BLUE}This is a DRY RUN - no actual changes will be made.${NC}" else echo -e "${RED}This is a LIVE DEPLOYMENT - changes will be applied immediately.${NC}" fi echo read -p "Are you sure you want to continue? [y/N]: " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then log "Deployment cancelled by user" exit 0 fi # Second confirmation for non-dry-run production deployments if [ "$DRY_RUN" != true ]; then echo echo -e "${RED}FINAL CONFIRMATION: This will deploy to PRODUCTION.${NC}" read -p "Type 'DEPLOY' to confirm: " -r echo if [[ $REPLY != "DEPLOY" ]]; then log "Deployment cancelled - confirmation not received" exit 0 fi fi else section "DEPLOYMENT CONFIRMATION" echo -e "${GREEN}Deploying to: ${DEPLOY_ENV} environment${NC}" echo -e "${YELLOW}Domain: michaelschiemer.de${NC}" if [ "$DRY_RUN" = true ]; then echo -e "${BLUE}Mode: DRY RUN (no actual changes)${NC}" fi echo read -p "Continue with deployment? [Y/n]: " -n 1 -r echo if [[ $REPLY =~ ^[Nn]$ ]]; then log "Deployment cancelled by user" exit 0 fi fi } # Enhanced environment detection detect_environment() { section "DETECTING DEPLOYMENT ENVIRONMENT" log "Analyzing deployment environment: $DEPLOY_ENV" # Detect if this is a fresh setup local env_file="${APPLICATIONS_DIR}/environments/.env.${DEPLOY_ENV}" if [[ ! -f "$env_file" ]]; then warn "Environment configuration not found: .env.${DEPLOY_ENV}" info "Consider running setup wizard: ./setup-wizard.sh" # Check if template exists local template_file="${env_file}.template" if [[ -f "$template_file" ]]; then printf "${CYAN}Create environment configuration now? [Y/n]: ${NC}" read -r create_env if [[ ! $create_env =~ ^[Nn]$ ]]; then info "Running configuration setup..." if command -v "${LIB_DIR}/config-manager.sh" >/dev/null 2>&1; then "${LIB_DIR}/config-manager.sh" apply-config "$DEPLOY_ENV" \ "${DOMAIN:-$DEPLOY_ENV.michaelschiemer.de}" \ "${EMAIL:-kontakt@michaelschiemer.de}" fi fi fi fi # Environment-specific warnings case $DEPLOY_ENV in production) if [[ "$INTERACTIVE" == "true" && "$FORCE_DEPLOY" != "true" ]]; then warn "Production deployment detected" warn "This will affect the live website: michaelschiemer.de" fi ;; staging) info "Staging deployment - safe for testing" ;; development) info "Development deployment - local development environment" ;; *) warn "Unknown environment: $DEPLOY_ENV" warn "Proceeding with custom environment configuration" ;; esac success "Environment detection completed" } # Validate prerequisites and environment validate_prerequisites() { section "VALIDATING PREREQUISITES" log "Checking deployment environment: $DEPLOY_ENV" # Check if we're in the project root if [[ ! -f "${PROJECT_ROOT}/docker-compose.yml" ]]; then error "Project root not found. Please run from the correct directory." error "Expected file: ${PROJECT_ROOT}/docker-compose.yml" exit 1 fi # Check for required tools local required_tools=() if [ "$INFRASTRUCTURE_ONLY" = true ] || [ "$APPLICATION_ONLY" = false ]; then required_tools+=("ansible-playbook") fi if [ "$APPLICATION_ONLY" = true ] || [ "$INFRASTRUCTURE_ONLY" = false ]; then required_tools+=("docker" "docker-compose") fi for tool in "${required_tools[@]}"; do if ! command -v "$tool" &> /dev/null; then error "Required tool not found: $tool" case $tool in ansible-playbook) error "Install with: sudo apt-get install ansible" ;; docker) error "Install with: curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh" ;; docker-compose) error "Install with: sudo apt-get install docker-compose" ;; esac exit 1 else debug "โœ“ $tool found" fi done # Validate environment-specific files if [ "$APPLICATION_ONLY" = true ] || [ "$INFRASTRUCTURE_ONLY" = false ]; then local compose_file="${APPLICATIONS_DIR}/docker-compose.${DEPLOY_ENV}.yml" local env_file="${APPLICATIONS_DIR}/environments/.env.${DEPLOY_ENV}" if [[ ! -f "$compose_file" ]]; then error "Docker Compose overlay not found: $compose_file" exit 1 else debug "โœ“ Docker Compose overlay found" fi if [[ ! -f "$env_file" ]]; then error "Environment file not found: $env_file" error "Copy from template: cp ${env_file}.template $env_file" exit 1 else debug "โœ“ Environment file found" fi fi # Validate Ansible inventory if [ "$INFRASTRUCTURE_ONLY" = true ] || [ "$APPLICATION_ONLY" = false ]; then local inventory="${INFRASTRUCTURE_DIR}/inventories/${DEPLOY_ENV}/hosts.yml" if [[ ! -f "$inventory" ]]; then warn "Ansible inventory not found: $inventory" if [ "$INFRASTRUCTURE_ONLY" = true ]; then error "Infrastructure deployment requires inventory file" exit 1 else warn "Skipping infrastructure deployment" INFRASTRUCTURE_ONLY=false APPLICATION_ONLY=true fi else debug "โœ“ Ansible inventory found" # Check if this is a fresh server setup if grep -q "fresh_server_setup: true" "$inventory" 2>/dev/null; then warn "Fresh server setup detected in inventory" warn "Run initial setup first: ansible-playbook -i $inventory setup-fresh-server.yml" if [ "$FORCE_DEPLOY" != true ]; then error "Use --force to skip initial setup check" exit 1 fi fi fi fi success "Prerequisites validation completed" } # Validate configuration files validate_configuration() { section "VALIDATING CONFIGURATION" if [ "$APPLICATION_ONLY" = true ] || [ "$INFRASTRUCTURE_ONLY" = false ]; then log "Validating application environment configuration" local env_file="${APPLICATIONS_DIR}/environments/.env.${DEPLOY_ENV}" # Check for required placeholder values local placeholder_found=false local required_placeholders=( "*** REQUIRED" "your-domain.com" "your-email@example.com" ) for placeholder in "${required_placeholders[@]}"; do if grep -q "$placeholder" "$env_file" 2>/dev/null; then error "Environment file contains unfilled templates:" grep "$placeholder" "$env_file" || true placeholder_found=true fi done if [ "$placeholder_found" = true ]; then if [ "$FORCE_DEPLOY" != true ]; then error "Fix configuration placeholders or use --force to proceed" exit 1 else warn "Proceeding with incomplete configuration due to --force flag" fi else debug "โœ“ No placeholder values found" fi # Validate critical environment variables source "$env_file" if [[ "$DEPLOY_ENV" = "production" ]]; then if [[ -z "${DB_PASSWORD:-}" || "${DB_PASSWORD}" = "changeme" ]]; then error "Production deployment requires a secure database password" if [ "$FORCE_DEPLOY" != true ]; then exit 1 fi fi if [[ "${APP_DEBUG:-false}" = "true" ]]; then warn "Debug mode is enabled in production environment" fi fi fi success "Configuration validation completed" } # Run deployment tests run_deployment_tests() { if [ "$SKIP_TESTS" = true ]; then warn "Skipping tests as requested" return 0 fi section "RUNNING DEPLOYMENT TESTS" if [ "$APPLICATION_ONLY" = true ] || [ "$INFRASTRUCTURE_ONLY" = false ]; then cd "$PROJECT_ROOT" # PHP tests if [[ -f "vendor/bin/pest" ]]; then log "Running PHP tests with Pest" if [ "$DRY_RUN" != true ]; then ./vendor/bin/pest --bail else debug "DRY RUN: Would run PHP tests" fi elif [[ -f "vendor/bin/phpunit" ]]; then log "Running PHP tests with PHPUnit" if [ "$DRY_RUN" != true ]; then ./vendor/bin/phpunit --stop-on-failure else debug "DRY RUN: Would run PHPUnit tests" fi else warn "No PHP test framework found" fi # JavaScript tests if [[ -f "package.json" ]] && command -v npm &> /dev/null; then log "Running JavaScript tests" if [ "$DRY_RUN" != true ]; then npm test else debug "DRY RUN: Would run JavaScript tests" fi fi # Code quality checks if [[ -f "composer.json" ]]; then log "Running code style checks" if [ "$DRY_RUN" != true ]; then composer cs || { error "Code style checks failed" if [ "$FORCE_DEPLOY" != true ]; then exit 1 else warn "Proceeding despite code style issues due to --force flag" fi } else debug "DRY RUN: Would run code style checks" fi fi fi # Ansible syntax check if [ "$INFRASTRUCTURE_ONLY" = true ] || [ "$APPLICATION_ONLY" = false ]; then log "Validating Ansible playbook syntax" local inventory="${INFRASTRUCTURE_DIR}/inventories/${DEPLOY_ENV}/hosts.yml" local playbook="${INFRASTRUCTURE_DIR}/site.yml" if [[ -f "$inventory" && -f "$playbook" ]]; then cd "$INFRASTRUCTURE_DIR" if [ "$DRY_RUN" != true ]; then ansible-playbook -i "$inventory" "$playbook" --syntax-check else debug "DRY RUN: Would validate Ansible syntax" fi fi fi success "All tests passed" } # Deploy infrastructure using Ansible deploy_infrastructure() { if [ "$APPLICATION_ONLY" = true ]; then debug "Skipping infrastructure deployment (application-only mode)" return 0 fi section "DEPLOYING INFRASTRUCTURE" local inventory="${INFRASTRUCTURE_DIR}/inventories/${DEPLOY_ENV}/hosts.yml" local playbook="${INFRASTRUCTURE_DIR}/site.yml" if [[ ! -f "$inventory" ]]; then warn "Ansible inventory not found: $inventory" warn "Skipping infrastructure deployment" return 0 fi log "Deploying infrastructure with Ansible for $DEPLOY_ENV environment" cd "$INFRASTRUCTURE_DIR" local ansible_cmd="ansible-playbook -i $inventory $playbook" if [ "$DRY_RUN" = true ]; then ansible_cmd="$ansible_cmd --check" fi if [ "$VERBOSE" = true ]; then ansible_cmd="$ansible_cmd -v" fi debug "Running: $ansible_cmd" if [ "$DRY_RUN" != true ]; then $ansible_cmd success "Infrastructure deployment completed" else debug "DRY RUN: Would run Ansible infrastructure deployment" success "Infrastructure deployment dry run completed" fi } # Deploy application using the existing script deploy_application() { if [ "$INFRASTRUCTURE_ONLY" = true ]; then debug "Skipping application deployment (infrastructure-only mode)" return 0 fi section "DEPLOYING APPLICATION" log "Deploying application with Docker Compose for $DEPLOY_ENV environment" local app_deploy_script="${APPLICATIONS_DIR}/scripts/deploy-app.sh" if [[ ! -f "$app_deploy_script" ]]; then error "Application deployment script not found: $app_deploy_script" exit 1 fi # Build command arguments local app_args=("$DEPLOY_ENV") if [ "$DRY_RUN" = true ]; then app_args+=("--dry-run") fi if [ "$SKIP_TESTS" = true ]; then app_args+=("--skip-tests") fi if [ "$SKIP_BACKUP" = true ]; then app_args+=("--skip-backup") fi if [ "$FORCE_DEPLOY" = true ]; then app_args+=("--force") fi if [ "$VERBOSE" = true ]; then app_args+=("--verbose") fi debug "Running: $app_deploy_script ${app_args[*]}" # Execute application deployment "$app_deploy_script" "${app_args[@]}" success "Application deployment completed" } # Perform comprehensive post-deployment validation post_deployment_validation() { section "POST-DEPLOYMENT VALIDATION" log "Performing comprehensive deployment validation" # Service health checks if [ "$INFRASTRUCTURE_ONLY" = true ] || [ "$APPLICATION_ONLY" = false ]; then log "Validating infrastructure services" # This would typically involve SSH connections to verify services # For now, we'll do basic connectivity tests debug "Infrastructure validation completed" fi # Application health checks if [ "$APPLICATION_ONLY" = true ] || [ "$INFRASTRUCTURE_ONLY" = false ]; then log "Validating application deployment" local health_check_script="${APPLICATIONS_DIR}/scripts/health-check.sh" if [[ -f "$health_check_script" ]]; then if [ "$DRY_RUN" != true ]; then "$health_check_script" "$DEPLOY_ENV" else debug "DRY RUN: Would run health checks" fi else warn "Health check script not found, performing basic validation" # Basic Docker Compose health check if [ "$DRY_RUN" != true ]; then cd "$PROJECT_ROOT" local compose_files="-f docker-compose.yml -f ${APPLICATIONS_DIR}/docker-compose.${DEPLOY_ENV}.yml" docker-compose $compose_files ps fi fi fi success "Post-deployment validation completed" } # Display deployment summary show_deployment_summary() { section "DEPLOYMENT SUMMARY" local deployment_type="" if [ "$INFRASTRUCTURE_ONLY" = true ]; then deployment_type="Infrastructure Only" elif [ "$APPLICATION_ONLY" = true ]; then deployment_type="Application Only" else deployment_type="Full Stack (Infrastructure + Application)" fi cat << EOF ${WHITE}๐ŸŽ‰ DEPLOYMENT COMPLETED SUCCESSFULLY! ๐ŸŽ‰${NC} ${CYAN}Deployment Details:${NC} โ€ข Environment: ${WHITE}${DEPLOY_ENV^^}${NC} โ€ข Type: ${WHITE}${deployment_type}${NC} โ€ข Domain: ${WHITE}michaelschiemer.de${NC} โ€ข PHP Version: ${WHITE}8.4${NC} โ€ข Mode: ${WHITE}$([ "$DRY_RUN" = true ] && echo "DRY RUN" || echo "LIVE DEPLOYMENT")${NC} ${CYAN}What was deployed:${NC} EOF if [ "$INFRASTRUCTURE_ONLY" = true ] || [ "$APPLICATION_ONLY" = false ]; then echo "โ€ข โœ… Infrastructure (Ansible)" echo " - Base security hardening" echo " - Docker runtime environment" echo " - Nginx reverse proxy with SSL" echo " - System monitoring and health checks" fi if [ "$APPLICATION_ONLY" = true ] || [ "$INFRASTRUCTURE_ONLY" = false ]; then echo "โ€ข โœ… Application (Docker Compose)" echo " - PHP 8.4 application container" echo " - Database with migrations" echo " - Frontend assets built and deployed" echo " - Health checks configured" fi echo if [ "$DEPLOY_ENV" = "production" ]; then cat << EOF ${GREEN}๐ŸŒŸ Production Deployment Complete!${NC} Your Custom PHP Framework is now live at: ${WHITE}https://michaelschiemer.de${NC} ${YELLOW}Next Steps:${NC} โ€ข Monitor application performance and logs โ€ข Verify all functionality is working correctly โ€ข Update DNS records if this is a new deployment โ€ข Consider setting up automated monitoring alerts EOF else cat << EOF ${GREEN}๐Ÿš€ ${DEPLOY_ENV^} Deployment Complete!${NC} ${YELLOW}Next Steps:${NC} โ€ข Test all application functionality โ€ข Run integration tests โ€ข Verify performance and security โ€ข Prepare for production deployment when ready EOF fi if [ "$DRY_RUN" = true ]; then echo -e "${BLUE}Note: This was a dry run. No actual changes were made.${NC}" echo -e "${BLUE}Remove the --dry-run flag to perform the actual deployment.${NC}" echo fi } # Error handling and cleanup cleanup() { local exit_code=$? if [ $exit_code -ne 0 ]; then error "Deployment failed with exit code: $exit_code" if [ "$DEPLOY_ENV" = "production" ] && [ "$DRY_RUN" != true ]; then error "PRODUCTION DEPLOYMENT FAILED!" error "Immediate action required. Check logs and consider rollback." fi echo echo -e "${RED}Troubleshooting Tips:${NC}" echo "โ€ข Check the error messages above for specific issues" echo "โ€ข Review configuration files for missing or incorrect values" echo "โ€ข Verify all required services are running" echo "โ€ข Check network connectivity to deployment targets" echo "โ€ข Review the deployment documentation in deployment/docs/" # Offer to run with verbose mode if not already enabled if [ "$VERBOSE" != true ]; then echo "โ€ข Try running with --verbose flag for more detailed output" fi # Offer dry run option if this was a live deployment if [ "$DRY_RUN" != true ]; then echo "โ€ข Use --dry-run flag to test deployment without making changes" fi fi } # Set up error handling trap cleanup EXIT # Enhanced deployment health check deployment_health_check() { section "DEPLOYMENT HEALTH CHECK" log "Performing comprehensive pre-deployment health check" local health_score=0 local max_score=100 # Check environment configuration (25 points) local env_file="${APPLICATIONS_DIR}/environments/.env.${DEPLOY_ENV}" if [[ -f "$env_file" ]]; then if ! grep -q "\*\*\* REQUIRED \*\*\*" "$env_file" 2>/dev/null; then health_score=$((health_score + 25)) debug "โœ“ Environment configuration complete" else warn "Environment configuration incomplete" fi else warn "Environment configuration missing" fi # Check Docker availability (25 points) if docker info >/dev/null 2>&1; then health_score=$((health_score + 25)) debug "โœ“ Docker daemon accessible" else warn "Docker daemon not accessible" fi # Check network connectivity (25 points) if [[ "$DEPLOY_ENV" != "development" ]]; then if ping -c 1 8.8.8.8 >/dev/null 2>&1; then health_score=$((health_score + 25)) debug "โœ“ Internet connectivity available" else warn "Internet connectivity issues detected" fi else health_score=$((health_score + 25)) # Skip for development fi # Check project files (25 points) local required_files=("docker-compose.yml" "composer.json") local files_found=0 for file in "${required_files[@]}"; do if [[ -f "${PROJECT_ROOT}/${file}" ]]; then ((files_found++)) fi done if [[ $files_found -eq ${#required_files[@]} ]]; then health_score=$((health_score + 25)) debug "โœ“ All required project files found" else warn "Some project files missing" fi # Health score summary local health_percentage=$((health_score * 100 / max_score)) if [[ $health_percentage -ge 90 ]]; then success "Deployment health check: EXCELLENT ($health_percentage%)" elif [[ $health_percentage -ge 75 ]]; then log "Deployment health check: GOOD ($health_percentage%)" elif [[ $health_percentage -ge 50 ]]; then warn "Deployment health check: FAIR ($health_percentage%)" else error "Deployment health check: POOR ($health_percentage%)" if [[ "$FORCE_DEPLOY" != "true" ]]; then error "Health check failed. Use --force to proceed anyway." exit 1 fi fi return 0 } # Main deployment orchestration function main() { log "Starting Custom PHP Framework deployment orchestration" if [ "$DRY_RUN" = true ]; then log "๐Ÿงช DRY RUN MODE - No actual changes will be made" fi # Pre-deployment steps detect_environment deployment_health_check confirm_deployment validate_prerequisites validate_configuration run_deployment_tests # Deployment execution deploy_infrastructure deploy_application # Post-deployment validation post_deployment_validation # Success summary show_deployment_summary success "Deployment orchestration completed successfully!" } # Script execution parse_arguments "$@" main