chore(14.3-02): add the D-20 container acceptance stages to the phase 14.3 gate
- --acceptance: in a bare node:24-bookworm container install jq, the Docker CLI and compose plugin (Docker apt repo) and Go 1.27.0 (sha256 from go.dev), pipe the committed new.sh into bash with SUMMERCMS_REPO=/fw and SUMMERCMS_REF=HEAD, then run the D-20 chain and require the starter route - refuses when modules/sunrise/new.sh differs from HEAD; unique compose project with host-side cleanup of containers, volumes and networks - --acceptance-production: same chain against https://summercms.io/new
This commit is contained in:
@@ -7,6 +7,22 @@
|
||||
# its own compose.yaml and serves the starter route with no edits. It ends
|
||||
# with "Phase 14.3 generator check passed".
|
||||
#
|
||||
# --acceptance proves D-20 before the release tag exists: in a bare
|
||||
# node:24-bookworm container it installs jq, the Docker CLI and compose
|
||||
# plugin from Docker's signed apt repository and Go 1.27.0 from go.dev
|
||||
# (sha256 checked), pipes the committed modules/sunrise/new.sh into
|
||||
# `bash -s -- demo` with SUMMERCMS_REPO=<this checkout> and SUMMERCMS_REF=HEAD,
|
||||
# then runs `docker compose up -d --wait && summer build && summer migrate &&
|
||||
# summer serve` in sm-demo-app and requires the starter route. The container
|
||||
# drives the host Docker daemon through its socket, so it runs with
|
||||
# --network host under a unique compose project that is removed afterwards.
|
||||
# It ends with "Phase 14.3 acceptance passed".
|
||||
#
|
||||
# --acceptance-production runs the same chain with
|
||||
# `curl -fsSL https://summercms.io/new | bash -s -- demo` and no SUMMERCMS_
|
||||
# overrides, after the release is tagged and the site redeployed. It ends
|
||||
# with "Phase 14.3 production acceptance passed".
|
||||
#
|
||||
# Needs Docker, the postgres:16 image (pulled when missing) and free host
|
||||
# ports 54320 and 8080. Every failure exits non-zero.
|
||||
#
|
||||
@@ -140,10 +156,152 @@ stage_generator() {
|
||||
echo "Phase 14.3 generator check passed"
|
||||
}
|
||||
|
||||
# acceptance_inner runs inside node:24-bookworm as root. ACC_MODE is local
|
||||
# or production; ACC_REF is the framework commit for local runs.
|
||||
read -r -d '' acceptance_inner <<'INNER' || true
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
run() {
|
||||
echo "+ $*"
|
||||
"$@"
|
||||
}
|
||||
|
||||
echo "== apt: ca-certificates curl gnupg jq"
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq ca-certificates curl gnupg jq >/dev/null
|
||||
|
||||
echo "== Docker CLI and compose plugin from Docker's apt repository"
|
||||
install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
|
||||
chmod a+r /etc/apt/keyrings/docker.asc
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian bookworm stable" >/etc/apt/sources.list.d/docker.list
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq docker-ce-cli docker-compose-plugin >/dev/null
|
||||
docker --version
|
||||
docker compose version
|
||||
|
||||
echo "== Go 1.27.0 from go.dev, sha256 checked"
|
||||
tarball=go1.27.0.linux-amd64.tar.gz
|
||||
sha="$(curl -fsSL 'https://go.dev/dl/?mode=json&include=all' |
|
||||
jq -r --arg f "$tarball" '.[] | select(.version == "go1.27.0") | .files[] | select(.filename == $f) | .sha256')"
|
||||
[[ $sha =~ ^[0-9a-f]{64}$ ]] || { echo "no sha256 for $tarball on go.dev" >&2; exit 1; }
|
||||
curl -fsSL -o "/tmp/$tarball" "https://go.dev/dl/$tarball"
|
||||
(cd /tmp && echo "$sha $tarball" | sha256sum -c -)
|
||||
tar -C /usr/local -xzf "/tmp/$tarball"
|
||||
export PATH="/usr/local/go/bin:$PATH"
|
||||
go version
|
||||
|
||||
# Throwaway root container cloning a host-owned checkout.
|
||||
git config --global --add safe.directory '*'
|
||||
|
||||
mkdir /work
|
||||
cd /work
|
||||
server_pid=""
|
||||
cleanup() {
|
||||
local rc=$?
|
||||
if [ -n "$server_pid" ]; then
|
||||
kill "$server_pid" 2>/dev/null || true
|
||||
wait "$server_pid" 2>/dev/null || true
|
||||
fi
|
||||
if [ -f /work/sm-demo-app/compose.yaml ]; then
|
||||
(cd /work/sm-demo-app && docker compose down -v --remove-orphans >/dev/null 2>&1) || true
|
||||
fi
|
||||
exit "$rc"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
if [ "$ACC_MODE" = production ]; then
|
||||
echo "+ curl -fsSL https://summercms.io/new | bash -s -- demo"
|
||||
curl -fsSL https://summercms.io/new | bash -s -- demo 2>&1 | tee /tmp/new.out
|
||||
else
|
||||
echo "+ curl -fsSL file:///fw/modules/sunrise/new.sh | SUMMERCMS_REPO=/fw SUMMERCMS_REF=$ACC_REF bash -s -- demo"
|
||||
curl -fsSL file:///fw/modules/sunrise/new.sh | SUMMERCMS_REPO=/fw SUMMERCMS_REF="$ACC_REF" bash -s -- demo 2>&1 | tee /tmp/new.out
|
||||
fi
|
||||
grep -qx ' cd /work/sm-demo-app' /tmp/new.out || { echo "the script did not print cd /work/sm-demo-app" >&2; exit 1; }
|
||||
grep -qF 'export PATH="/root/go/bin:$PATH"' /tmp/new.out || { echo "the script did not print the PATH hint" >&2; exit 1; }
|
||||
export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
|
||||
echo "== D-20 chain"
|
||||
cd sm-demo-app
|
||||
run docker compose up -d --wait
|
||||
run summer build
|
||||
run summer migrate
|
||||
echo "+ summer serve &"
|
||||
summer serve >/tmp/serve.log 2>&1 &
|
||||
server_pid=$!
|
||||
body=""
|
||||
for ((i = 0; i < 60; i++)); do
|
||||
if body="$(curl -fsS http://127.0.0.1:8080/ 2>/dev/null)"; then
|
||||
break
|
||||
fi
|
||||
kill -0 "$server_pid" 2>/dev/null || { cat /tmp/serve.log >&2; echo "summer serve exited" >&2; exit 1; }
|
||||
sleep 1
|
||||
done
|
||||
[ -n "$body" ] || { cat /tmp/serve.log >&2; echo "GET / did not answer within 60s" >&2; exit 1; }
|
||||
echo "GET http://127.0.0.1:8080/ -> $body"
|
||||
case "$body" in
|
||||
*'"plugin":"golem15.demo"'*) ;;
|
||||
*) echo "GET / body lacks \"plugin\":\"golem15.demo\"" >&2; exit 1 ;;
|
||||
esac
|
||||
INNER
|
||||
|
||||
# stage_acceptance runs acceptance_inner in node:24-bookworm. $1 is local
|
||||
# (committed script and repository at HEAD) or production.
|
||||
stage_acceptance() {
|
||||
local mode="$1"
|
||||
command -v docker >/dev/null || fail "docker is not installed"
|
||||
docker info >/dev/null 2>&1 || fail "the Docker daemon is not reachable (docker info failed)"
|
||||
port_free 54320 || fail "127.0.0.1:54320 is in use; the generated compose.yaml publishes PostgreSQL there"
|
||||
port_free 8080 || fail "127.0.0.1:8080 is in use; summer serve listens there"
|
||||
|
||||
local ref="" mounts=()
|
||||
if [ "$mode" = local ]; then
|
||||
git -C "$ROOT" ls-files --error-unmatch modules/sunrise/new.sh >/dev/null 2>&1 ||
|
||||
fail "modules/sunrise/new.sh is not committed; the acceptance run clones HEAD"
|
||||
git -C "$ROOT" diff --quiet HEAD -- modules/sunrise/new.sh ||
|
||||
fail "modules/sunrise/new.sh differs from HEAD; commit it first (what is tested must be committed)"
|
||||
ref="$(git -C "$ROOT" rev-parse HEAD)"
|
||||
mounts=(-v "$ROOT:/fw:ro")
|
||||
fi
|
||||
|
||||
echo "== docker pull node:24-bookworm"
|
||||
docker pull -q node:24-bookworm >/dev/null
|
||||
|
||||
# Globals: the EXIT trap runs after this function returns.
|
||||
acc_project="phase143acc-$$-$(date +%s)"
|
||||
acc_runner="$acc_project-runner"
|
||||
acc_cleanup() {
|
||||
local rc=$?
|
||||
docker rm -f "$acc_runner" >/dev/null 2>&1 || true
|
||||
local ids
|
||||
ids="$(docker ps -aq --filter "label=com.docker.compose.project=$acc_project")"
|
||||
[ -z "$ids" ] || docker rm -f $ids >/dev/null 2>&1 || true
|
||||
ids="$(docker volume ls -q --filter "label=com.docker.compose.project=$acc_project")"
|
||||
[ -z "$ids" ] || docker volume rm -f $ids >/dev/null 2>&1 || true
|
||||
ids="$(docker network ls -q --filter "label=com.docker.compose.project=$acc_project")"
|
||||
[ -z "$ids" ] || docker network rm $ids >/dev/null 2>&1 || true
|
||||
exit "$rc"
|
||||
}
|
||||
trap acc_cleanup EXIT
|
||||
|
||||
echo "== node:24-bookworm ($mode, compose project $acc_project)"
|
||||
docker run --rm --name "$acc_runner" --network host \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock "${mounts[@]}" \
|
||||
-e COMPOSE_PROJECT_NAME="$acc_project" -e ACC_MODE="$mode" -e ACC_REF="$ref" \
|
||||
node:24-bookworm bash -euo pipefail -c "$acceptance_inner"
|
||||
|
||||
if [ "$mode" = production ]; then
|
||||
echo "Phase 14.3 production acceptance passed"
|
||||
else
|
||||
echo "Phase 14.3 acceptance passed"
|
||||
fi
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
--generator) stage_generator ;;
|
||||
--acceptance) stage_acceptance local ;;
|
||||
--acceptance-production) stage_acceptance production ;;
|
||||
*)
|
||||
echo "usage: $0 --generator" >&2
|
||||
echo "usage: $0 --generator | --acceptance | --acceptance-production" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user