#!/bin/bash # Rollback Script for Portfolio Deployment # Restores previous version of the application set -e # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log() { echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" } error() { echo -e "${RED}[ERROR]${NC} $1" >&2 } success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } # Check if environment is specified ENV=${1:-production} COMPOSE_FILE="docker-compose.production.yml" CONTAINER_NAME="portfolio-app" IMAGE_TAG="production" if [ "$ENV" == "dev" ] || [ "$ENV" == "staging" ]; then COMPOSE_FILE="docker-compose.staging.yml" CONTAINER_NAME="portfolio-app-staging" IMAGE_TAG="staging" HEALTH_PORT="3002" else HEALTH_PORT="3000" fi log "🔄 Starting rollback for $ENV environment..." # Check if Docker is running if ! docker info > /dev/null 2>&1; then error "Docker is not running. Please start Docker and try again." exit 1 fi # List available image tags log "📋 Available image versions:" docker images portfolio-app --format "table {{.Tag}}\t{{.ID}}\t{{.CreatedAt}}" | head -10 # Get current container image CURRENT_IMAGE=$(docker inspect $CONTAINER_NAME --format='{{.Config.Image}}' 2>/dev/null || echo "") if [ ! -z "$CURRENT_IMAGE" ]; then log "Current image: $CURRENT_IMAGE" fi # Find previous image tags PREVIOUS_TAGS=$(docker images portfolio-app --format "{{.Tag}}" | grep -E "^(production|staging|latest|previous|backup)" | grep -v "^$IMAGE_TAG$" | head -5) if [ -z "$PREVIOUS_TAGS" ]; then error "No previous images found for rollback!" log "Available images:" docker images portfolio-app exit 1 fi # Use the first previous tag (most recent) PREVIOUS_TAG=$(echo "$PREVIOUS_TAGS" | head -1) log "Selected previous image: portfolio-app:$PREVIOUS_TAG" # Confirm rollback read -p "Do you want to rollback to portfolio-app:$PREVIOUS_TAG? (y/N): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then log "Rollback cancelled." exit 0 fi # Tag the previous image as current log "🔄 Tagging previous image as current..." docker tag "portfolio-app:$PREVIOUS_TAG" "portfolio-app:$IMAGE_TAG" || { error "Failed to tag previous image" exit 1 } # Stop current container log "🛑 Stopping current container..." docker compose -f $COMPOSE_FILE down || true # Start with previous image log "🚀 Starting previous version..." docker compose -f $COMPOSE_FILE up -d # Wait for health check log "⏳ Waiting for health check..." for i in {1..40}; do if curl -f http://localhost:$HEALTH_PORT/api/health > /dev/null 2>&1; then success "✅ Rollback successful! Application is healthy." break fi echo -n "." sleep 3 done if ! curl -f http://localhost:$HEALTH_PORT/api/health > /dev/null 2>&1; then error "❌ Health check failed after rollback!" log "Container logs:" docker compose -f $COMPOSE_FILE logs --tail=50 exit 1 fi success "🎉 Rollback completed successfully!" log "Application is available at: http://localhost:$HEALTH_PORT" log "To rollback further, run: ./scripts/rollback.sh $ENV"