test(19.3-05): gate plugins, layers and docs stages
- plugins: vet and -short in FAQ, menu and Journal, purge helper and deprecated-key suites by name; their Docker admin purge suites in docker - layers: cmp of the shared purge files, 11 sitePurge: names per layer - docs: TestDocsTree, docs:build --check, no consuming application named in framework lines added since the phase base
This commit is contained in:
@@ -117,6 +117,51 @@ DOCKER_COOLER_TESTS=(
|
||||
TestSiteCacheAfterCommitOnly
|
||||
TestSiteCacheFailureNeverFails
|
||||
)
|
||||
DOCKER_FAQ_TESTS=(TestFaqAdminPurgesSiteCache)
|
||||
DOCKER_MENU_TESTS=(TestMenuAdminPurgesSiteCache)
|
||||
DOCKER_JOURNAL_TESTS=(
|
||||
TestCategoriesAdminPurgesSiteCache
|
||||
TestPostsAdminPurgesSiteCache
|
||||
TestCategoriesAdminFrameworkKeysWin
|
||||
)
|
||||
|
||||
# plugins stage: the purge helpers and the Journal's deprecated keys (-short).
|
||||
FAQ_CONTROLLERS_TESTS=(
|
||||
TestPurgeSiteCacheWithoutTx
|
||||
TestPurgeSiteCacheWithoutPurger
|
||||
)
|
||||
MENU_CONTROLLERS_TESTS=("${FAQ_CONTROLLERS_TESTS[@]}")
|
||||
JOURNAL_ROOT_TESTS=(
|
||||
TestSiteCacheFrameworkKeysWin
|
||||
TestSiteCacheAliasKeysDeprecated
|
||||
TestSiteCacheNoKeys
|
||||
)
|
||||
JOURNAL_CLASSES_TESTS=(TestSiteCachePurgeConfig TestSiteCachePurgeRequest)
|
||||
|
||||
# layers stage: the shared purge spec, byte-identical in the three layers.
|
||||
LAYER_REQUIRE=(
|
||||
"sitePurge: the shared files match the pinned hashes"
|
||||
"sitePurge: a missing or short token disables the route"
|
||||
"sitePurge: a proxied request is refused before the token is checked"
|
||||
"sitePurge: authorize ok with the token and unauthorized otherwise"
|
||||
"sitePurge: purge removes only nitro:routes: keys"
|
||||
"sitePurge: purge event kinds and slugs"
|
||||
"sitePurge: ok in constant time over sha256 digests, whatever the bearer length"
|
||||
"sitePurge: purge works with a synchronous storage and skips the bare base key"
|
||||
"sitePurge: purge event edge cases"
|
||||
"sitePurge: route answers 404 when disabled or proxied and 401 for a wrong bearer"
|
||||
"sitePurge: route purges, answers the count and logs kind and slug only"
|
||||
)
|
||||
# Files every layer ships byte for byte.
|
||||
LAYER_SHARED=(
|
||||
server/lib/siteCachePurge.ts
|
||||
server/api/__site__/cache/purge.post.ts
|
||||
tests/sitePurge.test.ts
|
||||
)
|
||||
|
||||
# docs stage: names of consuming applications that framework lines added by
|
||||
# this phase must not carry (split so this file does not match itself).
|
||||
APP_NAMES=("fono""teka" "p[lł]yta""rium" "grzy""by" "summercms""io" "wave""path" "stu""dia")
|
||||
|
||||
usage() {
|
||||
cat >&2 <<'EOF'
|
||||
@@ -368,11 +413,6 @@ require_dir() {
|
||||
}
|
||||
}
|
||||
|
||||
not_wired() {
|
||||
echo "refuse: stage $1 is not wired yet" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
run_go() {
|
||||
(cd "$ROOT" && go vet ./...)
|
||||
echo "vet: $ROOT"
|
||||
@@ -400,19 +440,115 @@ run_docker() {
|
||||
go_named "$ROOT" ./modules/cabana "-timeout 20m" "${DOCKER_CABANA_TESTS[@]}"
|
||||
go_named "$ROOT" ./modules/lagoon/attach "-timeout 20m" "${DOCKER_ATTACH_TESTS[@]}"
|
||||
go_named "$ROOT" ./modules/cooler "-timeout 20m" "${DOCKER_COOLER_TESTS[@]}"
|
||||
require_dir "$FAQ_PLUGIN" "FAQ plugin"
|
||||
require_dir "$MENU_PLUGIN" "menu plugin"
|
||||
require_dir "$JOURNAL_PLUGIN" "Journal plugin"
|
||||
go_named "$FAQ_PLUGIN" . "-timeout 20m" "${DOCKER_FAQ_TESTS[@]}"
|
||||
go_named "$MENU_PLUGIN" . "-timeout 20m" "${DOCKER_MENU_TESTS[@]}"
|
||||
go_named "$JOURNAL_PLUGIN" . "-timeout 20m" "${DOCKER_JOURNAL_TESTS[@]}"
|
||||
echo "phase19.3 docker passed"
|
||||
}
|
||||
|
||||
run_plugins() {
|
||||
not_wired plugins
|
||||
require_dir "$FAQ_PLUGIN" "FAQ plugin"
|
||||
require_dir "$MENU_PLUGIN" "menu plugin"
|
||||
require_dir "$JOURNAL_PLUGIN" "Journal plugin"
|
||||
local repo
|
||||
for repo in "$FAQ_PLUGIN" "$MENU_PLUGIN" "$JOURNAL_PLUGIN"; do
|
||||
go -C "$repo" vet ./...
|
||||
echo "vet: $repo"
|
||||
# The Docker suites skip here and run by name in the docker stage.
|
||||
go_short "$repo"
|
||||
done
|
||||
go_named "$FAQ_PLUGIN" ./controllers -short "${FAQ_CONTROLLERS_TESTS[@]}"
|
||||
go_named "$MENU_PLUGIN" ./controllers -short "${MENU_CONTROLLERS_TESTS[@]}"
|
||||
go_named "$JOURNAL_PLUGIN" . -short "${JOURNAL_ROOT_TESTS[@]}"
|
||||
go_named "$JOURNAL_PLUGIN" ./classes -short "${JOURNAL_CLASSES_TESTS[@]}"
|
||||
echo "phase19.3 plugins passed"
|
||||
}
|
||||
|
||||
# pnpm_tap runs `pnpm -C <dir> test` (node --test, TAP) and checks the output
|
||||
# with detect_tap. It never installs anything: when pnpm refuses to run
|
||||
# because node_modules was installed against another store, it prints the
|
||||
# offline, frozen-lockfile recovery and fails.
|
||||
pnpm_tap() {
|
||||
local dir="$1" log rc=0 dc=0
|
||||
log="$(mktemp)"
|
||||
pnpm -C "$dir" test >"$log" 2>&1 || rc=$?
|
||||
if grep -q 'ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY' "$log"; then
|
||||
rm -f "$log"
|
||||
cat >&2 <<MSG
|
||||
refuse: pnpm wants to reinstall node_modules in $dir (store-dir mismatch) and
|
||||
aborted without a TTY. Restore the local install without changing the lockfile:
|
||||
pnpm -C "$dir" install --frozen-lockfile --offline --store-dir <the store named in node_modules/.modules.yaml without /v11>
|
||||
then run this stage again.
|
||||
MSG
|
||||
return 1
|
||||
fi
|
||||
detect_tap "$log" || dc=$?
|
||||
if [[ "$rc" -ne 0 || "$dc" -ne 0 ]]; then
|
||||
grep -E '^\s*(not ok|# )|Error' "$log" | tail -n 40 >&2 || true
|
||||
rm -f "$log"
|
||||
echo "refuse: pnpm test in $dir (test=$rc detect=$dc)" >&2
|
||||
return 1
|
||||
fi
|
||||
echo "tap: $(grep -E '^# (tests|pass|fail) ' "$log" | tr '\n' ' ')in $dir"
|
||||
rm -f "$log"
|
||||
}
|
||||
|
||||
run_layers() {
|
||||
not_wired layers
|
||||
require_dir "$FAQ_LAYER" "FAQ layer"
|
||||
require_dir "$MENU_LAYER" "menu layer"
|
||||
require_dir "$JOURNAL_LAYER" "Journal layer"
|
||||
local file layer
|
||||
for file in "${LAYER_SHARED[@]}"; do
|
||||
for layer in "$MENU_LAYER" "$JOURNAL_LAYER"; do
|
||||
if ! cmp -s "$FAQ_LAYER/$file" "$layer/$file"; then
|
||||
echo "refuse: $file differs between $FAQ_LAYER and $layer (the shared files ship byte for byte)" >&2
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
done
|
||||
echo "cmp: ${#LAYER_SHARED[@]} shared files identical in the three layers"
|
||||
for layer in "$FAQ_LAYER" "$MENU_LAYER" "$JOURNAL_LAYER"; do
|
||||
REQUIRE_NAMES="$(printf '%s\n' "${LAYER_REQUIRE[@]}")" pnpm_tap "$layer"
|
||||
done
|
||||
echo "phase19.3 layers passed"
|
||||
}
|
||||
|
||||
# phase_base prints the parent of the phase's first commit; PHASE193_BASE
|
||||
# overrides it.
|
||||
phase_base() {
|
||||
if [[ -n "${PHASE193_BASE:-}" ]]; then
|
||||
echo "$PHASE193_BASE"
|
||||
return
|
||||
fi
|
||||
local first
|
||||
first="$(git -C "$ROOT" log --format=%H --reverse --grep='(19\.3' | head -n 1)"
|
||||
if [[ -z "$first" ]]; then
|
||||
echo "refuse: no commit of phase 19.3 found; set PHASE193_BASE" >&2
|
||||
return 1
|
||||
fi
|
||||
echo "${first}^"
|
||||
}
|
||||
|
||||
run_docs() {
|
||||
not_wired docs
|
||||
go_named "$ROOT" ./cmd/summer "" TestDocsTree
|
||||
(cd "$ROOT" && go run ./cmd/summer docs:build --check)
|
||||
local base pattern hits
|
||||
base="$(phase_base)"
|
||||
pattern="$(IFS='|'; echo "${APP_NAMES[*]}")"
|
||||
# Lines this phase added to the framework (committed or not), planning
|
||||
# docs excluded.
|
||||
hits="$(git -C "$ROOT" diff "$base" -- . ':(exclude).planning' |
|
||||
grep -E '^\+' | grep -vE '^\+\+\+ ' | grep -inE "$pattern" || true)"
|
||||
if [[ -n "$hits" ]]; then
|
||||
printf '%s\n' "$hits" | head -n 20 >&2
|
||||
echo "refuse: framework lines added since $base name a consuming application" >&2
|
||||
return 1
|
||||
fi
|
||||
echo "names: no consuming application named in framework lines since $base"
|
||||
echo "phase19.3 docs passed"
|
||||
}
|
||||
|
||||
run_all() {
|
||||
|
||||
Reference in New Issue
Block a user