Files
summercms/scripts/check-phase10.2.sh
Jakub Zych 4c7d4cc4b9 test(10.2-02): add nested-layout hygiene gate
- Refuse root package directories, old imports, missing READMEs, and stale status text\n- Validate Go vet and tests across framework and Fonoteka
2026-09-28 13:18:08 +02:00

162 lines
4.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# Phase 10.2 fail-closed gate for the nested framework layout and onboarding.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
APP="$(cd "$ROOT/../fonoteka.go" && pwd)"
NAMES=(backpack boardwalk bonfire bouncer cabana compass festival fetchguard lagoon pact party phrasebook postcard surf tide towel wire wristband)
IMPORT_PREFIX='git.golem15.com/golem15/summercms/'
STALE_STATUS='Pre-alpha. Planning and research. Nothing runs yet.'
usage() {
cat >&2 <<'EOF'
usage:
check-phase10.2.sh --self-test
check-phase10.2.sh --layout
check-phase10.2.sh --imports
check-phase10.2.sh --readmes
check-phase10.2.sh --status
check-phase10.2.sh --go
check-phase10.2.sh --all
EOF
exit 2
}
refuse() {
echo "refuse: $*" >&2
return 1
}
tracked_source_files() {
local repo="$1"
if git -C "$repo" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
git -C "$repo" ls-files -z -- '*.go' '*.tmpl' '*.sh'
return
fi
(
cd "$repo"
find . -path './.planning' -prune -o -type f \( -name '*.go' -o -name '*.tmpl' -o -name '*.sh' \) -print0
)
}
check_layout() {
local root="$1" name
for name in "${NAMES[@]}"; do
if [[ -d "$root/$name" ]]; then
refuse "leftover root dir: $name"
return 1
fi
done
}
check_imports_in() {
local repo="$1" file name
while IFS= read -r -d '' file; do
[[ "$file" != 'scripts/check-phase10.2.sh' ]] || continue
for name in "${NAMES[@]}"; do
if grep -Fq "${IMPORT_PREFIX}${name}" "$repo/$file"; then
refuse "old import: $repo/$file uses ${name} outside modules"
return 1
fi
done
done < <(tracked_source_files "$repo")
}
check_imports() {
check_imports_in "$1" || return 1
check_imports_in "$2"
}
check_readmes() {
local root="$1" name
for name in "${NAMES[@]}"; do
if [[ ! -f "$root/modules/$name/README.md" ]]; then
refuse "missing README: modules/$name/README.md"
return 1
fi
done
}
check_status() {
local root="$1"
if grep -Fq "$STALE_STATUS" "$root/README.md"; then
refuse "stale Status: README still claims nothing runs"
return 1
fi
}
check_hygiene() {
local root="$1" app="$2"
check_layout "$root" || return 1
check_imports "$root" "$app" || return 1
check_readmes "$root" || return 1
check_status "$root" || return 1
}
run_go() {
(cd "$ROOT" && go vet ./...)
(cd "$ROOT" && go test ./...)
(cd "$APP" && go vet ./... ./plugins/golem15/fonoteka/... ./plugins/golem15/user/...)
(cd "$APP" && go test ./... ./plugins/golem15/fonoteka/... ./plugins/golem15/user/...)
echo "phase10.2 go passed"
}
expect_refusal() {
local name="$1" want="$2" root="$3" app="$4" output
if output="$(check_hygiene "$root" "$app" 2>&1)"; then
echo "refuse: self-test accepted planted $name" >&2
exit 1
fi
if ! grep -Fq "$want" <<<"$output"; then
echo "refuse: self-test $name failed for the wrong rule: $output" >&2
exit 1
fi
}
run_self_test() {
bash -n "${BASH_SOURCE[0]}"
local scratch app name
scratch="$(mktemp -d)"
app="$(mktemp -d)"
trap 'rm -rf "$scratch" "$app"' RETURN
cp "$ROOT/README.md" "$scratch/README.md"
for name in "${NAMES[@]}"; do
mkdir -p "$scratch/modules/$name"
cp "$ROOT/modules/$name/README.md" "$scratch/modules/$name/README.md"
done
check_hygiene "$scratch" "$app"
mkdir "$scratch/backpack"
expect_refusal 'leftover root dir' 'leftover root dir' "$scratch" "$app"
rmdir "$scratch/backpack"
printf '%s%s\n' "$IMPORT_PREFIX" backpack >"$scratch/old_import.go"
expect_refusal 'old import' 'old import' "$scratch" "$app"
rm "$scratch/old_import.go"
mv "$scratch/modules/backpack/README.md" "$scratch/modules/backpack/README.saved"
expect_refusal 'missing README' 'missing README' "$scratch" "$app"
mv "$scratch/modules/backpack/README.saved" "$scratch/modules/backpack/README.md"
printf '\n%s\n' "$STALE_STATUS" >>"$scratch/README.md"
expect_refusal 'stale Status' 'stale Status' "$scratch" "$app"
echo "phase10.2 self-test passed"
}
case "${1:-}" in
--self-test) run_self_test ;;
--layout) check_layout "$ROOT" ;;
--imports) check_imports "$ROOT" "$APP" ;;
--readmes) check_readmes "$ROOT" ;;
--status) check_status "$ROOT" ;;
--go) run_go ;;
--all)
check_hygiene "$ROOT" "$APP"
run_go
echo "phase10.2 check passed"
;;
*) usage ;;
esac