← back to Watches

scripts/deploy.sh

252 lines

#!/bin/bash

###############################################################################
# Omega Watch Price History - Deployment Script
#
# Performs safe deployment with rollback capability
###############################################################################

set -euo pipefail

PROJECT_DIR="/root/Projects/watches"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
DEPLOY_LOG="${PROJECT_DIR}/logs/deploy_${TIMESTAMP}.log"

GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

log() {
    echo -e "${GREEN}[$(date +'%H:%M:%S')]${NC} $1" | tee -a "${DEPLOY_LOG}"
}

error() {
    echo -e "${RED}[$(date +'%H:%M:%S')] ERROR:${NC} $1" | tee -a "${DEPLOY_LOG}" >&2
}

warning() {
    echo -e "${YELLOW}[$(date +'%H:%M:%S')] WARNING:${NC} $1" | tee -a "${DEPLOY_LOG}"
}

info() {
    echo -e "${BLUE}[$(date +'%H:%M:%S')] INFO:${NC} $1" | tee -a "${DEPLOY_LOG}"
}

# Pre-deployment checks
pre_deploy_checks() {
    log "Running pre-deployment checks..."

    # Check if port is available
    if ! netstat -tuln | grep -q ":7600 "; then
        warning "Service not currently running on port 7600"
    fi

    # Check disk space
    local available_space=$(df -h /root | awk 'NR==2 {print $4}')
    log "Available disk space: ${available_space}"

    # Check if PM2 is running
    if ! pm2 list | grep -q "online"; then
        warning "No PM2 processes currently running"
    fi

    # Verify data integrity
    if [ -f "${PROJECT_DIR}/data/watches.json" ]; then
        if jq empty "${PROJECT_DIR}/data/watches.json" 2>/dev/null; then
            log "✓ Data integrity check passed"
        else
            error "Data file is corrupted!"
            exit 1
        fi
    else
        error "Data file not found!"
        exit 1
    fi

    log "Pre-deployment checks completed"
}

# Create backup before deployment
create_deployment_backup() {
    log "Creating pre-deployment backup..."

    "${PROJECT_DIR}/scripts/backup-system.sh" backup >> "${DEPLOY_LOG}" 2>&1

    if [ $? -eq 0 ]; then
        log "✓ Backup created successfully"
    else
        error "Backup failed!"
        exit 1
    fi
}

# Deploy application
deploy() {
    log "=========================================="
    log "Starting deployment: ${TIMESTAMP}"
    log "=========================================="

    cd "${PROJECT_DIR}"

    # Git pull if repository exists
    if [ -d ".git" ]; then
        log "Pulling latest changes from repository..."
        git pull origin main || warning "Git pull failed or no remote configured"
    fi

    # Install/update dependencies
    log "Installing dependencies..."
    npm ci --production >> "${DEPLOY_LOG}" 2>&1 || {
        error "npm install failed"
        exit 1
    }

    # Build frontend
    log "Building frontend..."
    npm run build >> "${DEPLOY_LOG}" 2>&1 || {
        error "Build failed"
        exit 1
    }

    # Reload PM2 process
    log "Reloading PM2 process..."
    pm2 reload ecosystem.config.js --update-env >> "${DEPLOY_LOG}" 2>&1 || {
        error "PM2 reload failed"
        return 1
    }

    # Wait for service to be ready
    log "Waiting for service to start..."
    sleep 5

    # Health check
    if health_check; then
        log "✓ Deployment successful!"
        pm2 save >> "${DEPLOY_LOG}" 2>&1
        return 0
    else
        error "Health check failed after deployment"
        return 1
    fi
}

# Health check
health_check() {
    local max_attempts=5
    local attempt=1

    while [ $attempt -le $max_attempts ]; do
        log "Health check attempt ${attempt}/${max_attempts}..."

        local http_code=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:7600/api/health)

        if [ "$http_code" = "200" ]; then
            log "✓ Health check passed (HTTP ${http_code})"
            return 0
        fi

        warning "Health check failed (HTTP ${http_code}), retrying..."
        sleep 3
        ((attempt++))
    done

    error "Health check failed after ${max_attempts} attempts"
    return 1
}

# Rollback to previous version
rollback() {
    error "=========================================="
    error "INITIATING ROLLBACK"
    error "=========================================="

    log "Restoring from latest backup..."

    local latest_backup=$(ls -t "${PROJECT_DIR}/backups/daily"/full_backup_*.tar.gz 2>/dev/null | head -1)

    if [ -n "${latest_backup}" ]; then
        "${PROJECT_DIR}/scripts/backup-system.sh" restore "${latest_backup}" >> "${DEPLOY_LOG}" 2>&1

        if health_check; then
            log "✓ Rollback successful"
            return 0
        else
            error "Rollback failed - manual intervention required!"
            return 1
        fi
    else
        error "No backup found for rollback!"
        return 1
    fi
}

# Post-deployment tasks
post_deploy() {
    log "Running post-deployment tasks..."

    # Clear cache
    curl -s -X POST http://localhost:7600/api/admin/clear-cache > /dev/null || true

    # Log deployment
    echo "${TIMESTAMP}: Deployment successful" >> "${PROJECT_DIR}/logs/deployments.log"

    # Display service info
    info "=========================================="
    info "Deployment Summary"
    info "=========================================="
    info "Timestamp: ${TIMESTAMP}"
    info "Service: http://45.61.58.125:7600"
    info "Health: http://45.61.58.125:7600/api/health"
    info "PM2 Status:"
    pm2 list | grep -E "omega-watches|health-monitor" || true
    info "=========================================="
}

# Main deployment flow
main() {
    mkdir -p "${PROJECT_DIR}/logs"

    log "Omega Watch Price History - Deployment Script"
    log "Log file: ${DEPLOY_LOG}"

    # Pre-deployment
    pre_deploy_checks
    create_deployment_backup

    # Deploy
    if deploy; then
        post_deploy
        log "🚀 Deployment completed successfully!"
        exit 0
    else
        # Deployment failed, attempt rollback
        if rollback; then
            error "Deployment failed, but rollback successful"
            exit 1
        else
            error "CRITICAL: Deployment AND rollback failed!"
            error "Manual intervention required immediately"
            exit 2
        fi
    fi
}

# Handle command line arguments
case "${1:-deploy}" in
    deploy)
        main
        ;;
    rollback)
        rollback
        ;;
    health-check)
        health_check
        ;;
    *)
        echo "Usage: $0 {deploy|rollback|health-check}"
        exit 1
        ;;
esac