Files
TX/scripts/redeploy.sh
T
riyadhafraa 1659dc4b68 Task #589: Live build stamp + server start time in System Updates panel
Problem: After `git pull && docker compose up -d --build api` on the
Mac, the admin → System Updates panel kept showing the same version
(0.1.0-dev) and the same build (20260517.b5efd9eb) because both come
from version.json, a hand-edited file that nothing rewrites on every
build. No visible signal that a new image was actually running.

Two independent signals were added — neither needs editing version.json
by hand:

1) Auto-stamp version.json at Docker build time
   - docker/api-server.Dockerfile: new ARGs GIT_SHA and BUILD_DATE.
     A `node -e` step rewrites version.json's `build` field to
     `${YYYYMMDDTHHmm}.${sha}` (e.g. 20260518T1042.a34eb5f5). When
     the args are missing/"unknown", version.json is left untouched
     so plain `docker build` and Replit `pnpm dev` still work.
   - docker-compose.yml: api.build.args wires through GIT_SHA and
     BUILD_DATE with `${GIT_SHA:-unknown}` fallbacks.
   - scripts/redeploy.sh: exports GIT_SHA (git rev-parse --short HEAD)
     and BUILD_DATE (date -u +%Y-%m-%dT%H:%M:%SZ) before `docker
     compose build`, so the helper script just works.

2) startedAt timestamp from the API
   - artifacts/api-server/src/routes/system.ts: SERVER_STARTED_AT
     captured at module load (frozen for the process lifetime) and
     added to every branch of GET /system/version (not-configured,
     error, invalid-version, up-to-date, update-available, catch).
   - lib/api-spec/openapi.yaml: added `startedAt: date-time` to
     SystemVersionResponse (required). Regenerated api-client-react
     and api-zod via `pnpm --filter @workspace/api-spec run codegen`.

3) Admin UI surfacing both signals
   - artifacts/tx-os/src/pages/admin.tsx: new formatBuildStamp parses
     `YYYYMMDD[THHmm].sha` and renders a localized date next to the
     raw token. A new "Server started" line below the build number
     formats the boot timestamp via the existing formatChecked helper.
   - artifacts/tx-os/src/locales/{en,ar}.json: added
     admin.systemUpdates.serverStartedAt ("Server started" /
     "بدأ تشغيل الخادم").

4) Docs
   - replit.md: documented how to verify a real redeploy via the
     System Updates panel and the manual one-liner for `docker
     compose build` without the helper script.

Verified: codegen succeeds, API workflow restarted clean, Vite served
fine. Pre-existing typecheck errors in push.ts and font-settings are
unrelated and untouched.

Mac next steps:
  cd ~/Downloads/TX && git pull && ./scripts/redeploy.sh
Then open admin → System Updates: build line should show a new
`YYYYMMDDTHHmm.sha` stamp and "Server started" should reflect the
new boot time.
2026-05-18 10:39:17 +00:00

103 lines
3.5 KiB
Bash
Executable File

#!/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/4 git pull"
git pull --ff-only
else
step "1/4 git pull (skipped via --no-pull)"
fi
step "2/5 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/5 docker compose run --rm migrate (schema push + tolerant seed)"
"${DC[@]}" run --rm migrate
step "4/5 explicit seed pass (fails hard on seed regressions)"
"${DC[@]}" run --rm --no-deps --entrypoint "" migrate \
pnpm --filter @workspace/scripts run seed
step "5/5 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."