Files
Agent-System/scripts/candidate-images-build.sh
T
weichenandCursor da15eb91b6 feat(infra): Wave 2C same-image digest pin for test/main promote
Build/apply candidate images once, require digests on promote, and keep
pinned env-service from rebuilding divergent images.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 14:44:26 +00:00

111 lines
3.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# Build candidate app (+events) and pi-agent images once for a commit.
# Writes .doc/test-reports/assets/promotion-receipts/<sha>.images.json
#
# Usage:
# ./scripts/candidate-images-build.sh [--commit SHA] [--force]
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "${ROOT}"
COMMIT=""
FORCE=0
while [[ $# -gt 0 ]]; do
case "$1" in
--commit) COMMIT="${2:-}"; shift 2 ;;
--force) FORCE=1; shift ;;
-h|--help)
sed -n '2,8p' "$0" | sed 's/^# \{0,1\}//'
exit 0
;;
*) echo "unknown arg: $1" >&2; exit 1 ;;
esac
done
if [[ -z "${COMMIT}" ]]; then
COMMIT="$(git rev-parse HEAD)"
fi
COMMIT="$(git rev-parse --verify "${COMMIT}^{commit}")"
SHORT="${COMMIT:0:12}"
RECEIPT_DIR="${ROOT}/.doc/test-reports/assets/promotion-receipts"
OUT="${RECEIPT_DIR}/${COMMIT}.images.json"
mkdir -p "${RECEIPT_DIR}"
if [[ -f "${OUT}" && "${FORCE}" -ne 1 ]]; then
echo "images.json already exists (immutable): ${OUT}" >&2
echo "hint: use --force to rebuild local fixtures" >&2
cat "${OUT}"
exit 0
fi
APP_TAG="shuimu-agent-app:candidate-${SHORT}"
EVENTS_TAG="shuimu-agent-events:candidate-${SHORT}"
PI_TAG="shuimu-pi-agent:candidate-${SHORT}"
echo "==> building app/events image ${APP_TAG}..."
docker build -f deploy/app/Dockerfile -t "${APP_TAG}" .
# events binary lives in the same image
docker tag "${APP_TAG}" "${EVENTS_TAG}"
echo "==> building pi-agent image ${PI_TAG}..."
docker build -f deploy/pi-agent/Dockerfile -t "${PI_TAG}" .
image_id() {
docker inspect --format '{{.Id}}' "$1"
}
repo_digest_or_id() {
local name="$1"
local repo
repo="$(docker inspect --format '{{index .RepoDigests 0}}' "${name}" 2>/dev/null || true)"
if [[ -n "${repo}" && "${repo}" != "<no value>" ]]; then
printf '%s' "${repo}"
else
image_id "${name}"
fi
}
APP_ID="$(image_id "${APP_TAG}")"
EVENTS_ID="$(image_id "${EVENTS_TAG}")"
PI_ID="$(image_id "${PI_TAG}")"
APP_DIGEST="$(repo_digest_or_id "${APP_TAG}")"
EVENTS_DIGEST="$(repo_digest_or_id "${EVENTS_TAG}")"
PI_DIGEST="$(repo_digest_or_id "${PI_TAG}")"
RECORDED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
export COMMIT SHORT RECORDED_AT APP_TAG EVENTS_TAG PI_TAG
export APP_ID EVENTS_ID PI_ID APP_DIGEST EVENTS_DIGEST PI_DIGEST OUT
python3 -c '
import json, os
payload = {
"commit": os.environ["COMMIT"],
"recorded_at": os.environ["RECORDED_AT"],
"tags": {
"app": os.environ["APP_TAG"],
"events": os.environ["EVENTS_TAG"],
"pi-agent": os.environ["PI_TAG"],
},
"image_ids": {
"app": os.environ["APP_ID"],
"events": os.environ["EVENTS_ID"],
"pi-agent": os.environ["PI_ID"],
},
"image_digests": {
"app": os.environ["APP_DIGEST"],
"events": os.environ["EVENTS_DIGEST"],
"pi-agent": os.environ["PI_DIGEST"],
},
}
with open(os.environ["OUT"], "w", encoding="utf-8") as f:
json.dump(payload, f, indent=2, ensure_ascii=False)
f.write("\n")
print(os.environ["OUT"])
'
echo "wrote candidate images manifest: ${OUT}"
echo "app=${APP_DIGEST}"
echo "events=${EVENTS_DIGEST}"
echo "pi-agent=${PI_DIGEST}"