#!/usr/bin/env bash set -euo pipefail # ============================================================================= # OliVAS Production Deploy Script # Idempotent — safe to run for initial deploy and subsequent updates # ============================================================================= REPO_DIR=/opt/olivas WEB_DIR=/var/www/html/olivas COMPOSE="docker compose -f docker-compose.yml -f docker-compose.prod.yml" # --------------------------------------------------------------------------- # Color helpers # --------------------------------------------------------------------------- info() { printf '\033[1;34m[INFO]\033[0m %s\n' "$*"; } warn() { printf '\033[1;33m[WARN]\033[0m %s\n' "$*"; } error() { printf '\033[1;31m[ERROR]\033[0m %s\n' "$*"; } success() { printf '\033[1;32m[OK]\033[0m %s\n' "$*"; } # --------------------------------------------------------------------------- # 1. Preflight checks # --------------------------------------------------------------------------- if ! command -v docker &>/dev/null; then error "docker is not installed." exit 1 fi if ! docker compose version &>/dev/null; then error "docker compose plugin is not available." exit 1 fi # --------------------------------------------------------------------------- # 2. Pull latest code # --------------------------------------------------------------------------- cd "$REPO_DIR" info "Pulling latest code..." git pull --ff-only origin main COMMIT=$(git rev-parse --short HEAD) success "At commit $COMMIT" # --------------------------------------------------------------------------- # 3. Handle .env # --------------------------------------------------------------------------- if [[ ! -f .env ]]; then cp .env.example .env warn ".env was created from .env.example." warn "Edit /opt/olivas/.env with production values, then re-run this script." exit 0 fi info "Loading .env..." set -a # shellcheck disable=SC1091 source .env set +a # --------------------------------------------------------------------------- # 4. Build backend Docker image # --------------------------------------------------------------------------- info "Building backend image..." $COMPOSE build backend # --------------------------------------------------------------------------- # 5. Start postgres and wait for it to be healthy # --------------------------------------------------------------------------- info "Starting postgres..." $COMPOSE up -d postgres info "Waiting for postgres to be ready..." for i in $(seq 1 30); do if $COMPOSE exec postgres pg_isready -U olivas &>/dev/null; then success "Postgres is ready." break fi if [[ $i -eq 30 ]]; then error "Postgres did not become ready within 30 seconds." exit 1 fi sleep 1 done # --------------------------------------------------------------------------- # 6. Run database migrations # --------------------------------------------------------------------------- info "Starting backend for migrations..." $COMPOSE up -d backend info "Running database migrations..." $COMPOSE exec -e PYTHONPATH=/app backend alembic -c alembic.ini upgrade head success "Migrations complete." # --------------------------------------------------------------------------- # 7. Restart backend (pick up new code/env) # --------------------------------------------------------------------------- info "Restarting backend..." $COMPOSE up -d --force-recreate backend success "Backend restarted." # --------------------------------------------------------------------------- # 8. Build frontend in a temporary Docker container # --------------------------------------------------------------------------- info "Building frontend..." docker run --rm \ -v "$REPO_DIR/frontend:/app" \ -w /app \ -e VITE_AZURE_TENANT_ID \ -e VITE_AZURE_CLIENT_ID \ -e VITE_AZURE_REDIRECT_URI \ node:20-alpine \ sh -c "npm ci --prefer-offline && npm run build" success "Frontend built." # --------------------------------------------------------------------------- # 9. Deploy frontend to web directory # --------------------------------------------------------------------------- info "Deploying frontend to $WEB_DIR..." mkdir -p "$WEB_DIR" rm -rf "${WEB_DIR:?}"/* cp -r "$REPO_DIR/frontend/dist/"* "$WEB_DIR/" chmod -R a+rX "$WEB_DIR" success "Frontend deployed." # --------------------------------------------------------------------------- # 10. Health check # --------------------------------------------------------------------------- info "Waiting for backend health check..." sleep 3 if curl -sf http://localhost:8000/api/health > /dev/null 2>&1; then success "Backend health check passed." else warn "Backend health check failed — it may still be starting up." fi # --------------------------------------------------------------------------- # 11. Summary # --------------------------------------------------------------------------- echo "" success "Deploy complete" info "Commit: $COMMIT" info "Timestamp: $(date -u '+%Y-%m-%d %H:%M:%S UTC')"