Files
2026-01-15 16:19:14 +02:00

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! 🎉"