pounce/deploy.sh
Yves Gugger 3e067a9792
Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
fix: rsync compatibility for macOS
2025-12-13 17:00:48 +01:00

187 lines
6.4 KiB
Bash
Executable File

#!/bin/bash
# ============================================================================
# POUNCE ZERO-DOWNTIME DEPLOY SCRIPT
# - Builds locally first (optional)
# - Syncs only changed files
# - Hot-reloads backend without full restart
# - Rebuilds frontend in background
# ============================================================================
set -e
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
RED='\033[0;31m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Server config
SERVER_USER="user"
SERVER_HOST="10.42.0.73"
SERVER_PATH="/home/user/pounce"
SERVER_PASS="user"
# Parse flags
QUICK_MODE=false
BACKEND_ONLY=false
FRONTEND_ONLY=false
while [[ "$#" -gt 0 ]]; do
case $1 in
-q|--quick) QUICK_MODE=true ;;
-b|--backend) BACKEND_ONLY=true ;;
-f|--frontend) FRONTEND_ONLY=true ;;
*) COMMIT_MSG="$1" ;;
esac
shift
done
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
echo -e "${BLUE} POUNCE ZERO-DOWNTIME DEPLOY ${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
if $QUICK_MODE; then
echo -e "${CYAN}⚡ Quick mode: Skipping git, only syncing changes${NC}"
fi
if $BACKEND_ONLY; then
echo -e "${CYAN}🔧 Backend only mode${NC}"
fi
if $FRONTEND_ONLY; then
echo -e "${CYAN}🎨 Frontend only mode${NC}"
fi
# Step 1: Git (unless quick mode)
if ! $QUICK_MODE; then
echo -e "\n${YELLOW}[1/4] Git operations...${NC}"
# Check for changes
if git diff --quiet && git diff --staged --quiet; then
echo " No changes to commit"
else
git add -A
if [ -z "$COMMIT_MSG" ]; then
COMMIT_MSG="Deploy: $(date '+%Y-%m-%d %H:%M')"
fi
git commit -m "$COMMIT_MSG" || true
echo " ✓ Committed: $COMMIT_MSG"
fi
git push origin main 2>/dev/null && echo " ✓ Pushed to git.6bit.ch" || echo " ⚠ Push failed or nothing to push"
else
echo -e "\n${YELLOW}[1/4] Skipping git (quick mode)${NC}"
fi
# Step 2: Sync files (only changed)
echo -e "\n${YELLOW}[2/4] Syncing changed files...${NC}"
RSYNC_OPTS="-avz --delete"
if ! $BACKEND_ONLY; then
echo " Frontend:"
sshpass -p "$SERVER_PASS" rsync $RSYNC_OPTS \
--exclude 'node_modules' \
--exclude '.next' \
--exclude '.git' \
frontend/ $SERVER_USER@$SERVER_HOST:$SERVER_PATH/frontend/ 2>&1 | sed 's/^/ /'
fi
if ! $FRONTEND_ONLY; then
echo " Backend:"
sshpass -p "$SERVER_PASS" rsync $RSYNC_OPTS \
--exclude '__pycache__' \
--exclude '.pytest_cache' \
--exclude 'venv' \
--exclude '.git' \
--exclude '*.pyc' \
--exclude '.env' \
--exclude '*.db' \
backend/ $SERVER_USER@$SERVER_HOST:$SERVER_PATH/backend/ 2>&1 | sed 's/^/ /'
fi
# Step 3: Reload backend (graceful, no restart)
if ! $FRONTEND_ONLY; then
echo -e "\n${YELLOW}[3/4] Reloading backend (graceful)...${NC}"
sshpass -p "$SERVER_PASS" ssh $SERVER_USER@$SERVER_HOST << 'BACKEND_EOF'
# Signal uvicorn to reload (if running with --reload)
# Otherwise, just check it's running
BACKEND_PID=$(pgrep -f 'uvicorn app.main:app' | head -1)
if [ -n "$BACKEND_PID" ]; then
# Touch a file to trigger auto-reload if uvicorn has --reload
touch ~/pounce/backend/app/main.py
echo " ✓ Backend reload triggered (PID: $BACKEND_PID)"
else
echo " ⚠ Backend not running, starting..."
cd ~/pounce/backend
source ../venv/bin/activate
nohup uvicorn app.main:app --host 0.0.0.0 --port 8000 > backend.log 2>&1 &
sleep 2
echo " ✓ Backend started"
fi
BACKEND_EOF
else
echo -e "\n${YELLOW}[3/4] Skipping backend (frontend only)${NC}"
fi
# Step 4: Rebuild frontend (in background to minimize downtime)
if ! $BACKEND_ONLY; then
echo -e "\n${YELLOW}[4/4] Rebuilding frontend...${NC}"
sshpass -p "$SERVER_PASS" ssh $SERVER_USER@$SERVER_HOST << 'FRONTEND_EOF'
cd ~/pounce/frontend
# Build new version
echo " Building..."
npm run build 2>&1 | grep -E '(✓|○|λ|Error|error)' | head -10 | sed 's/^/ /'
BUILD_EXIT=$?
if [ $BUILD_EXIT -eq 0 ]; then
# Gracefully restart Next.js
NEXT_PID=$(pgrep -f 'next start' | head -1)
if [ -n "$NEXT_PID" ]; then
echo " Restarting Next.js (PID: $NEXT_PID)..."
kill $NEXT_PID 2>/dev/null
sleep 1
fi
# Start new instance
nohup npm run start > frontend.log 2>&1 &
sleep 2
# Verify
NEW_PID=$(pgrep -f 'next start' | head -1)
if [ -n "$NEW_PID" ]; then
echo " ✓ Frontend running (PID: $NEW_PID)"
else
echo " ⚠ Frontend may not have started correctly"
fi
else
echo " ✗ Build failed, keeping old version"
fi
FRONTEND_EOF
else
echo -e "\n${YELLOW}[4/4] Skipping frontend (backend only)${NC}"
fi
# Summary
echo -e "\n${GREEN}═══════════════════════════════════════════════════════════════${NC}"
echo -e "${GREEN} ✅ DEPLOY COMPLETE! ${NC}"
echo -e "${GREEN}═══════════════════════════════════════════════════════════════${NC}"
echo -e ""
echo -e " Frontend: ${BLUE}https://pounce.ch${NC} / http://$SERVER_HOST:3000"
echo -e " Backend: ${BLUE}https://pounce.ch/api${NC} / http://$SERVER_HOST:8000"
echo -e ""
echo -e "${CYAN}Quick commands:${NC}"
echo -e " ./deploy.sh -q # Quick sync, no git"
echo -e " ./deploy.sh -b # Backend only"
echo -e " ./deploy.sh -f # Frontend only"
echo -e " ./deploy.sh \"message\" # Full deploy with commit message"