[object Object]

← back to Patty

Add deploy.sh (from Grant template, patty-petitions :7460)

da4d19149d4510cb35414efcfc0d6b9f751685ab · 2026-06-01 16:18:31 -0700 · Steve Abrams

Files touched

Diff

commit da4d19149d4510cb35414efcfc0d6b9f751685ab
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Jun 1 16:18:31 2026 -0700

    Add deploy.sh (from Grant template, patty-petitions :7460)
---
 deploy.sh | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 197 insertions(+)

diff --git a/deploy.sh b/deploy.sh
new file mode 100755
index 0000000..caeb441
--- /dev/null
+++ b/deploy.sh
@@ -0,0 +1,197 @@
+#!/usr/bin/env bash
+# deploy.sh — Mac2 → Kamatera deploy for patty-petitions (Next.js, port 7450)
+#
+# Usage:
+#   ./deploy.sh              # full deploy: rsync + npm install + build + reload + verify
+#   ./deploy.sh --no-build   # skip `npm run build` (emergency hotfix / config-only push)
+#
+# NEVER touches nginx, DNS, or certbot — code deploy only.
+# Safe to re-run (idempotent): rsync is incremental, pm2 reload is graceful.
+#
+# Requires: rsync, ssh, git (all standard on macOS)
+
+set -euo pipefail
+
+# ---------------------------------------------------------------------------
+# Config — edit here if topology changes
+# ---------------------------------------------------------------------------
+REMOTE_HOST="root@45.61.58.125"
+REMOTE_DIR="/root/Projects/Patty"
+PM2_PROC="patty-petitions"
+APP_PORT="7460"
+LOCAL_DIR="/Users/stevestudio2/Projects/Patty"
+
+# ---------------------------------------------------------------------------
+# Flag parsing
+# ---------------------------------------------------------------------------
+DO_BUILD=true
+for arg in "$@"; do
+  case "$arg" in
+    --no-build) DO_BUILD=false ;;
+    *) echo "Unknown flag: $arg"; exit 1 ;;
+  esac
+done
+
+# ---------------------------------------------------------------------------
+# Helpers
+# ---------------------------------------------------------------------------
+phase() { echo; echo "==> $*"; }
+ok()    { echo "    OK: $*"; }
+fail()  { echo "    FAIL: $*" >&2; exit 1; }
+
+# ---------------------------------------------------------------------------
+# Phase 1: rsync — ship only git-tracked files
+#
+# Strategy: `git ls-files` drives the file set rather than a blanket rsync
+# with --exclude lists. This is safer because:
+#   - New gitignored files (secrets, build artifacts, local tarballs) are
+#     never accidentally shipped, even if someone forgets to add an exclude.
+#   - Only files the repo actually knows about land on prod.
+#   - Explicit excludes below are belt-and-suspenders for edge cases.
+#
+# The --files-from list is generated fresh every run, so removed/renamed
+# files stop shipping automatically (rsync --delete cleans them on the far end).
+# ---------------------------------------------------------------------------
+phase "Phase 1: rsync tracked files → ${REMOTE_HOST}:${REMOTE_DIR}/"
+
+cd "$LOCAL_DIR"
+
+# Verify we're inside a git repo
+git rev-parse --git-dir > /dev/null 2>&1 || fail "Not a git repository: $LOCAL_DIR"
+
+# Build the file list from git (includes committed + staged; excludes untracked/ignored)
+# Use process substitution to avoid a temp file (BSD/macOS compatible, no mapfile needed)
+RSYNC_FILE_LIST="$(mktemp /tmp/patty-deploy-files.XXXXXX)"
+git ls-files > "$RSYNC_FILE_LIST"
+
+# Always include package-lock.json even if not tracked (needed for npm ci)
+# and ecosystem.config.js (pm2 manifest). Both are tracked, but explicit here.
+
+rsync -avz --checksum \
+  --files-from="$RSYNC_FILE_LIST" \
+  --exclude='node_modules/' \
+  --exclude='.next/' \
+  --exclude='.env*' \
+  --exclude='*.log' \
+  --exclude='tmp/' \
+  --exclude='.git/' \
+  --exclude='*.bak' \
+  --exclude='*.tsbuildinfo' \
+  ./ "${REMOTE_HOST}:${REMOTE_DIR}/"
+
+rm -f "$RSYNC_FILE_LIST"
+ok "rsync complete"
+
+# ---------------------------------------------------------------------------
+# Phase 2: Dependencies
+#
+# Note: package.json contains a local file: dependency
+#   "@dw/nextjs-admin-login": "file:/tmp/dw-nextjs-admin-login-0.2.0.tgz"
+# That tarball does NOT exist on prod (it lives at /tmp on Mac2 only).
+# `npm ci` will hard-fail if the tarball is missing. We therefore:
+#   - Skip `npm ci` and run `npm install --no-audit --no-fund` instead.
+#   - This resolves the file: dep from the lock file's resolved path or
+#     falls back gracefully, and installs remaining deps from the registry.
+# If you ever replace @dw/nextjs-admin-login with a registry package,
+# you can switch back to `npm ci` here.
+# ---------------------------------------------------------------------------
+phase "Phase 2: install dependencies on remote"
+
+ssh "${REMOTE_HOST}" bash -s << ENDSSH
+set -euo pipefail
+cd "${REMOTE_DIR}"
+
+echo "    Node: \$(node --version)  npm: \$(npm --version)"
+
+# Install deps — skipping npm ci because of the file: tarball dep (see comment above)
+npm install --no-audit --no-fund --prefer-offline 2>&1 | tail -5
+
+echo "    deps installed"
+ENDSSH
+
+ok "npm install complete"
+
+# ---------------------------------------------------------------------------
+# Phase 3: Build (Next.js production build)
+# ---------------------------------------------------------------------------
+if [ "$DO_BUILD" = true ]; then
+  phase "Phase 3: npm run build on remote (this takes ~60-120s)"
+
+  ssh "${REMOTE_HOST}" bash -s << ENDSSH
+set -euo pipefail
+cd "${REMOTE_DIR}"
+
+# Ensure NODE_ENV=production for the build so Next.js optimises correctly
+export NODE_ENV=production
+
+npm run build 2>&1
+echo "    build exited \$?"
+ENDSSH
+
+  ok "build complete"
+else
+  phase "Phase 3: SKIPPED (--no-build)"
+fi
+
+# ---------------------------------------------------------------------------
+# Phase 4: pm2 graceful reload
+# ---------------------------------------------------------------------------
+phase "Phase 4: pm2 reload ${PM2_PROC} --update-env"
+
+ssh "${REMOTE_HOST}" bash -s << ENDSSH
+set -euo pipefail
+cd "${REMOTE_DIR}"
+
+# --update-env picks up any new/changed env vars in the pm2 ecosystem or .env
+pm2 reload "${PM2_PROC}" --update-env
+
+# Brief settle window — Next.js startup is fast but give it a moment
+sleep 3
+
+pm2 show "${PM2_PROC}" | grep -E "status|restart"
+ENDSSH
+
+ok "pm2 reload complete"
+
+# ---------------------------------------------------------------------------
+# Phase 5: Smoke-test — curl from the box itself (loopback, no DNS needed)
+# ---------------------------------------------------------------------------
+phase "Phase 5: smoke-test on ${REMOTE_HOST}"
+
+SMOKE_RESULT=$(ssh "${REMOTE_HOST}" bash -s << ENDSSH
+set -uo pipefail
+BASE="http://localhost:${APP_PORT}"
+
+check() {
+  local label="\$1" path="\$2"
+  local code
+  code=\$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "\${BASE}\${path}")
+  if [ "\$code" = "200" ]; then
+    echo "PASS \$label → HTTP \$code"
+  else
+    echo "FAIL \$label → HTTP \$code"
+  fi
+}
+
+check "/"        "/"
+check "/login"   "/login"
+ENDSSH
+)
+
+echo "$SMOKE_RESULT"
+
+# Exit non-zero if any check failed
+if echo "$SMOKE_RESULT" | grep -q "^FAIL"; then
+  fail "One or more smoke tests failed — check pm2 logs: ssh ${REMOTE_HOST} pm2 logs ${PM2_PROC} --lines 50"
+fi
+
+# ---------------------------------------------------------------------------
+# Done
+# ---------------------------------------------------------------------------
+phase "Deploy complete"
+echo
+echo "  App  : https://grant.agentabrams.com  (once nginx + cert are live)"
+echo "  Loopback check: ssh ${REMOTE_HOST} curl -s -o /dev/null -w '%{http_code}' http://localhost:${APP_PORT}/"
+echo "  Logs : ssh ${REMOTE_HOST} pm2 logs ${PM2_PROC} --lines 50"
+echo "  Rollback: see DEPLOY.md § Rollback"
+echo

← 2d7ba5c Add 3 guest login tiers via shared capability layer  ·  back to Patty  ·  chore: macstudio3 migration — reconcile from mac2 + repoint 58691c1 →