| # 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" | |