Co-authored-by: Claude (Opus 4.6) <claude@hermes.local> Co-committed-by: Claude (Opus 4.6) <claude@hermes.local>
101 lines
4.5 KiB
Bash
Executable File
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 ""
|