#!/bin/bash # Auto-Deploy Script fΓΌr Portfolio # FΓΌhrt automatisch Tests, Build und Deployment durch set -e # Configuration PROJECT_NAME="portfolio" CONTAINER_NAME="portfolio-app" IMAGE_NAME="portfolio-app" PORT=3000 BACKUP_PORT=3001 LOG_FILE="./logs/portfolio-deploy.log" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Logging function log() { echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE" } error() { echo -e "${RED}[ERROR]${NC} $1" | tee -a "$LOG_FILE" } success() { echo -e "${GREEN}[SUCCESS]${NC} $1" | tee -a "$LOG_FILE" } warning() { echo -e "${YELLOW}[WARNING]${NC} $1" | tee -a "$LOG_FILE" } # Check if running as root (skip in CI environments) if [[ $EUID -eq 0 ]] && [[ -z "$CI" ]]; then error "This script should not be run as root (use CI=true to override)" exit 1 fi # Check if Docker is running if ! sudo docker info > /dev/null 2>&1; then error "Docker is not running. Please start Docker and try again." exit 1 fi # Check if we're in the right directory if [ ! -f "package.json" ] || [ ! -f "Dockerfile" ]; then error "Please run this script from the project root directory" exit 1 fi log "πŸš€ Starting automatic deployment for $PROJECT_NAME" # Step 1: Code Quality Checks log "πŸ“‹ Step 1: Running code quality checks..." # Check for uncommitted changes if [ -n "$(git status --porcelain)" ]; then warning "You have uncommitted changes. Committing them..." git add . git commit -m "Auto-commit before deployment $(date)" fi # Pull latest changes log "πŸ“₯ Pulling latest changes..." git pull origin production || { error "Failed to pull latest changes" exit 1 } # Run linting log "πŸ” Running ESLint..." npm run lint || { error "ESLint failed. Please fix the issues before deploying." exit 1 } # Run tests log "πŸ§ͺ Running tests..." npm run test || { error "Tests failed. Please fix the issues before deploying." exit 1 } success "βœ… Code quality checks passed" # Step 2: Build Application log "πŸ”¨ Step 2: Building application..." # Build Next.js application log "πŸ“¦ Building Next.js application..." npm run build || { error "Build failed" exit 1 } success "βœ… Application built successfully" # Step 3: Docker Operations log "🐳 Step 3: Docker operations..." # Build Docker image log "πŸ—οΈ Building Docker image..." sudo docker build -t "$IMAGE_NAME:latest" . || { error "Docker build failed" exit 1 } # Tag with timestamp TIMESTAMP=$(date +%Y%m%d-%H%M%S) sudo docker tag "$IMAGE_NAME:latest" "$IMAGE_NAME:$TIMESTAMP" success "βœ… Docker image built successfully" # Step 4: Deployment log "πŸš€ Step 4: Deploying application..." # Check if container is running if [ "$(sudo docker inspect -f '{{.State.Running}}' "$CONTAINER_NAME" 2>/dev/null)" = "true" ]; then log "πŸ“¦ Stopping existing container..." sudo docker stop "$CONTAINER_NAME" || true sudo docker rm "$CONTAINER_NAME" || true fi # Check if port is available if lsof -Pi :$PORT -sTCP:LISTEN -t >/dev/null ; then warning "Port $PORT is in use. Trying backup port $BACKUP_PORT" DEPLOY_PORT=$BACKUP_PORT else DEPLOY_PORT=$PORT fi # Start new container log "πŸš€ Starting new container on port $DEPLOY_PORT..." sudo docker run -d \ --name "$CONTAINER_NAME" \ --restart unless-stopped \ -p "$DEPLOY_PORT:3000" \ -e NODE_ENV=production \ "$IMAGE_NAME:latest" || { error "Failed to start container" exit 1 } # Wait for container to be ready log "⏳ Waiting for container to be ready..." sleep 10 # Health check log "πŸ₯ Performing health check..." HEALTH_CHECK_TIMEOUT=60 HEALTH_CHECK_INTERVAL=2 ELAPSED=0 while [ $ELAPSED -lt $HEALTH_CHECK_TIMEOUT ]; do if curl -f "http://localhost:$DEPLOY_PORT/api/health" > /dev/null 2>&1; then success "βœ… Application is healthy!" break fi sleep $HEALTH_CHECK_INTERVAL ELAPSED=$((ELAPSED + HEALTH_CHECK_INTERVAL)) echo -n "." done if [ $ELAPSED -ge $HEALTH_CHECK_TIMEOUT ]; then error "Health check timeout. Application may not be running properly." log "Container logs:" docker logs "$CONTAINER_NAME" --tail=50 exit 1 fi # Step 5: Verification log "βœ… Step 5: Verifying deployment..." # Test main page if curl -f "http://localhost:$DEPLOY_PORT/" > /dev/null 2>&1; then success "βœ… Main page is accessible" else error "❌ Main page is not accessible" exit 1 fi # Show container status log "πŸ“Š Container status:" sudo docker ps --filter "name=$CONTAINER_NAME" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" # Show resource usage log "πŸ“ˆ Resource usage:" sudo docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}" "$CONTAINER_NAME" # Step 6: Cleanup log "🧹 Step 6: Cleaning up old images..." # Remove old images (keep last 3 versions) sudo docker images "$IMAGE_NAME" --format "table {{.Tag}}\t{{.ID}}" | tail -n +2 | head -n -3 | awk '{print $2}' | xargs -r sudo docker rmi || { warning "No old images to remove" } # Clean up unused Docker resources sudo docker system prune -f --volumes || { warning "Failed to clean up Docker resources" } # Final success message success "πŸŽ‰ Deployment completed successfully!" log "🌐 Application is available at: http://localhost:$DEPLOY_PORT" log "πŸ₯ Health check endpoint: http://localhost:$DEPLOY_PORT/api/health" log "πŸ“Š Container name: $CONTAINER_NAME" log "πŸ“ Logs: sudo docker logs $CONTAINER_NAME" # Update deployment log echo "$(date): Deployment successful - Port: $DEPLOY_PORT - Image: $IMAGE_NAME:$TIMESTAMP" >> "$LOG_FILE" exit 0