From 2ebaf6420f7e23701ae997c6522481ce2d16a1ac Mon Sep 17 00:00:00 2001 From: Vadym Samoilenko Date: Wed, 15 Apr 2026 10:57:48 +0100 Subject: [PATCH] Add deploy-dev.sh for dev server (sudo docker, fix dist permissions) Co-Authored-By: Claude Sonnet 4.6 --- deploy-dev.sh | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100755 deploy-dev.sh diff --git a/deploy-dev.sh b/deploy-dev.sh new file mode 100755 index 0000000..9b5a24f --- /dev/null +++ b/deploy-dev.sh @@ -0,0 +1,219 @@ +#!/bin/bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +echo "=== ModComms DEV Deployment ===" +echo "Working directory: $SCRIPT_DIR" + +# --- Check prerequisites --- +echo "" +echo "[Prerequisites] Checking required tools..." + +check_command() { + if ! command -v "$1" &> /dev/null; then + echo "Error: $1 is not installed" + exit 1 + fi + echo " ✓ $1" +} + +check_command git +check_command node +check_command npm +check_command docker + +# --- Load deployment configuration --- +if [ -f .env.deploy ]; then + source .env.deploy + echo " ✓ .env.deploy loaded" +else + echo "" + echo "Error: .env.deploy not found" + echo "Create it from the template:" + echo " cp .env.deploy.example .env.deploy" + echo " nano .env.deploy" + exit 1 +fi + +# Validate required variables +require_var() { + local var_name="$1" + local value="${!var_name}" + if [ -z "$value" ] || [[ "$value" == *"your_"* ]]; then + echo "" + echo "Error: ${var_name} is not configured in .env.deploy" + exit 1 + fi + echo " ✓ ${var_name}" +} + +echo "" +echo "[Config] Validating required variables..." +require_var FRONTEND_DEPLOY_DIR +require_var GEMINI_API_KEY +require_var AZURE_TENANT_ID +require_var AZURE_CLIENT_ID +require_var VITE_BACKEND_URL +require_var VITE_AZURE_REDIRECT_URI + +# Set defaults +COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME:-modcomms-dev}" +BACKEND_PORT="${BACKEND_PORT:-8001}" +POSTGRES_PORT="${POSTGRES_PORT:-5432}" +POSTGRES_USER="${POSTGRES_USER:-modcomms}" +POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-modcomms_dev}" +POSTGRES_DB="${POSTGRES_DB:-modcomms}" +VITE_BASE_PATH="${VITE_BASE_PATH:-/}" +DISABLE_AUTH="${DISABLE_AUTH:-false}" +CORS_ORIGINS="${CORS_ORIGINS:-}" + +echo " Environment: ${COMPOSE_PROJECT_NAME} (backend:${BACKEND_PORT}, postgres:${POSTGRES_PORT})" + +# --- Generate .env (docker compose) --- +cat > .env << EOF +# Auto-generated by deploy-dev.sh — do not edit manually +# Edit .env.deploy instead and re-run deploy-dev.sh +COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME} +BACKEND_PORT=${BACKEND_PORT} +POSTGRES_PORT=${POSTGRES_PORT} +POSTGRES_USER=${POSTGRES_USER} +POSTGRES_PASSWORD=${POSTGRES_PASSWORD} +POSTGRES_DB=${POSTGRES_DB} +EOF +echo " ✓ .env created for docker compose" + +# --- Generate backend/.env --- +echo "" +echo "[Config] Generating backend/.env..." +cat > backend/.env << EOF +# Auto-generated by deploy-dev.sh — do not edit manually +# Edit .env.deploy instead and re-run deploy-dev.sh +GEMINI_API_KEY=${GEMINI_API_KEY} +CORS_ORIGINS=${CORS_ORIGINS} +HOST=0.0.0.0 +PORT=${BACKEND_PORT} +AZURE_TENANT_ID=${AZURE_TENANT_ID} +AZURE_CLIENT_ID=${AZURE_CLIENT_ID} +DISABLE_AUTH=${DISABLE_AUTH} +MAILGUN_API_URL=${MAILGUN_API_URL} +MAILGUN_API_KEY=${MAILGUN_API_KEY} +MAILGUN_FROM=${MAILGUN_FROM} +SUPPORT_EMAIL=${SUPPORT_EMAIL} +LLAMA_CLOUD_API_KEY=${LLAMA_CLOUD_API_KEY} +EOF +echo " ✓ backend/.env generated" + +# --- Generate frontend/.env.local --- +echo "" +echo "[Config] Generating frontend/.env.local..." +cat > frontend/.env.local << EOF +# Auto-generated by deploy-dev.sh — do not edit manually +# Edit .env.deploy instead and re-run deploy-dev.sh +VITE_BASE_PATH=${VITE_BASE_PATH} +VITE_BACKEND_URL=${VITE_BACKEND_URL} +VITE_AZURE_CLIENT_ID=${AZURE_CLIENT_ID} +VITE_AZURE_TENANT_ID=${AZURE_TENANT_ID} +VITE_AZURE_REDIRECT_URI=${VITE_AZURE_REDIRECT_URI} +EOF +echo " ✓ frontend/.env.local generated" + +# --- 1. Pull latest code --- +echo "" +echo "[1/6] Updating code..." +if [ -d .git ]; then + if git remote -v | grep -q origin; then + git checkout -- frontend/package-lock.json 2>/dev/null || true + git pull || echo "Warning: git pull failed, continuing with local code" + else + echo " No remote configured, skipping git pull" + fi +else + echo " Not a git repository, skipping git pull" +fi + +# --- 2. Build frontend --- +echo "" +echo "[2/6] Building frontend..." +# Fix ownership of dist so npm build (running as current user) can clean it +sudo rm -rf frontend/dist +cd frontend +npm install +npm run build +cd "$SCRIPT_DIR" + +# --- 3. Deploy frontend to Apache --- +echo "" +echo "[3/6] Deploying frontend to ${FRONTEND_DEPLOY_DIR}..." +sudo mkdir -p "$FRONTEND_DEPLOY_DIR" +if [ -n "$FRONTEND_DEPLOY_DIR" ] && [ -d "$FRONTEND_DEPLOY_DIR" ]; then + sudo find "$FRONTEND_DEPLOY_DIR" -mindepth 1 -delete 2>/dev/null || true +fi +sudo cp -r frontend/dist/* "$FRONTEND_DEPLOY_DIR/" +sudo chown -R www-data:www-data "$FRONTEND_DEPLOY_DIR" +echo " ✓ Frontend deployed" + +# --- 4. Build containers and run database migrations --- +echo "" +echo "[4/6] Building containers..." +sudo docker compose build + +echo " Starting PostgreSQL..." +sudo docker compose up -d postgres + +echo " Waiting for PostgreSQL to be ready..." +for i in {1..30}; do + if sudo docker compose exec -T postgres pg_isready -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" > /dev/null 2>&1; then + echo " ✓ PostgreSQL is ready" + break + fi + if [ $i -eq 30 ]; then + echo " Error: PostgreSQL failed to start" + sudo docker compose logs postgres + exit 1 + fi + sleep 1 +done + +# --- 5. Run database migrations --- +echo "" +echo "[5/6] Running database migrations..." +if sudo docker compose run --rm backend alembic upgrade head; then + echo " ✓ Database migrations complete" +else + echo " Error: Database migrations failed" + exit 1 +fi + +# --- 6. Start backend service --- +echo "" +echo "[6/6] Starting backend service..." +sudo docker compose up -d --force-recreate backend + +echo " Waiting for backend to be healthy..." +for i in {1..30}; do + if curl -sf "http://localhost:${BACKEND_PORT}/health" > /dev/null 2>&1; then + echo " ✓ Backend is healthy" + break + fi + if [ $i -eq 30 ]; then + echo " Warning: Backend health check timed out" + fi + sleep 1 +done + +# --- Summary --- +echo "" +echo "=========================================" +echo " DEV Deployment Complete!" +echo "=========================================" +echo "" +echo "Environment: ${COMPOSE_PROJECT_NAME}" +echo "Frontend: ${FRONTEND_DEPLOY_DIR}" +echo "Backend: http://localhost:${BACKEND_PORT}" +echo "" +sudo docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}" +echo "" +echo "Health check:" +curl -s "http://localhost:${BACKEND_PORT}/health" && echo "" || echo "Warning: Backend not responding"