← back to Commercialrealestate

deploy/push-full-kamatera.sh

65 lines

#!/usr/bin/env bash
# push-full-kamatera.sh — COMBINED front-end + serve.js deploy mac -> Kamatera CRCP prod.
#
# WHY (vs push-frontend-kamatera.sh): the global-search feature needs BOTH the front-end
# (public/*.html + global-search.js) AND the new server endpoint (scripts/serve.js: /api/search
# with a snapshot fallback for the DB-less prod box). The frontend-only script deliberately skips
# serve.js because a server change needs a process RESTART (bigger blast radius). This script does
# the server change too — backup, push, RESTART, verify — and aborts safely if it can't restart.
#
# SCOPE: public/*.html,*.js,*.css + scripts/serve.js ONLY. Does NOT touch data/ or .env.
# SAFETY: timestamped remote backup of public/ AND serve.js first (rollback points); rsync has no
#   --delete; if no managed serve.js process is found, it does NOT blind-kill — it stops and tells you.
#
# Usage:  bash deploy/push-full-kamatera.sh [--dry-run]
set -euo pipefail
HOST="root@45.61.58.125"
BASE="/root/public-projects/commercialrealestate"
LOCAL="$(cd "$(dirname "$0")/.." && pwd)"
STAMP="$(date +%Y%m%d-%H%M%S)"
DRY=""; [ "${1:-}" = "--dry-run" ] && DRY="--dry-run"

echo "== CRCP FULL deploy (frontend + serve.js) -> $HOST:$BASE =="
[ -n "$DRY" ] && echo "   (DRY RUN — no files written, no restart)"

# 1) backup public/ + serve.js on the remote (rollback points)
if [ -z "$DRY" ]; then
  ssh -o ConnectTimeout=10 "$HOST" \
    "cp -a '$BASE/public' '$BASE/public.bak-$STAMP' && cp -a '$BASE/scripts/serve.js' '$BASE/scripts/serve.js.bak-$STAMP' && echo '   backups: public.bak-$STAMP , serve.js.bak-$STAMP'"
fi

# 2) push front-end assets (html/js/css), no --delete
rsync -avz $DRY --include='*/' --include='*.html' --include='*.js' --include='*.css' --exclude='*' \
  -e 'ssh -o ConnectTimeout=10' "$LOCAL/public/" "$HOST:$BASE/public/"

# 3) push serve.js (server logic)
rsync -avz $DRY -e 'ssh -o ConnectTimeout=10' "$LOCAL/scripts/serve.js" "$HOST:$BASE/scripts/serve.js"

# 4) RESTART the node app so the new serve.js takes effect. Auto-detect the manager; abort safely
#    (no blind kill) if none is found so we never leave prod down.
if [ -z "$DRY" ]; then
  ssh -o ConnectTimeout=10 "$HOST" bash -s <<'REMOTE'
set -e
APP="/root/public-projects/commercialrealestate"
if command -v pm2 >/dev/null 2>&1 && pm2 jlist 2>/dev/null | grep -q "commercialrealestate\|cre-viewer\|serve.js"; then
  NAME=$(pm2 jlist | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{try{const a=JSON.parse(s);const m=a.find(p=>/commercialreal|cre-viewer|serve/.test(p.name)||/serve\.js/.test((p.pm2_env&&p.pm2_env.pm_exec_path)||""));process.stdout.write(m?m.name:"")}catch(e){}})' 2>/dev/null)
  [ -n "$NAME" ] && { pm2 restart "$NAME" >/dev/null && echo "   restarted via pm2: $NAME"; } || echo "   pm2 present but no matching app — MANUAL RESTART NEEDED"
elif systemctl list-units --type=service 2>/dev/null | grep -qiE 'crcp|commercialreal|cre-viewer'; then
  SVC=$(systemctl list-units --type=service --plain --no-legend 2>/dev/null | grep -iE 'crcp|commercialreal|cre-viewer' | awk '{print $1}' | head -1)
  systemctl restart "$SVC" && echo "   restarted via systemd: $SVC"
else
  echo "   ⚠ NO managed serve.js process found (pm2/systemd). Files are pushed; RESTART MANUALLY:"
  echo "     cd $APP && (pkill -f 'node.*serve.js'; sleep 1; setsid nohup node scripts/serve.js >/tmp/crcp-serve.log 2>&1 &)"
  exit 3
fi
REMOTE
fi

# 5) verify the new endpoint is live
if [ -z "$DRY" ]; then
  echo "== verify:"
  echo "   curl -s 'https://crcp.agentabrams.com/api/search?q=torrance' | head -c 200"
  echo "   curl -sI https://crcp.agentabrams.com/global-search.js | grep -i 'HTTP\\|last-modified'"
fi
echo "== done =="