260 lines
6.2 KiB
Bash
Executable File
260 lines
6.2 KiB
Bash
Executable File
#!/bin/bash
|
|
# Deployment script for Moyos Wedding App
|
|
# Usage: ./deploy.sh [--staging|--production] [--skip-build] [--skip-migrations]
|
|
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
log() {
|
|
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1"
|
|
}
|
|
|
|
error() {
|
|
echo -e "${RED}[ERROR]${NC} $1" >&2
|
|
}
|
|
|
|
warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
|
}
|
|
|
|
info() {
|
|
echo -e "${BLUE}[INFO]${NC} $1"
|
|
}
|
|
|
|
# Configuration
|
|
APP_DIR="${APP_DIR:-/opt/moyos-wedding-app/app}"
|
|
ENV_FILE="${ENV_FILE:-.env.production}"
|
|
PM2_APP_NAME="${PM2_APP_NAME:-moyos-wedding-app}"
|
|
ENVIRONMENT="${1:-production}"
|
|
SKIP_BUILD=false
|
|
SKIP_MIGRATIONS=false
|
|
|
|
# Parse arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--staging)
|
|
ENVIRONMENT="staging"
|
|
ENV_FILE=".env.staging"
|
|
shift
|
|
;;
|
|
--production)
|
|
ENVIRONMENT="production"
|
|
ENV_FILE=".env.production"
|
|
shift
|
|
;;
|
|
--skip-build)
|
|
SKIP_BUILD=true
|
|
shift
|
|
;;
|
|
--skip-migrations)
|
|
SKIP_MIGRATIONS=true
|
|
shift
|
|
;;
|
|
*)
|
|
error "Unknown option: $1"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
log "Starting deployment to $ENVIRONMENT environment..."
|
|
|
|
# Check if running as correct user
|
|
if [ "$EUID" -eq 0 ]; then
|
|
warn "Running as root. Consider using a non-root user for deployment."
|
|
fi
|
|
|
|
# Navigate to app directory
|
|
if [ ! -d "$APP_DIR" ]; then
|
|
error "App directory not found: $APP_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
cd "$APP_DIR"
|
|
log "Working directory: $(pwd)"
|
|
|
|
# Check if environment file exists
|
|
if [ ! -f "$ENV_FILE" ]; then
|
|
error "Environment file not found: $ENV_FILE"
|
|
error "Please create $ENV_FILE before deploying"
|
|
exit 1
|
|
fi
|
|
|
|
# Load environment variables
|
|
set -a
|
|
source "$ENV_FILE"
|
|
set +a
|
|
|
|
# Pre-deployment checks
|
|
log "Running pre-deployment checks..."
|
|
|
|
# Check Node.js version
|
|
NODE_VERSION=$(node --version)
|
|
log "Node.js version: $NODE_VERSION"
|
|
if [[ ! "$NODE_VERSION" =~ ^v20\. ]]; then
|
|
error "Node.js 20.x required. Found: $NODE_VERSION"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if PM2 is installed
|
|
if ! command -v pm2 &> /dev/null; then
|
|
error "PM2 is not installed. Install with: npm install -g pm2"
|
|
exit 1
|
|
fi
|
|
|
|
# Check database connection
|
|
if [ "$SKIP_MIGRATIONS" = false ]; then
|
|
log "Checking database connection..."
|
|
if command -v psql &> /dev/null && [ -n "$DATABASE_URL" ]; then
|
|
# Extract connection details from DATABASE_URL
|
|
# This is a simple check - actual connection test would be better
|
|
log "Database URL configured"
|
|
else
|
|
warn "Cannot verify database connection. Proceeding anyway..."
|
|
fi
|
|
fi
|
|
|
|
# Git pull (if in git repository)
|
|
if [ -d ".git" ]; then
|
|
log "Pulling latest changes from Git..."
|
|
git pull origin main || git pull || {
|
|
warn "Git pull failed or not on a branch. Continuing with current code..."
|
|
}
|
|
else
|
|
warn "Not a Git repository. Skipping Git pull."
|
|
fi
|
|
|
|
# Install dependencies
|
|
log "Installing dependencies..."
|
|
npm ci --production=false || {
|
|
error "Failed to install dependencies"
|
|
exit 1
|
|
}
|
|
|
|
# Generate Prisma client
|
|
log "Generating Prisma client..."
|
|
npx prisma generate || {
|
|
error "Failed to generate Prisma client"
|
|
exit 1
|
|
}
|
|
|
|
# Run database migrations
|
|
if [ "$SKIP_MIGRATIONS" = false ]; then
|
|
log "Running database migrations..."
|
|
npx prisma migrate deploy || {
|
|
error "Database migrations failed"
|
|
exit 1
|
|
}
|
|
log "Database migrations completed"
|
|
else
|
|
warn "Skipping database migrations (--skip-migrations flag)"
|
|
fi
|
|
|
|
# Build application
|
|
if [ "$SKIP_BUILD" = false ]; then
|
|
log "Building application..."
|
|
npm run build || {
|
|
error "Build failed"
|
|
exit 1
|
|
}
|
|
log "Build completed successfully"
|
|
else
|
|
warn "Skipping build (--skip-build flag)"
|
|
if [ ! -d ".next" ]; then
|
|
error "No .next directory found and --skip-build was used"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Health check before deployment
|
|
log "Running pre-deployment health check..."
|
|
if [ -f "scripts/health-check.sh" ]; then
|
|
bash scripts/health-check.sh || {
|
|
warn "Pre-deployment health check failed, but continuing..."
|
|
}
|
|
fi
|
|
|
|
# PM2 deployment
|
|
log "Deploying with PM2..."
|
|
|
|
# Check if app is already running
|
|
if pm2 list | grep -q "$PM2_APP_NAME"; then
|
|
log "App is already running. Performing graceful reload..."
|
|
pm2 reload "$PM2_APP_NAME" || {
|
|
error "PM2 reload failed"
|
|
exit 1
|
|
}
|
|
else
|
|
log "Starting app with PM2..."
|
|
|
|
# Check for ecosystem file
|
|
if [ -f "ecosystem.config.js" ]; then
|
|
pm2 start ecosystem.config.js || {
|
|
error "Failed to start PM2 with ecosystem config"
|
|
exit 1
|
|
}
|
|
else
|
|
# Fallback: start with npm
|
|
pm2 start npm --name "$PM2_APP_NAME" -- start || {
|
|
error "Failed to start PM2"
|
|
exit 1
|
|
}
|
|
fi
|
|
fi
|
|
|
|
# Save PM2 process list
|
|
pm2 save || {
|
|
warn "Failed to save PM2 process list"
|
|
}
|
|
|
|
# Wait for app to be ready
|
|
log "Waiting for application to be ready..."
|
|
sleep 5
|
|
|
|
# Health check after deployment
|
|
log "Running post-deployment health check..."
|
|
MAX_RETRIES=10
|
|
RETRY_COUNT=0
|
|
HEALTH_CHECK_URL="${NEXT_PUBLIC_APP_URL:-http://localhost:3000}/api/health"
|
|
|
|
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
|
|
if curl -f -s "$HEALTH_CHECK_URL" > /dev/null 2>&1; then
|
|
log "Health check passed!"
|
|
break
|
|
else
|
|
RETRY_COUNT=$((RETRY_COUNT + 1))
|
|
if [ $RETRY_COUNT -ge $MAX_RETRIES ]; then
|
|
error "Health check failed after $MAX_RETRIES attempts"
|
|
error "Check application logs: pm2 logs $PM2_APP_NAME"
|
|
exit 1
|
|
fi
|
|
warn "Health check failed. Retrying... ($RETRY_COUNT/$MAX_RETRIES)"
|
|
sleep 3
|
|
fi
|
|
done
|
|
|
|
# Show deployment status
|
|
log "Deployment completed successfully!"
|
|
info "PM2 Status:"
|
|
pm2 status "$PM2_APP_NAME"
|
|
info ""
|
|
info "View logs: pm2 logs $PM2_APP_NAME"
|
|
info "Monitor: pm2 monit"
|
|
info "Restart: pm2 restart $PM2_APP_NAME"
|
|
|
|
# Optional: Run smoke tests
|
|
if [ -f "scripts/smoke-tests.sh" ]; then
|
|
log "Running smoke tests..."
|
|
bash scripts/smoke-tests.sh || {
|
|
warn "Smoke tests failed, but deployment succeeded"
|
|
}
|
|
fi
|
|
|
|
log "Deployment to $ENVIRONMENT completed successfully! 🎉"
|