103 lines
4.7 KiB
Bash
Executable File
103 lines
4.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Regenerate the committed UI-snapshot baseline locally, using Docker.
|
|
#
|
|
# Visual baselines must be rendered in the SAME environment the CI gate uses, or
|
|
# they won't match (fonts/anti-aliasing differ across renderers). This script
|
|
# renders inside the exact digest-pinned Playwright image ui-snapshot.yml runs
|
|
# in, so the baseline it produces is byte-identical to what CI will compare
|
|
# against -- commit it directly.
|
|
#
|
|
# Only Docker is required (no local Node/Python/uv). It:
|
|
# 1. builds the web SPA in a Node 20 container, then
|
|
# 2. compares the whole visual suite in the pinned Playwright image and
|
|
# rewrites only the baselines that drift (or are missing) -- baselines that
|
|
# already match are left byte-for-byte untouched, mirroring the label-driven
|
|
# CI flow (installs the project + Chromium-from-the-image, no browser
|
|
# download).
|
|
#
|
|
# Usage:
|
|
# tests/e2e_ui/visual/regen_baseline_docker.sh [--skip-build]
|
|
#
|
|
# --skip-build Reuse an existing omnigent/server/static/web-ui build (e.g.
|
|
# from a prior `cd web && npm run build`) instead of building
|
|
# in a container. The bundle is platform-independent, so a host
|
|
# build renders the same pixels.
|
|
set -euo pipefail
|
|
|
|
# Keep these in lockstep with ui-snapshot.yml / ui-snapshot-update.yml.
|
|
PW_IMAGE="mcr.microsoft.com/playwright/python:v1.60.0-noble@sha256:8ff591d613b01c884cc488339ed4318b4513eaf0c57a164a878ba49e70e3f384"
|
|
NODE_IMAGE="node:20-bookworm"
|
|
# The pinned digest is a multi-arch manifest, and CI renders the linux/amd64
|
|
# variant. Force it here too so an arm64 host (e.g. Apple Silicon) renders the
|
|
# same Chromium build -- otherwise the local PNG diverges from the gate. On
|
|
# arm64 this runs under emulation (slower; needs Docker's binfmt/qemu).
|
|
PLATFORM="linux/amd64"
|
|
# Match CI's npm pin (.github/actions/setup-node) so the SPA bundle the build
|
|
# produces is identical to the one the gate renders.
|
|
NPM_VERSION="11.12.1"
|
|
BUILD_OUTPUT="omnigent/server/static/web-ui"
|
|
SNAP_ROOT="tests/e2e_ui/visual/snapshots"
|
|
|
|
SKIP_BUILD=false
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--skip-build) SKIP_BUILD=true; shift ;;
|
|
-h|--help) sed -n '2,22p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
|
*) echo "error: unknown argument $1" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
command -v docker >/dev/null || { echo "error: docker is required." >&2; exit 1; }
|
|
cd "$(git rev-parse --show-toplevel)"
|
|
|
|
if [ "$SKIP_BUILD" = true ]; then
|
|
[ -f "$BUILD_OUTPUT/index.html" ] || {
|
|
echo "error: --skip-build but no SPA build at $BUILD_OUTPUT. Build it first or drop the flag." >&2
|
|
exit 1
|
|
}
|
|
echo "Reusing existing SPA build at $BUILD_OUTPUT."
|
|
else
|
|
echo "Building the web SPA (Node container) ..."
|
|
docker run --rm --platform "$PLATFORM" -v "$PWD":/work -w /work/web "$NODE_IMAGE" \
|
|
bash -c "npm install -g npm@${NPM_VERSION} && npm ci --legacy-peer-deps --no-audit --no-fund && npm run build"
|
|
fi
|
|
|
|
echo "Rendering + comparing the baselines in the pinned Playwright image ..."
|
|
# Deliberately NOT --update-snapshots: that rewrites every PNG, churning
|
|
# baselines that still pass (a sub-threshold re-render changes the bytes). Plain
|
|
# compare leaves passing baselines alone and rewrites only the drift. GITHUB_ACTIONS
|
|
# is set so the plugin behaves exactly as the CI gate does: it updates a mismatching
|
|
# baseline IN PLACE (and creates a missing one) under snapshots/, so the git diff
|
|
# below is the real signal. The run "fails" by design on any drift, so `|| true` is
|
|
# expected. UV_PROJECT_ENVIRONMENT lives in the container (not the mounted repo) so
|
|
# no root-owned .venv leaks out.
|
|
docker run --rm --platform "$PLATFORM" -v "$PWD":/work -w /work \
|
|
-e CI=1 \
|
|
-e GITHUB_ACTIONS=true \
|
|
-e OMNIGENT_PW_NO_SANDBOX=1 \
|
|
-e OMNIGENT_SKIP_WEB_UI=true \
|
|
-e UV_PYTHON_PREFERENCE=only-system \
|
|
-e UV_PROJECT_ENVIRONMENT=/opt/uv-venv \
|
|
"$PW_IMAGE" bash -c '
|
|
pip install --quiet uv &&
|
|
uv sync --extra all --extra dev &&
|
|
uv run pytest tests/e2e_ui/visual -m visual \
|
|
-p no:rerunfailures --ui-skip-build
|
|
' || true
|
|
|
|
# Files Docker wrote are root-owned; hand them back so git add works unprivileged.
|
|
# Includes web (node_modules + build intermediates the Node container wrote).
|
|
docker run --rm --platform "$PLATFORM" -v "$PWD":/work "$PW_IMAGE" \
|
|
chown -R "$(id -u):$(id -g)" /work/tests/e2e_ui/visual /work/"$BUILD_OUTPUT" /work/web 2>/dev/null || true
|
|
|
|
echo
|
|
if git diff --quiet -- "$SNAP_ROOT"; then
|
|
echo "Baselines unchanged — they already match this render (or the render failed; check the output above)."
|
|
else
|
|
git --no-pager diff --stat -- "$SNAP_ROOT" || true
|
|
echo
|
|
echo "Updated baseline(s) under: $SNAP_ROOT"
|
|
echo "Next: review the image(s), then commit + push:"
|
|
echo " git add \"$SNAP_ROOT\" && git commit -m 'test(ui-snapshot): update visual baselines' && git push"
|
|
fi
|