Files
padhle/supabase-project/tests/test-upgrades-manifest.sh
T
2026-09-15 04:08:55 -04:00

91 lines
3.5 KiB
Bash

#!/bin/sh
#
# Validate the upgrade manifest (upgrades.json), which update.sh reads with jq.
#
# - json: upgrades.json is valid JSON
# - keys: top-level keys are bare-semver versions (e.g. "0.7.0"), plus the
# optional "_schema" documentation block
# - schema: each version-keyed entry has only known fields, with valid types
# (an unknown/misspelled key like "breakng" would silently disarm
# its gate, so it is rejected here)
# - gate: any non-null "gate" points at a script that exists in the repo
#
# The manifest is the source of truth for gating; the CHANGELOG is display only,
# so this test deliberately does NOT cross-check the two. Requires jq (already a
# runtime dependency of update.sh); no yq, no generation step.
#
# Usage:
# sh tests/test-upgrades-manifest.sh # run from the docker/ directory
#
set -eu
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
DOCKER_DIR=$(dirname "$SCRIPT_DIR")
cd "$DOCKER_DIR"
JSON=upgrades.json
command -v jq >/dev/null 2>&1 || { echo "ERROR: jq is required"; exit 1; }
[ -f "$JSON" ] || { echo "ERROR: $JSON missing"; exit 1; }
TMP=$(mktemp -d)
trap 'rm -rf "$TMP"' EXIT INT TERM
PASS=0; FAIL=0
ok() { PASS=$((PASS+1)); printf " ok - %s\n" "$1"; }
bad() { FAIL=$((FAIL+1)); printf " FAIL - %s\n" "$1"; }
echo ""
echo "=== upgrades.json is valid JSON ==="
if jq -e . "$JSON" >/dev/null 2>"$TMP/err"; then
ok "upgrades.json parses"
else
bad "upgrades.json is not valid JSON: $(cat "$TMP/err" 2>/dev/null)"
echo "=== Result: $PASS passed, $FAIL failed ==="; exit 1
fi
echo ""
echo "=== top-level keys are versions (or _schema) ==="
for k in $(jq -r 'keys[]' "$JSON"); do
case "$k" in
_schema) ok "doc block '_schema' present" ;;
[0-9]*.[0-9]*) ok "version key $k" ;;
*) bad "unexpected top-level key '$k' (want bare semver like 0.7.0)" ;;
esac
done
echo ""
echo "=== version-keyed entries have only known fields, with valid types ==="
for k in $(jq -r 'keys[]' "$JSON"); do
case "$k" in [0-9]*.[0-9]*) ;; *) continue ;; esac
errs=$(jq -r --arg k "$k" '.[$k] as $e
| (($e | keys) - ["breaking", "gate", "migration_guide_url", "requires"]) as $unknown
| [ (if ($e.breaking != null) and (($e.breaking|type) != "boolean") then "breaking must be bool" else empty end),
(if ($e.gate != null) and (($e.gate|type) != "string") then "gate must be string|null" else empty end),
(if ($e.migration_guide_url != null) and (($e.migration_guide_url|type) != "string") then "migration_guide_url must be string|null" else empty end),
(if ($e.requires != null) and (($e.requires|type) != "array") then "requires must be array" else empty end),
(if ($unknown | length) > 0 then "unknown field(s) (typo?): " + ($unknown | join(", ")) else empty end)
] | join("; ")' "$JSON")
if [ -z "$errs" ]; then ok "entry $k valid"; else bad "entry $k: $errs"; fi
done
echo ""
echo "=== gate scripts referenced by entries exist ==="
checked=0
for k in $(jq -r 'keys[]' "$JSON"); do
case "$k" in [0-9]*.[0-9]*) ;; *) continue ;; esac
gate=$(jq -r --arg k "$k" '.[$k].gate // empty' "$JSON")
[ -n "$gate" ] || continue
checked=$((checked+1))
if [ -f "$gate" ]; then
ok "gate for $k exists: $gate"
else
bad "gate for $k missing: $gate"
fi
done
[ "$checked" = 0 ] && echo " (no entries reference a gate script)"
echo ""
echo "=== Result: $PASS passed, $FAIL failed ==="
[ "$FAIL" = 0 ] || exit 1