#!/bin/bash # Tesseract — VM-side deploy script. Idempotent: safe to re-run. # # Run on the Oracle VM after `git clone`: # cd /opt/tesseract # ./deploy/deploy.sh # # What it does: # 1. Pulls latest code (skip with --no-pull for first run from a clone) # 2. Installs/updates Python deps if requirements.txt changed # 3. Installs/updates Node deps if package-lock.json changed # 4. Builds the SPA into studio/dist/ # 5. Captures the git sha into .env so /api/version is correct # 6. Restarts the systemd unit # # Exits non-zero on any step failure — systemd won't be touched if the build # broke, so the previous version keeps serving. set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT" NO_PULL=0 for arg in "$@"; do case "$arg" in --no-pull) NO_PULL=1 ;; --help|-h) echo "Usage: $0 [--no-pull]" echo " --no-pull skip 'git pull' (use on the first deploy after cloning)" exit 0 ;; esac done # ── 1. Pull ─────────────────────────────────────────────────────────────────── if [ "$NO_PULL" -eq 0 ]; then echo "→ git pull" git pull --ff-only fi # ── 2. Python deps ──────────────────────────────────────────────────────────── # Hash-compare requirements.txt against the last successful install so we # only run pip when something actually changed. REQ="$ROOT/app/requirements.txt" HASH_FILE="$ROOT/.venv/.requirements.sha" CURRENT_HASH=$(sha256sum "$REQ" | cut -d' ' -f1) LAST_HASH=$(cat "$HASH_FILE" 2>/dev/null || echo "") if [ "$CURRENT_HASH" != "$LAST_HASH" ]; then echo "→ pip install (requirements.txt changed)" "$ROOT/.venv/bin/pip" install --upgrade -r "$REQ" echo "$CURRENT_HASH" > "$HASH_FILE" else echo "→ pip install skipped (requirements.txt unchanged)" fi # ── 3. Node deps ────────────────────────────────────────────────────────────── LOCK="$ROOT/studio/package-lock.json" NODE_HASH_FILE="$ROOT/studio/.npm.sha" NODE_CURRENT_HASH=$(sha256sum "$LOCK" | cut -d' ' -f1) NODE_LAST_HASH=$(cat "$NODE_HASH_FILE" 2>/dev/null || echo "") if [ "$NODE_CURRENT_HASH" != "$NODE_LAST_HASH" ]; then echo "→ npm ci (package-lock.json changed)" (cd "$ROOT/studio" && npm ci --no-audit --no-fund) echo "$NODE_CURRENT_HASH" > "$NODE_HASH_FILE" else echo "→ npm install skipped (package-lock.json unchanged)" fi # ── 4. Build SPA ────────────────────────────────────────────────────────────── echo "→ npm run build" (cd "$ROOT/studio" && npm run build) # ── 5. Capture git sha into .env ────────────────────────────────────────────── GIT_SHA=$(git rev-parse --short HEAD) BUILT_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ) if [ -f "$ROOT/.env" ]; then # Replace existing lines if present, append if not. In-place edit via # a tmpfile so a partial write can't corrupt .env. TMP=$(mktemp) grep -v -E '^(TESSERACT_GIT_SHA|TESSERACT_BUILT_AT)=' "$ROOT/.env" > "$TMP" || true echo "TESSERACT_GIT_SHA=$GIT_SHA" >> "$TMP" echo "TESSERACT_BUILT_AT=$BUILT_AT" >> "$TMP" mv "$TMP" "$ROOT/.env" chmod 600 "$ROOT/.env" echo "→ stamped .env with sha=$GIT_SHA" else echo "→ WARNING: .env missing — skipping sha stamp" fi # ── 6. Restart ──────────────────────────────────────────────────────────────── echo "→ systemctl restart tesseract" sudo systemctl restart tesseract # Give systemd a beat to start the worker, then report status. sleep 1 sudo systemctl status tesseract --no-pager --lines=5 echo "" echo "✓ Deploy complete. Tail logs with: sudo journalctl -u tesseract -f"