#!/usr/bin/env bash # Tx OS — redeploy after `git pull` on the Mac (or any Docker host). # # Why this exists: # The SPA is baked into the `web` (nginx) image at build time, and the # API binary is baked into the `api` image. `docker compose up -d` on # its own re-uses the existing images, so a plain `git pull` will NOT # pick up new front-end assets (e.g. service tile images), code # changes, or DB-seed updates. # # What it does: # 1. git pull — fast-forward the working tree (skipped with --no-pull) # 2. docker compose build api web # — rebuild both images so source + static assets are fresh # 3. docker compose run --rm migrate # — apply Drizzle schema (migrate.sh also runs the seed, # but tolerates seed failures — see step 4) # 4. docker compose run --rm --entrypoint "" --no-deps migrate \ # pnpm --filter @workspace/scripts run seed # — explicit seed pass that fails hard if the seed # errors. Catches new-app / renamed-app regressions # that migrate.sh would otherwise swallow. # 5. docker compose up -d # — restart api + web with the new images # # Safe to re-run. Each step is idempotent. set -euo pipefail PULL=1 for arg in "$@"; do case "$arg" in --no-pull) PULL=0 ;; -h|--help) sed -n '2,27p' "$0" exit 0 ;; *) echo "Unknown argument: $arg" >&2 echo "Usage: $0 [--no-pull]" >&2 exit 2 ;; esac done # Resolve the repo root so the script works no matter where it's invoked from. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" cd "$REPO_ROOT" if [ ! -f docker-compose.yml ]; then echo "[redeploy] error: docker-compose.yml not found in $REPO_ROOT" >&2 exit 1 fi if ! command -v docker >/dev/null 2>&1; then echo "[redeploy] error: docker CLI not found in PATH" >&2 exit 1 fi # Pick `docker compose` (v2) and fall back to `docker-compose` (v1) so this # works on older hosts. if docker compose version >/dev/null 2>&1; then DC=(docker compose) elif command -v docker-compose >/dev/null 2>&1; then DC=(docker-compose) else echo "[redeploy] error: neither 'docker compose' nor 'docker-compose' is available" >&2 exit 1 fi step() { echo; echo "==> $*"; } if [ "$PULL" -eq 1 ]; then step "1/6 git pull" git pull --ff-only else step "1/6 git pull (skipped via --no-pull)" fi step "2/6 docker compose build api web (rebuilds SPA + API images)" # Stamp the API image with the current git SHA + UTC build time so the # admin "System Updates" panel shows visible proof that the new image # is actually running (instead of the old, hand-edited version.json). # Both are read inside docker/api-server.Dockerfile as ARGs. export GIT_SHA="$(git rev-parse --short HEAD 2>/dev/null || echo unknown)" export BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)" echo "[redeploy] GIT_SHA=$GIT_SHA BUILD_DATE=$BUILD_DATE" "${DC[@]}" build api web step "3/6 docker compose run --rm migrate (schema push + tolerant seed)" "${DC[@]}" run --rm migrate step "4/6 explicit seed pass (fails hard on seed regressions)" "${DC[@]}" run --rm --no-deps --entrypoint "" migrate \ pnpm --filter @workspace/scripts run seed step "5/6 one-shot data migrations (idempotent)" # #603: bump seeded app tile colours on existing installs. The seed # step above uses onConflictDoNothing for `slug`, so already-seeded # rows keep their old colours forever without this. The script only # touches rows that still hold the OLD default — admin customisations # from the Apps editor are left alone. "${DC[@]}" run --rm --no-deps --entrypoint "" migrate \ pnpm --filter @workspace/scripts run update-app-colors step "6/6 docker compose up -d (restart with the new images)" "${DC[@]}" up -d echo echo "[redeploy] done. Verify in a browser; hard-refresh once to bust the SPA cache."