#!/usr/bin/env bash # DeckForge Fast Update Script # For code-only updates: copies files into running containers, no Docker rebuild. # Run ./deploy.sh only when Dockerfile or dependencies change. set -euo pipefail GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' info() { echo -e "${GREEN}[update]${NC} $*"; } warn() { echo -e "${YELLOW}[warn]${NC} $*"; } SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" # ── Step 1: Pull latest code ────────────────────────────────────────────────── info "Pulling latest code..." git pull origin main # ── Detect what changed since last pull ────────────────────────────────────── CHANGED=$(git diff HEAD@{1} HEAD --name-only 2>/dev/null || echo "unknown") BACKEND_DEPS_CHANGED=false FRONTEND_DEPS_CHANGED=false FRONTEND_CHANGED=false BACKEND_CHANGED=false if echo "$CHANGED" | grep -q "pyproject.toml\|backend/Dockerfile"; then BACKEND_DEPS_CHANGED=true fi if echo "$CHANGED" | grep -q "package.json\|package-lock.json\|frontend/Dockerfile"; then FRONTEND_DEPS_CHANGED=true fi if echo "$CHANGED" | grep -qE "^frontend/"; then FRONTEND_CHANGED=true fi if echo "$CHANGED" | grep -qE "^backend/"; then BACKEND_CHANGED=true fi export API_PORT WEB_PORT env_val() { local key=$1 def=$2; grep -E "^${key}=" .env 2>/dev/null | cut -d= -f2 | tr -d '"' | head -1 | grep -v '^$' || echo "$def"; } API_PORT=${API_PORT:-$(env_val API_PORT 8000)} WEB_PORT=${WEB_PORT:-$(env_val WEB_PORT 3000)} # ── Backend: hot-copy files if no dep changes (avoids 2min Docker rebuild) ─── if $BACKEND_DEPS_CHANGED; then warn "Backend dependencies changed — run ./deploy.sh for a full rebuild." warn "Continuing with hot-copy anyway (new deps won't be available until full rebuild)." fi if $BACKEND_CHANGED; then API_CONTAINER=$(docker compose -f docker-compose.yml -f docker-compose.prod.yml ps -q api 2>/dev/null | head -1) WORKER_CONTAINER=$(docker compose -f docker-compose.yml -f docker-compose.prod.yml ps -q worker 2>/dev/null | head -1) if [[ -n "$API_CONTAINER" ]]; then info "Hot-copying backend code into containers..." docker cp backend/. "$API_CONTAINER":/app/ [[ -n "$WORKER_CONTAINER" ]] && docker cp backend/. "$WORKER_CONTAINER":/app/ info "Restarting api + worker..." docker compose -f docker-compose.yml -f docker-compose.prod.yml restart api worker info "Running migrations..." sleep 5 docker compose -f docker-compose.yml -f docker-compose.prod.yml \ exec -T api alembic upgrade head || warn "Migration already up to date" else warn "api container not running — falling back to docker build" DOCKER_BUILDKIT=1 docker compose -f docker-compose.yml -f docker-compose.prod.yml build api worker docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d api worker fi fi # ── Frontend: still needs build (Next.js compilation required) ─────────────── if $FRONTEND_DEPS_CHANGED; then warn "Frontend dependencies changed — run ./deploy.sh for a full rebuild." fi if $FRONTEND_CHANGED; then info "Rebuilding frontend (Next.js build required)..." DOCKER_BUILDKIT=1 docker compose -f docker-compose.yml -f docker-compose.prod.yml build web docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d web fi if ! $BACKEND_CHANGED && ! $FRONTEND_CHANGED; then info "No relevant changes. Services are up to date." fi info "Update complete." docker compose -f docker-compose.yml -f docker-compose.prod.yml ps