#!/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" PROJECT_TMP="${SCRIPT_DIR}/tmp" mkdir -p "${PROJECT_TMP}" TMP=$(mktemp -d "${PROJECT_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" [ "${fail}" -eq 0 ] && echo "PASS: release gate self-test" || { echo "FAILED"; exit 1; }