#!/usr/bin/env bash # ========================================================= # BreakPilot Compliance — Deploy Script # ========================================================= # Pushes to both remotes, rebuilds changed services on # Mac Mini, and monitors Coolify production health. # # Usage: ./scripts/deploy.sh # ========================================================= set -euo pipefail # --- Configuration --- PROJECT="breakpilot-compliance" PROJECT_DIR="/Users/benjaminadmin/Projekte/${PROJECT}" COMPOSE_FILE="${PROJECT_DIR}/docker-compose.yml" DOCKER="/usr/local/bin/docker" MAC_MINI="macmini" # Coolify health endpoints HEALTH_ENDPOINTS=( "https://api-dev.breakpilot.ai/health" "https://sdk-dev.breakpilot.ai/health" ) HEALTH_INTERVAL=20 HEALTH_TIMEOUT=300 # 5 minutes # Map top-level directories to docker-compose service names declare -A DIR_TO_SERVICE=( [admin-compliance]=admin-compliance [backend-compliance]=backend-compliance [ai-compliance-sdk]=ai-compliance-sdk [developer-portal]=developer-portal [compliance-tts-service]=compliance-tts-service [document-crawler]=document-crawler [dsms-node]=dsms-node [dsms-gateway]=dsms-gateway [docs-src]=docs ) # --- Helpers --- info() { printf "\033[1;34m[INFO]\033[0m %s\n" "$*"; } ok() { printf "\033[1;32m[OK]\033[0m %s\n" "$*"; } warn() { printf "\033[1;33m[WARN]\033[0m %s\n" "$*"; } fail() { printf "\033[1;31m[FAIL]\033[0m %s\n" "$*"; } # --- Step 1: Push to both remotes --- info "Pushing to origin (local Gitea)..." git push origin main ok "Pushed to origin." info "Pushing to gitea (external)..." git push gitea main ok "Pushed to gitea." # --- Step 2: Detect changed services --- info "Detecting changed services since last deploy..." # Get the commit before the push (what Mac Mini currently has) REMOTE_HEAD=$(ssh "${MAC_MINI}" "git -C ${PROJECT_DIR} rev-parse HEAD" 2>/dev/null || echo "") LOCAL_HEAD=$(git rev-parse HEAD) CHANGED_SERVICES=() if [ -z "${REMOTE_HEAD}" ] || [ "${REMOTE_HEAD}" = "${LOCAL_HEAD}" ]; then # Cannot determine diff or already up to date — check last 1 commit info "Cannot determine remote HEAD or already equal. Checking last commit diff..." CHANGED_DIRS=$(git diff --name-only HEAD~1 HEAD 2>/dev/null | cut -d'/' -f1 | sort -u) else CHANGED_DIRS=$(git diff --name-only "${REMOTE_HEAD}" "${LOCAL_HEAD}" 2>/dev/null | cut -d'/' -f1 | sort -u) fi for dir in ${CHANGED_DIRS}; do svc="${DIR_TO_SERVICE[${dir}]:-}" if [ -n "${svc}" ]; then CHANGED_SERVICES+=("${svc}") fi done # Also check if docker-compose.yml itself changed if echo "${CHANGED_DIRS}" | grep -q "^docker-compose"; then info "docker-compose.yml changed — will rebuild all services." CHANGED_SERVICES=() for svc in "${DIR_TO_SERVICE[@]}"; do CHANGED_SERVICES+=("${svc}") done fi if [ ${#CHANGED_SERVICES[@]} -eq 0 ]; then warn "No service directories changed. Nothing to rebuild on Mac Mini." info "Coolify will still deploy from the gitea push." else # Deduplicate CHANGED_SERVICES=($(printf '%s\n' "${CHANGED_SERVICES[@]}" | sort -u)) info "Changed services: ${CHANGED_SERVICES[*]}" # --- Step 3: Pull code on Mac Mini --- info "Pulling latest code on Mac Mini..." ssh "${MAC_MINI}" "git -C ${PROJECT_DIR} pull --no-rebase origin main" ok "Code pulled on Mac Mini." # --- Step 4: Rebuild + restart changed services --- SERVICES_STR="${CHANGED_SERVICES[*]}" info "Building changed services on Mac Mini: ${SERVICES_STR}" ssh "${MAC_MINI}" "${DOCKER} compose -f ${COMPOSE_FILE} build ${SERVICES_STR}" ok "Build complete." info "Restarting changed services on Mac Mini: ${SERVICES_STR}" ssh "${MAC_MINI}" "${DOCKER} compose -f ${COMPOSE_FILE} up -d --no-deps ${SERVICES_STR}" ok "Services restarted on Mac Mini." fi # --- Step 5: Monitor Coolify health in background --- info "Monitoring Coolify production health in background (every ${HEALTH_INTERVAL}s, max ${HEALTH_TIMEOUT}s)..." ( elapsed=0 all_healthy=false while [ ${elapsed} -lt ${HEALTH_TIMEOUT} ]; do sleep ${HEALTH_INTERVAL} elapsed=$((elapsed + HEALTH_INTERVAL)) healthy_count=0 for endpoint in "${HEALTH_ENDPOINTS[@]}"; do if curl -sf --max-time 5 "${endpoint}" >/dev/null 2>&1; then healthy_count=$((healthy_count + 1)) fi done if [ ${healthy_count} -eq ${#HEALTH_ENDPOINTS[@]} ]; then all_healthy=true break fi printf "\033[1;34m[HEALTH]\033[0m %d/%d endpoints healthy (%ds elapsed)\n" \ ${healthy_count} ${#HEALTH_ENDPOINTS[@]} ${elapsed} done echo "" if ${all_healthy}; then printf "\033[1;32m========================================\033[0m\n" printf "\033[1;32m Coolify deploy complete! \033[0m\n" printf "\033[1;32m All health endpoints are healthy. \033[0m\n" printf "\033[1;32m Test at: https://admin-dev.breakpilot.ai\033[0m\n" printf "\033[1;32m========================================\033[0m\n" else printf "\033[1;31m========================================\033[0m\n" printf "\033[1;31m Coolify deploy may have failed! \033[0m\n" printf "\033[1;31m Not all endpoints healthy after %ds. \033[0m\n" ${HEALTH_TIMEOUT} printf "\033[1;31m Check Coolify logs. \033[0m\n" printf "\033[1;31m========================================\033[0m\n" fi ) & HEALTH_PID=$! # --- Step 6: Report --- echo "" ok "Local deploy to Mac Mini: done." info "Coolify health monitor running in background (PID ${HEALTH_PID})." info "You will see a status banner when Coolify is ready (or after ${HEALTH_TIMEOUT}s timeout)." echo ""