fix(scripts): read the sibling application paths and names from the environment in the 19.8 gate (IN-09, quick-261028-rqd)

This commit is contained in:
Jakub Zych
2026-10-28 20:56:23 +01:00
parent 2da42e93f9
commit 10fec478be

View File

@@ -19,10 +19,12 @@
# docs the console decision note names the six charm modules,
# TestDocsTree, summer docs:build --check, no consuming
# application named in the console and logging sources and
# pages, and every command in summer's JSON listing has
# pages (the names come from PHASE198_APP_NAMES; NOT RUN
# without it), and every command in summer's JSON listing has
# examples.
# plugins each swept shared plugin (PLUGINS_ROOT, and the user, golem
# and feedback checkouts under FONOTEKA): vet, short tests, its
# and feedback checkouts under PHASE198_PLUGIN_WORKSPACE, NOT
# RUN without it): vet, short tests, its
# warn-only TestCommandsDocumented by name, a build without the
# workspace (GOWORK=off), and the additive check: in the diff of
# its sweep commit (found by subject) against its parent no
@@ -34,16 +36,19 @@
# the Docker suites of sitemap, faq, menu and the user plugin's
# updates package fail before the sweep too (deferred-items.md)
# and are not part of this gate.
# apps each application: go build ./... (binaries into a temporary
# apps each application in PHASE198_APPS (NOT RUN without it):
# go build ./... (binaries into a temporary
# directory), summer build (this checkout's summer) leaves the
# committed main.go and plugins.gen.go unchanged, and
# bin/<binary> list and help migrate exit 0.
# landing the landing site: nuxt generate, then its node --test suite
# landing the landing site (PHASE198_LANDING_APP and
# PHASE198_LANDING_FRONTEND, NOT RUN without them): nuxt
# generate of the frontend, then its node --test suite
# (TAP: every test passes, none skipped or todo); the
# application's terminal Go tests by name (the end-to-end
# TestTerminalCommands only with SUMMERCMS_TERMINAL_CHECK=1,
# NOT RUN otherwise); the demo
# application's roadmap tests by name and
# NOT RUN otherwise); the demo application's (PHASE198_DEMO_APP,
# NOT RUN without it) roadmap tests by name and
# scripts/sync-roadmap.sh --check against ROADMAP_REF (default
# origin/master: local master carries other sessions' unpushed
# planning commits).
@@ -60,11 +65,29 @@
# docker when a Docker daemon answers (NOT RUN docker otherwise, a failure
# with PHASE198_REQUIRE_DOCKER=1).
#
# Environment overrides (default: the sibling checkouts next to this
# repository): PHASE198_ROOT (this repository), PLUGINS_ROOT (the directory
# holding the sm-*-plugin checkouts), FONOTEKA (the application workspace
# that carries the user, golem and feedback plugin checkouts), DEMO_APP,
# BM_APP, GRZYBY_APP, SUMMERCMSIO_APP, ROADMAP_REF, PHASE198_REQUIRE_DOCKER.
# Environment. This framework script names no consuming application: every
# application path and the names the docs stage refuses come from the
# environment, with no defaults.
# PHASE198_ROOT this repository (default: the script's parent).
# PLUGINS_ROOT the directory holding the shared sm-*-plugin
# checkouts (default: this repository's parent).
# PHASE198_PLUGIN_WORKSPACE the application workspace that carries the
# user, golem and feedback plugin checkouts
# under plugins/golem15/.
# PHASE198_APPS space-separated application checkout paths
# for the apps stage (labelled by basename).
# PHASE198_DEMO_APP the demo application (roadmap check).
# PHASE198_LANDING_APP the landing site application (terminal tests).
# PHASE198_LANDING_FRONTEND the landing site frontend (nuxt generate,
# node --test).
# PHASE198_APP_NAMES space-separated ERE patterns of consuming
# application names the docs stage refuses.
# PHASE198_REQUIRE_SIBLINGS 1 turns every NOT RUN for an unset variable
# above into a failure.
# ROADMAP_REF, PHASE198_REQUIRE_DOCKER, SUMMERCMS_TERMINAL_CHECK.
# A stage or sub-check whose variable is unset prints "NOT RUN <stage>: set
# <VAR>" (a failure with PHASE198_REQUIRE_SIBLINGS=1), the way the docker
# stage treats PHASE198_REQUIRE_DOCKER.
set -euo pipefail
unset FORCE_COLOR
@@ -72,11 +95,10 @@ export NO_COLOR=1
ROOT="${PHASE198_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
PLUGINS_ROOT="${PLUGINS_ROOT:-$ROOT/..}"
FONOTEKA="${FONOTEKA:-$ROOT/../fono""teka.go}"
DEMO_APP="${DEMO_APP:-$ROOT/../sm-demo-app}"
BM_APP="${BM_APP:-$ROOT/../sm-bm-app}"
GRZYBY_APP="${GRZYBY_APP:-$ROOT/../sm-grzybyfunkcjonalne-app}"
SUMMERCMSIO_APP="${SUMMERCMSIO_APP:-$ROOT/../sm-summercmsio-app}"
PLUGIN_WORKSPACE="${PHASE198_PLUGIN_WORKSPACE:-}"
DEMO_APP="${PHASE198_DEMO_APP:-}"
LANDING_APP="${PHASE198_LANDING_APP:-}"
LANDING_FRONTEND="${PHASE198_LANDING_FRONTEND:-}"
# ---------------------------------------------------------------------------
# Required test names. Each list runs with -run '^(a|b|...)$' and every name
@@ -231,9 +253,13 @@ PLUGIN_REPOS=(
"sm-chatvideo-plugin|$PLUGINS_ROOT/sm-chatvideo-plugin"
"sm-forum-plugin|$PLUGINS_ROOT/sm-forum-plugin"
"sm-herald-plugin|$PLUGINS_ROOT/sm-herald-plugin"
"sm-golem-plugin|$FONOTEKA/plugins/golem15/golem"
"sm-feedback-plugin|$FONOTEKA/plugins/golem15/feedback"
"sm-user-plugin|$FONOTEKA/plugins/golem15/user"
)
# The plugin checkouts inside an application workspace
# (PHASE198_PLUGIN_WORKSPACE), "<label>|<path below the workspace>".
WORKSPACE_PLUGIN_REPOS=(
"sm-golem-plugin|plugins/golem15/golem"
"sm-feedback-plugin|plugins/golem15/feedback"
"sm-user-plugin|plugins/golem15/user"
)
# Repositories plan 03 may have deferred: without a sweep commit they print
# NOT SWEPT instead of failing. Plan 03 swept every repository (D-20
@@ -242,14 +268,12 @@ SWEEP_OPTIONAL=()
# The sweep commit's subject carries both strings.
SWEEP_SUBJECT=("console help" "(SummerCMS v")
# apps stage: "<label>|<path>".
APP_REPOS=(
"sm-demo-app|$DEMO_APP"
"sm-bm-app|$BM_APP"
"sm-grzybyfunkcjonalne-app|$GRZYBY_APP"
"sm-summercmsio-app|$SUMMERCMSIO_APP"
"fono""teka.go|$FONOTEKA"
)
# apps stage: "<label>|<path>", from PHASE198_APPS (labelled by basename).
APP_REPOS=()
for app_dir in ${PHASE198_APPS:-}; do
APP_REPOS+=("$(basename "$app_dir")|$app_dir")
done
unset app_dir
# landing stage.
# TestTerminalCommands runs the landing page's commands against the deployed
@@ -258,9 +282,9 @@ APP_REPOS=(
LANDING_TERMINAL_TESTS=(TestTerminalRunScript TestLoadTerminal TestTerminalScript TestTerminalEnv)
ROADMAP_TESTS=(TestRoadmapParse TestRoadmapDeckOrder TestRoadmapNoClientNames TestRoadmapPolishTitles)
# docs stage: names of consuming applications (split so this file does not
# match itself), the decision note and the modules it must name.
APP_NAMES=("p[lł]yta""rium" "fono""teka" "wave""path" "horo""skopia" "bm\\.jakub""zych" "grzyby""funkcjonalne")
# docs stage: the names of consuming applications (ERE patterns from
# PHASE198_APP_NAMES), the decision note and the modules it must name.
read -r -a APP_NAMES <<<"${PHASE198_APP_NAMES:-}"
DECISION_NOTE=".planning/notes/2026-10-21-console-charm-stack.md"
DECISION_NAMES=(
"charm.land/lipgloss/v2" "github.com/charmbracelet/colorprofile" "charm.land/bubbletea/v2"
@@ -406,6 +430,16 @@ go_vet() {
echo "vet: $dir ($*)"
}
# not_run STAGE VAR reports a stage or sub-check skipped because VAR is
# unset: NOT RUN, or a failure with PHASE198_REQUIRE_SIBLINGS=1.
not_run() {
if [[ "${PHASE198_REQUIRE_SIBLINGS:-0}" == "1" ]]; then
echo "FAIL $1: set $2 (PHASE198_REQUIRE_SIBLINGS=1)" >&2
return 1
fi
echo "NOT RUN $1: set $2"
}
require_dir() {
[[ -d "$1" ]] || {
echo "refuse: $2 $1 not found" >&2
@@ -620,6 +654,13 @@ run_self_test() {
fi
rm -rf "$repos"
# The NOT RUN rule for the sibling checkouts: an unset variable skips
# the stage, or fails it with PHASE198_REQUIRE_SIBLINGS=1.
expect_mode apps-not-run 0 "NOT RUN apps: set PHASE198_APPS" --apps PHASE198_APPS= PHASE198_REQUIRE_SIBLINGS=0
expect_mode apps-required 1 "FAIL apps: set PHASE198_APPS" --apps PHASE198_APPS= PHASE198_REQUIRE_SIBLINGS=1
expect_mode landing-not-run 0 "NOT RUN landing roadmap: set PHASE198_DEMO_APP" --landing PHASE198_LANDING_APP= PHASE198_LANDING_FRONTEND= PHASE198_DEMO_APP= PHASE198_REQUIRE_SIBLINGS=0
expect_mode landing-required 1 "FAIL landing site" --landing PHASE198_LANDING_APP= PHASE198_LANDING_FRONTEND= PHASE198_DEMO_APP= PHASE198_REQUIRE_SIBLINGS=1
local mode
for mode in self-test go hello docs plugins apps landing docker all; do
grep -q -- "^ --$mode" "${BASH_SOURCE[0]}" || {
@@ -674,23 +715,27 @@ run_docs() {
go_named "$ROOT" ./cmd/summer "" TestDocsTree
(cd "$ROOT" && go run ./cmd/summer docs:build --check)
local pattern hits files=() scope
pattern="$(IFS='|'; echo "${APP_NAMES[*]}")"
for scope in "${NAME_SCOPE[@]}"; do
[[ -e "$ROOT/$scope" ]] || {
echo "refuse: $scope not found" >&2
if [[ "${#APP_NAMES[@]}" -eq 0 ]]; then
not_run "docs name check" PHASE198_APP_NAMES || return 1
else
pattern="$(IFS='|'; echo "${APP_NAMES[*]}")"
for scope in "${NAME_SCOPE[@]}"; do
[[ -e "$ROOT/$scope" ]] || {
echo "refuse: $scope not found" >&2
return 1
}
while IFS= read -r -d '' f; do
files+=("$f")
done < <(find "$ROOT/$scope" -type f -print0)
done
hits="$(grep -inHIE "$pattern" "${files[@]}" || true)"
if [[ -n "$hits" ]]; then
printf '%s\n' "$hits" | head -n 20 >&2
echo "refuse: a console or logging source or page names a consuming application" >&2
return 1
}
while IFS= read -r -d '' f; do
files+=("$f")
done < <(find "$ROOT/$scope" -type f -print0)
done
hits="$(grep -inHIE "$pattern" "${files[@]}" || true)"
if [[ -n "$hits" ]]; then
printf '%s\n' "$hits" | head -n 20 >&2
echo "refuse: a console or logging source or page names a consuming application" >&2
return 1
fi
echo "names: ${#files[@]} files under ${NAME_SCOPE[*]} checked, no consuming application named"
fi
echo "names: ${#files[@]} files under ${NAME_SCOPE[*]} checked, no consuming application named"
local listing rc=0
listing="$(cd "$ROOT" && go run ./cmd/summer list --format=json)" || rc=$?
if [[ "$rc" -ne 0 ]]; then
@@ -711,8 +756,15 @@ print(f"examples: every one of the {len(commands)} summer commands has examples"
}
run_plugins() {
local entry label dir
for entry in "${PLUGIN_REPOS[@]}"; do
local entry label dir repos=("${PLUGIN_REPOS[@]}")
if [[ -z "$PLUGIN_WORKSPACE" ]]; then
not_run "plugins (${#WORKSPACE_PLUGIN_REPOS[@]} workspace plugin checkouts)" PHASE198_PLUGIN_WORKSPACE || return 1
else
for entry in "${WORKSPACE_PLUGIN_REPOS[@]}"; do
repos+=("${entry%%|*}|$PLUGIN_WORKSPACE/${entry#*|}")
done
fi
for entry in "${repos[@]}"; do
label="${entry%%|*}"
dir="${entry#*|}"
require_dir "$dir" "$label"
@@ -729,11 +781,15 @@ run_plugins() {
return 1
fi
done
echo "phase19.8 plugins passed (${#PLUGIN_REPOS[@]} repositories)"
echo "phase19.8 plugins passed (${#repos[@]} repositories)"
}
run_apps() {
local tmp summer entry label dir binary dirty out
if [[ "${#APP_REPOS[@]}" -eq 0 ]]; then
not_run apps PHASE198_APPS
return
fi
tmp="$(mktemp -d)"
summer="$tmp/summer"
(cd "$ROOT" && go build -o "$summer" ./cmd/summer)
@@ -800,40 +856,49 @@ run_apps() {
}
run_landing() {
local vue="$SUMMERCMSIO_APP/vue-summercmsio-app" log rc=0 dc=0
require_dir "$vue" "landing site"
require_dir "$DEMO_APP" "demo application"
log="$(mktemp)"
if ! npm --prefix "$vue" run generate >"$log" 2>&1; then
tail -n 30 "$log" >&2
rm -f "$log"
echo "refuse: npm run generate in $vue" >&2
return 1
fi
echo "generate: $vue/.output/public"
npm --prefix "$vue" run test >"$log" 2>&1 || rc=$?
detect_tap "$log" || dc=$?
if [[ "$rc" -ne 0 || "$dc" -ne 0 ]]; then
grep -E '^\s*not ok|^# ' "$log" | tail -n 30 >&2
rm -f "$log"
echo "refuse: npm run test in $vue (test=$rc detect=$dc)" >&2
return 1
fi
echo "tap: $(grep -E '^# (tests|pass) ' "$log" | tr '\n' ' ')"
rm -f "$log"
go_named "$SUMMERCMSIO_APP" . -short "${LANDING_TERMINAL_TESTS[@]}"
if [[ "${SUMMERCMS_TERMINAL_CHECK:-}" == "1" ]]; then
go_named "$SUMMERCMSIO_APP" . "-timeout 15m" TestTerminalCommands
local log rc=0 dc=0
if [[ -z "$LANDING_APP" || -z "$LANDING_FRONTEND" ]]; then
not_run "landing site" "PHASE198_LANDING_APP and PHASE198_LANDING_FRONTEND" || return 1
else
echo "NOT RUN TestTerminalCommands (the deployed one-liner end to end: needs network, Docker and ports 54320 and 8080; set SUMMERCMS_TERMINAL_CHECK=1)"
require_dir "$LANDING_FRONTEND" "landing site frontend"
require_dir "$LANDING_APP" "landing site application"
log="$(mktemp)"
if ! npm --prefix "$LANDING_FRONTEND" run generate >"$log" 2>&1; then
tail -n 30 "$log" >&2
rm -f "$log"
echo "refuse: npm run generate in $LANDING_FRONTEND" >&2
return 1
fi
echo "generate: $LANDING_FRONTEND/.output/public"
npm --prefix "$LANDING_FRONTEND" run test >"$log" 2>&1 || rc=$?
detect_tap "$log" || dc=$?
if [[ "$rc" -ne 0 || "$dc" -ne 0 ]]; then
grep -E '^\s*not ok|^# ' "$log" | tail -n 30 >&2
rm -f "$log"
echo "refuse: npm run test in $LANDING_FRONTEND (test=$rc detect=$dc)" >&2
return 1
fi
echo "tap: $(grep -E '^# (tests|pass) ' "$log" | tr '\n' ' ')"
rm -f "$log"
go_named "$LANDING_APP" . -short "${LANDING_TERMINAL_TESTS[@]}"
if [[ "${SUMMERCMS_TERMINAL_CHECK:-}" == "1" ]]; then
go_named "$LANDING_APP" . "-timeout 15m" TestTerminalCommands
else
echo "NOT RUN TestTerminalCommands (the deployed one-liner end to end: needs network, Docker and ports 54320 and 8080; set SUMMERCMS_TERMINAL_CHECK=1)"
fi
fi
go_named "$DEMO_APP" ./plugins/demo/roadmap -short "${ROADMAP_TESTS[@]}"
local ref="${ROADMAP_REF:-origin/master}"
if ! ROADMAP_REF="$ref" "$DEMO_APP/scripts/sync-roadmap.sh" --check; then
echo "refuse: the demo roadmap snapshot differs from $ref" >&2
return 1
if [[ -z "$DEMO_APP" ]]; then
not_run "landing roadmap" PHASE198_DEMO_APP || return 1
else
require_dir "$DEMO_APP" "demo application"
go_named "$DEMO_APP" ./plugins/demo/roadmap -short "${ROADMAP_TESTS[@]}"
local ref="${ROADMAP_REF:-origin/master}"
if ! ROADMAP_REF="$ref" "$DEMO_APP/scripts/sync-roadmap.sh" --check; then
echo "refuse: the demo roadmap snapshot differs from $ref" >&2
return 1
fi
echo "roadmap: snapshot matches $ref"
fi
echo "roadmap: snapshot matches $ref"
echo "phase19.8 landing passed"
}