Files
OpenShell/build/scripts/cluster-push-component.sh
T
Drew Newberry 07b5ddac33 feat(cluster): speed up local deploy loop with incremental change tracking (!53)
## Summary
- Track last deployed local changes and only redeploy new deltas in auto mode.
- Add per-component fingerprints (server/sandbox/helm) persisted to .cache/cluster-deploy-fast.state.
- Update docs for the new incremental deploy behavior.

```
mise run cluster

....

________________________________________________________
Executed in   75.21 secs      fish           external
   usr time  578.03 millis    0.25 millis  577.78 millis
   sys time  364.45 millis    1.22 millis  363.22 millis
```

with a change to `navigator-sandbox` (triggers rust recompile)

```
⟩ time mise run cluster:deploy
[cluster:deploy] $ build/scripts/cluster-deploy-fast.sh
Change detection took 0s
Fast deploy plan:
  build server:  0
  build sandbox: 1
  helm upgrade:  1

...

________________________________________________________
Executed in   25.88 secs      fish           external
   usr time  618.91 millis    0.24 millis  618.67 millis
   sys time  557.71 millis    1.54 millis  556.18 millis



```

(most time is spent in docker build)

## Test Plan
- mise run pre-commit
2026-02-25 08:34:43 -08:00

61 lines
1.8 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
component=${1:-}
if [ -z "${component}" ]; then
echo "usage: $0 <server|sandbox>" >&2
exit 1
fi
case "${component}" in
server|sandbox)
;;
*)
echo "invalid component '${component}'; expected server or sandbox" >&2
exit 1
;;
esac
IMAGE_TAG=${IMAGE_TAG:-dev}
IMAGE_REPO_BASE=${IMAGE_REPO_BASE:-${NAVIGATOR_REGISTRY:-127.0.0.1:5000/navigator}}
CLUSTER_NAME=${CLUSTER_NAME:-$(basename "$PWD")}
CONTAINER_NAME="navigator-cluster-${CLUSTER_NAME}"
SOURCE_IMAGE="navigator/${component}:${IMAGE_TAG}"
TARGET_IMAGE="${IMAGE_REPO_BASE}/${component}:${IMAGE_TAG}"
source_candidates=(
"navigator/${component}:${IMAGE_TAG}"
"localhost:5000/navigator/${component}:${IMAGE_TAG}"
"127.0.0.1:5000/navigator/${component}:${IMAGE_TAG}"
)
resolved_source_image=""
for candidate in "${source_candidates[@]}"; do
if docker image inspect "${candidate}" >/dev/null 2>&1; then
resolved_source_image="${candidate}"
break
fi
done
if [ -z "${resolved_source_image}" ]; then
echo "missing local image for ${component}:${IMAGE_TAG}" >&2
echo "checked candidates:" >&2
for candidate in "${source_candidates[@]}"; do
echo " ${candidate}" >&2
done
echo "build it first with either:" >&2
echo " mise run docker:build:${component}" >&2
echo " mise run cluster:build" >&2
exit 1
fi
docker tag "${resolved_source_image}" "${TARGET_IMAGE}"
docker push "${TARGET_IMAGE}"
# Evict the stale image from k3s's containerd cache so new pods pull the
# updated image. Without this, k3s uses its cached copy (imagePullPolicy
# defaults to IfNotPresent for non-:latest tags) and pods run stale code.
if docker ps -q --filter "name=${CONTAINER_NAME}" | grep -q .; then
docker exec "${CONTAINER_NAME}" crictl rmi "${TARGET_IMAGE}" >/dev/null 2>&1 || true
fi