Files
michaelschiemer/deployment/deploy.sh
Michael Schiemer 9b74ade5b0 feat: Fix discovery system critical issues
Resolved multiple critical discovery system issues:

## Discovery System Fixes
- Fixed console commands not being discovered on first run
- Implemented fallback discovery for empty caches
- Added context-aware caching with separate cache keys
- Fixed object serialization preventing __PHP_Incomplete_Class

## Cache System Improvements
- Smart caching that only caches meaningful results
- Separate caches for different execution contexts (console, web, test)
- Proper array serialization/deserialization for cache compatibility
- Cache hit logging for debugging and monitoring

## Object Serialization Fixes
- Fixed DiscoveredAttribute serialization with proper string conversion
- Sanitized additional data to prevent object reference issues
- Added fallback for corrupted cache entries

## Performance & Reliability
- All 69 console commands properly discovered and cached
- 534 total discovery items successfully cached and restored
- No more __PHP_Incomplete_Class cache corruption
- Improved error handling and graceful fallbacks

## Testing & Quality
- Fixed code style issues across discovery components
- Enhanced logging for better debugging capabilities
- Improved cache validation and error recovery

Ready for production deployment with stable discovery system.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-13 12:04:17 +02:00

898 lines
28 KiB
Bash
Executable File

#!/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