mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 23:21:08 +02:00
fix(macmini): auto-rebuild stale sveltekit-base before per-app web builds
NOTE: the previous commit 048184bef carried this commit message but
accidentally bundled an unrelated PickerOverlay refactor instead of
this script change (lint-staged stash interaction). This is the
actual fix.
Per-app web Dockerfiles do `FROM sveltekit-base:local` and do NOT
re-COPY packages/shared-* — those packages are baked into the base
image. So a change to packages/shared-utils, packages/shared-ui, etc.
only reaches the live web app if the base image is also rebuilt.
This bit us THREE times on 2026-04-08 alone:
1. CSP fix in shared-utils ('wasm-unsafe-eval') sat unused in
production for over an hour because every `build-app.sh mana-web`
reused the cached base layer with old shared-utils.
2. The BaseListView export in shared-ui after the ListView
consolidation refactor — mana-web's build failed because Rollup
couldn't resolve the new symbol from the stale base.
3. Same shape, different package, repeatedly during the Gemma 4
migration push.
The pattern is identical every time and the manual workaround
(`build-app.sh --base` first) is something you only think to run if
you already know how the layering works. Make the script catch it.
New `is_base_image_stale` helper compares the base image's `Created`
timestamp against the latest git commit touching paths the base image
actually depends on (packages/, docker/Dockerfile.sveltekit-base,
pnpm-lock.yaml). When building any *-web service, if the image is
stale or missing, the base is rebuilt automatically before the
per-app build kicks off, with the triggering commit's oneline
printed for transparency.
Date parsing handles macOS Docker's local-TZ-offset RFC3339 format
(`...+02:00`, not Z). We strip from char 19 onward and parse the
literal local clock time with BSD date (no -u). GNU date is the
fallback for Linux dev boxes. If parsing fails for any reason we
conservatively force a rebuild rather than risk shipping stale code.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
048184bef0
commit
30766f153e
1 changed files with 60 additions and 2 deletions
|
|
@ -113,6 +113,55 @@ build_base_images() {
|
|||
echo ""
|
||||
}
|
||||
|
||||
# Returns 0 (true) if the sveltekit-base:local image is older than the most
|
||||
# recent commit touching any path that would actually change its contents.
|
||||
#
|
||||
# Why this exists: per-app web Dockerfiles do `FROM sveltekit-base:local` and
|
||||
# do NOT re-copy packages/shared-* — those packages are baked into the base
|
||||
# image. So a change to e.g. packages/shared-utils only reaches the live web
|
||||
# app if the base image is also rebuilt. We learned this the hard way on
|
||||
# 2026-04-08 when a CSP fix in shared-utils sat unused in production for an
|
||||
# hour because every `build-app.sh mana-web` reused the cached base layer.
|
||||
#
|
||||
# Detection: compare the base image's Created timestamp against the last git
|
||||
# commit that touched packages/, the base Dockerfile, or pnpm-lock.yaml. If
|
||||
# any such commit is newer than the image, the image is stale.
|
||||
is_base_image_stale() {
|
||||
# No image at all → definitely needs building
|
||||
if ! $DOCKER image inspect sveltekit-base:local >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
local image_iso image_epoch latest_commit_epoch
|
||||
image_iso=$($DOCKER inspect -f '{{.Created}}' sveltekit-base:local 2>/dev/null)
|
||||
|
||||
# Docker on the Mac Mini emits RFC3339 with the *local* TZ offset, e.g.
|
||||
# "2026-04-08T18:30:12.871278257+02:00". On Linux it's typically a Z
|
||||
# suffix. We strip everything from char 19 onward (fractional + offset),
|
||||
# leaving "2026-04-08T18:30:12", and parse it as LOCAL time — which is
|
||||
# what the original timestamp meant on this host. The GNU fallback can
|
||||
# handle the full string directly because GNU date understands offsets.
|
||||
image_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%S" "${image_iso:0:19}" +%s 2>/dev/null \
|
||||
|| date -d "$image_iso" +%s 2>/dev/null \
|
||||
|| echo 0)
|
||||
|
||||
if [ "$image_epoch" = "0" ]; then
|
||||
# Couldn't parse — be conservative and force a rebuild
|
||||
return 0
|
||||
fi
|
||||
|
||||
# %ct is the committer date as Unix epoch — directly comparable.
|
||||
latest_commit_epoch=$(git -C "$PROJECT_ROOT" log -1 --format=%ct -- \
|
||||
packages/ \
|
||||
docker/Dockerfile.sveltekit-base \
|
||||
pnpm-lock.yaml 2>/dev/null || echo 0)
|
||||
|
||||
if [ "$latest_commit_epoch" -gt "$image_epoch" ]; then
|
||||
return 0 # stale
|
||||
fi
|
||||
return 1 # fresh
|
||||
}
|
||||
|
||||
build_services() {
|
||||
local services=("$@")
|
||||
|
||||
|
|
@ -120,9 +169,18 @@ build_services() {
|
|||
for svc in "${services[@]}"; do
|
||||
case "$svc" in
|
||||
*-web)
|
||||
if ! $DOCKER image inspect sveltekit-base:local >/dev/null 2>&1; then
|
||||
echo "=== Building sveltekit-base (first time) ==="
|
||||
if is_base_image_stale; then
|
||||
if ! $DOCKER image inspect sveltekit-base:local >/dev/null 2>&1; then
|
||||
echo "=== Building sveltekit-base (first time) ==="
|
||||
else
|
||||
local last_commit
|
||||
last_commit=$(git -C "$PROJECT_ROOT" log -1 --oneline -- \
|
||||
packages/ docker/Dockerfile.sveltekit-base pnpm-lock.yaml 2>/dev/null || echo "?")
|
||||
echo "=== Rebuilding sveltekit-base (stale: newer commit touches packages/) ==="
|
||||
echo " Triggering commit: $last_commit"
|
||||
fi
|
||||
$DOCKER build -f "$PROJECT_ROOT/docker/Dockerfile.sveltekit-base" -t sveltekit-base:local "$PROJECT_ROOT"
|
||||
echo ""
|
||||
fi
|
||||
break
|
||||
;;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue