2026-06-15 16:56:55 +02:00
|
|
|
#!/bin/sh
|
|
|
|
|
# Smoke test for the release-channel clean-repo gate in build.sh.
|
|
|
|
|
#
|
|
|
|
|
# Why this exists: the gate only runs on BUILD_CHANNEL=release, so `sh -n`,
|
|
|
|
|
# prettier, and dev builds never exercise it — a broken gate ships green. This
|
|
|
|
|
# test pins the two properties we depend on:
|
|
|
|
|
# 1. assert_clean_repo fails a tree with untracked OR modified files, and
|
|
|
|
|
# passes a clean tree (the porcelain check, not diff-only).
|
|
|
|
|
# 2. check_release_gate is invoked AFTER it is defined in build.sh (guards the
|
|
|
|
|
# call-before-definition regression that aborts release builds with exit 127).
|
|
|
|
|
#
|
|
|
|
|
# Run: sh scripts/test-release-gate.sh
|
|
|
|
|
set -eu
|
|
|
|
|
|
|
|
|
|
SCRIPT_DIR=$(cd "$(dirname "$0")/.." && pwd)
|
|
|
|
|
BUILD_SH="${SCRIPT_DIR}/build.sh"
|
|
|
|
|
TMP=$(mktemp -d "${TMPDIR:-/tmp}/release-gate-test.XXXXXX")
|
|
|
|
|
trap 'rm -rf "${TMP}"' EXIT
|
|
|
|
|
fail=0
|
|
|
|
|
check() { if [ "$1" = "$2" ]; then echo "ok - $3"; else echo "FAIL - $3 (want '$2', got '$1')"; fail=1; fi; }
|
|
|
|
|
|
|
|
|
|
# --- property 2: definition precedes invocation -------------------------------
|
|
|
|
|
_def=$(grep -n '^check_release_gate() {' "${BUILD_SH}" | head -1 | cut -d: -f1)
|
|
|
|
|
_call=$(grep -n '^[[:space:]]*check_release_gate$' "${BUILD_SH}" | head -1 | cut -d: -f1)
|
|
|
|
|
if [ -n "${_def}" ] && [ -n "${_call}" ] && [ "${_call}" -gt "${_def}" ]; then
|
|
|
|
|
echo "ok - check_release_gate invoked after its definition (def ${_def}, call ${_call})"
|
|
|
|
|
else
|
|
|
|
|
echo "FAIL - check_release_gate call/definition order (def '${_def}', call '${_call}')"; fail=1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# --- property 1: assert_clean_repo semantics ----------------------------------
|
|
|
|
|
# Extract the helper from build.sh and exercise it against real temp git repos.
|
|
|
|
|
sed -n '/^assert_clean_repo() {/,/^}/p' "${BUILD_SH}" > "${TMP}/fn.sh"
|
|
|
|
|
. "${TMP}/fn.sh"
|
|
|
|
|
|
|
|
|
|
mkrepo() { d="${TMP}/$1"; mkdir -p "$d"; git -C "$d" init -q; git -C "$d" config user.email t@t; git -C "$d" config user.name t;
|
|
|
|
|
echo base > "$d/file"; git -C "$d" add file; git -C "$d" commit -qm init; printf '%s' "$d"; }
|
|
|
|
|
|
|
|
|
|
clean=$(mkrepo clean)
|
|
|
|
|
_release_errors=0; assert_clean_repo clean "${clean}"; check "${_release_errors}" 0 "clean repo passes"
|
|
|
|
|
|
|
|
|
|
untracked=$(mkrepo untracked); : > "${untracked}/stray.txt"
|
|
|
|
|
_release_errors=0; assert_clean_repo untracked "${untracked}"; check "${_release_errors}" 1 "untracked file fails (porcelain catches it)"
|
|
|
|
|
|
|
|
|
|
modified=$(mkrepo modified); echo changed > "${modified}/file"
|
|
|
|
|
_release_errors=0; assert_clean_repo modified "${modified}"; check "${_release_errors}" 1 "modified tracked file fails"
|
|
|
|
|
|
|
|
|
|
_release_errors=0; assert_clean_repo nogit "${TMP}/does-not-exist"; check "${_release_errors}" 0 "non-git path is skipped"
|
|
|
|
|
|
2026-06-15 18:50:16 +02:00
|
|
|
[ "${fail}" -eq 0 ] && echo "PASS: release gate self-test" || { echo "FAILED"; exit 1; }
|