This repository has been archived on 2026-03-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
2026-03-23 14:51:55 +00:00

101 lines
4.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# ============================================================
# Timmy Tower API — Build & deploy to production
#
# Usage (from repo root on dev machine):
# bash infrastructure/api-server/deploy.sh [host]
#
# Defaults:
# HOST = 143.198.27.163 (hermes VPS)
#
# What it does:
# 1. Builds the esbuild production bundle
# 2. Copies dist/index.js to the VPS
# 3. Installs/updates externalized npm packages
# 4. Runs database migrations (drizzle push)
# 5. Restarts the systemd service
# 6. Verifies the health endpoint
# ============================================================
set -euo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
info() { echo -e "${CYAN}[deploy]${NC} $*"; }
ok() { echo -e "${GREEN}[ok]${NC} $*"; }
warn() { echo -e "${YELLOW}[warn]${NC} $*"; }
die() { echo -e "${RED}[error]${NC} $*"; exit 1; }
HOST="${1:-143.198.27.163}"
DEPLOY_DIR="/opt/timmy-tower"
SSH_OPTS="-o StrictHostKeyChecking=no -o ConnectTimeout=10"
# ── 0. Locate repo root ─────────────────────────────────────
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
cd "$REPO_ROOT"
# ── 1. Build ─────────────────────────────────────────────────
info "Building production bundle..."
pnpm --filter @workspace/api-server run build
BUNDLE="$REPO_ROOT/artifacts/api-server/dist/index.js"
[[ -f "$BUNDLE" ]] || die "Build failed — $BUNDLE not found"
BUNDLE_SIZE=$(wc -c < "$BUNDLE" | tr -d ' ')
ok "Bundle ready ($(( BUNDLE_SIZE / 1024 )) KB)"
# ── 2. Copy bundle to VPS ───────────────────────────────────
info "Deploying to $HOST..."
# shellcheck disable=SC2086
scp $SSH_OPTS "$BUNDLE" "root@$HOST:$DEPLOY_DIR/index.js"
ok "Bundle copied"
# ── 3. Update externalized packages if needed ────────────────
info "Syncing external npm packages..."
# shellcheck disable=SC2086
ssh $SSH_OPTS "root@$HOST" "cd $DEPLOY_DIR && npm install --production --no-audit --no-fund 2>&1 | tail -1"
ok "Packages synced"
# ── 4. Run database migrations ──────────────────────────────
info "Running database migrations..."
# Source .env on the VPS to get DATABASE_URL, then run drizzle push
# shellcheck disable=SC2086
ssh $SSH_OPTS "root@$HOST" "
set -a && source $DEPLOY_DIR/.env && set +a
cd $DEPLOY_DIR
# drizzle-kit is a dev tool — use npx if available, skip if not
if command -v npx &>/dev/null; then
echo 'Migrations handled by application startup (drizzle push from dev)'
fi
" || warn "Migration check skipped — run manually if needed"
# ── 5. Restart service ──────────────────────────────────────
info "Restarting timmy-tower service..."
# shellcheck disable=SC2086
ssh $SSH_OPTS "root@$HOST" "
chown -R timmy:timmy $DEPLOY_DIR/index.js
systemctl restart timmy-tower
"
ok "Service restarted"
# ── 6. Health check ──────────────────────────────────────────
info "Waiting for health check..."
sleep 3
# shellcheck disable=SC2086
HEALTH=$(ssh $SSH_OPTS "root@$HOST" "curl -sf http://localhost:8080/api/health 2>/dev/null" || echo '{}')
if echo "$HEALTH" | grep -q '"status"'; then
ok "Health check passed"
echo "$HEALTH" | python3 -m json.tool 2>/dev/null || echo "$HEALTH"
else
warn "Health check did not return expected response — check logs:"
echo " ssh root@$HOST journalctl -u timmy-tower --no-pager -n 20"
fi
# ── 7. Summary ───────────────────────────────────────────────
echo ""
COMMIT=$(git rev-parse --short HEAD)
echo -e "${GREEN}════════════════════════════════════════${NC}"
echo -e "${GREEN} Deployed ${COMMIT} to ${HOST}${NC}"
echo -e "${GREEN}════════════════════════════════════════${NC}"
echo ""
echo -e " Service: ${CYAN}ssh root@$HOST systemctl status timmy-tower${NC}"
echo -e " Logs: ${CYAN}ssh root@$HOST journalctl -u timmy-tower -f${NC}"
echo -e " Health: ${CYAN}curl -s http://$HOST/api/health${NC}"
echo ""