Files
clean-architecture-backend-…/scripts/verify-mongodb-platform.sh
T

178 lines
7.0 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# The MongoDB Stable release gate (design §30, plan Task 50).
#
# Runs every lane that produces one of the Stable evidence categories:
#
# mapping, transaction, migration, change-stream, security,
# failover, performance, compatibility
#
# The gate exists because "the test suite is green" and "every category has evidence" are different
# statements. A suite passes happily with a whole lane skipped -- no Docker, a disabled tag, a
# renamed task -- and a release built on that suite has no failover or compatibility evidence at
# all, silently. Each lane below is therefore run by name, and a skipped lane is reported as skipped
# rather than counted as passed.
#
# Advanced capabilities are NOT promoted or transitively included here. See
# scripts/verify-mongodb-advanced.sh.
#
# Usage:
# bash scripts/verify-mongodb-platform.sh # hermetic lanes only
# MONGODB_DOCKER=1 bash scripts/verify-mongodb-platform.sh # + container lanes
#
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
GRADLE_DIR="${REPO_ROOT}/src"
MODULE=':adapter:outbound:persistence-mongo'
GRADLE=(./gradlew --console=plain)
RESULTS_DIR="${GRADLE_DIR}/adapter/outbound/persistence-mongo/build/test-results"
RAN=()
SKIPPED=()
FAILED=()
# Counts the tests a lane actually executed, from its JUnit XML.
#
# A lane whose filter matches nothing passes: Gradle runs the task, discovers no tests, and reports
# success. That is the failure mode this whole gate exists to prevent -- an empty lane is not
# evidence, it is the absence of evidence wearing a green tick. Any lane that reports zero executed
# tests is treated as a failure.
executed_tests() {
local task="$1"
local dir="${RESULTS_DIR}/${task}"
[[ -d "${dir}" ]] || { echo 0; return; }
local total=0
shopt -s nullglob
for xml in "${dir}"/*.xml; do
local count
count=$(sed -n 's/.*<testsuite[^>]* tests="\([0-9]*\)".*/\1/p' "${xml}" | head -1)
total=$(( total + ${count:-0} ))
done
shopt -u nullglob
echo "${total}"
}
run_lane() {
local category="$1"
local task="$2"
shift 2
echo ""
echo "=== [${category}] ${task}"
if ! (cd "${GRADLE_DIR}" && "${GRADLE[@]}" "${MODULE}:${task}" "$@"); then
FAILED+=("${category}:${task}")
return
fi
# `check` aggregates several tasks and has no results directory of its own.
if [[ "${task}" == "check" ]]; then
RAN+=("${category}:${task}")
return
fi
local executed
executed=$(executed_tests "${task}")
if (( executed == 0 )); then
echo "!!! ${task} passed without executing a single test — the lane's filter matches nothing,"
echo "!!! so the '${category}' evidence category is empty."
FAILED+=("${category}:${task} (0 tests executed)")
else
RAN+=("${category}:${task} (${executed} tests)")
fi
}
skip_lane() {
local category="$1"
local task="$2"
local reason="$3"
echo ""
echo "=== [${category}] ${task} -- SKIPPED (${reason})"
SKIPPED+=("${category}:${task} (${reason})")
}
docker_available() {
[[ "${MONGODB_DOCKER:-0}" == "1" ]] && command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1
}
echo "MongoDB Stable release gate"
echo "repository: ${REPO_ROOT}"
# --- Always-on lanes -------------------------------------------------------------------------
# Static analysis, architecture boundaries, unit and hermetic contract tests. These produce the
# mapping, transaction, migration, change-stream and security evidence that does not need a server.
run_lane "static-analysis" "check" -x "mongoStableContractTest"
run_lane "mapping+transaction+migration+change-stream+security" "mongoStableContractTest"
# --- Container lanes -------------------------------------------------------------------------
# A lane that needs Docker inside `check` teaches people to skip `check`, so these are opt-in --
# but opting out is recorded, not silent.
if docker_available; then
run_lane "compatibility" "mongoCompatibilityTest"
run_lane "migration" "mongoMigrationTest"
run_lane "security" "mongoSecurityIntegrationTest"
run_lane "failover" "mongoReplicaSetTest"
run_lane "failover" "mongoFailoverTest"
run_lane "performance" "mongoPerformanceTest"
else
reason="MONGODB_DOCKER!=1 or Docker unavailable"
skip_lane "compatibility" "mongoCompatibilityTest" "${reason}"
skip_lane "migration" "mongoMigrationTest" "${reason}"
skip_lane "security" "mongoSecurityIntegrationTest" "${reason}"
skip_lane "failover" "mongoReplicaSetTest" "${reason}"
skip_lane "failover" "mongoFailoverTest" "${reason}"
skip_lane "performance" "mongoPerformanceTest" "${reason}"
fi
# --- Architecture-wide gates -----------------------------------------------------------------
echo ""
echo "=== [architecture] repository-wide verification"
if (cd "${GRADLE_DIR}" \
&& "${GRADLE[@]}" verifyCleanArchitectureDependencies \
&& "${GRADLE[@]}" :app-bootstrap:test --tests '*CleanArchitectureTest'); then
RAN+=("architecture:repository-wide")
else
FAILED+=("architecture:repository-wide")
fi
# --- Report ------------------------------------------------------------------------------------
echo ""
echo "---------------------------------------------------------------"
echo "ran: ${#RAN[@]}"
for entry in "${RAN[@]:-}"; do [[ -n "${entry}" ]] && echo " + ${entry}"; done
echo "skipped: ${#SKIPPED[@]}"
for entry in "${SKIPPED[@]:-}"; do [[ -n "${entry}" ]] && echo " ~ ${entry}"; done
echo "failed: ${#FAILED[@]}"
for entry in "${FAILED[@]:-}"; do [[ -n "${entry}" ]] && echo " - ${entry}"; done
# --- promotion manifest -------------------------------------------------------------------------
# What was actually certified, tied to what produced it. A gate output that says "PASSED" and
# nothing else cannot be checked later against the artefact it supposedly certified: the commit, the
# server image and the driver version are exactly what somebody reads during an incident.
MANIFEST_DIR="${REPO_ROOT}/src/adapter/outbound/persistence-mongo/build/reports/mongo-release"
mkdir -p "${MANIFEST_DIR}"
{
echo "{"
echo " \"commit\": \"$(git -C "${REPO_ROOT}" rev-parse HEAD)\","
echo " \"commitDirty\": $( [[ -n "$(git -C "${REPO_ROOT}" status --porcelain)" ]] && echo true || echo false ),"
echo " \"serverImage\": \"${MONGODB_IMAGE:-mongo:8.0.16}\","
echo " \"generatedAt\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\","
echo " \"contractManifest\": \"src/config/mongodb/release-contracts.json\","
echo " \"contractManifestSha256\": \"$(sha256sum "${REPO_ROOT}/src/config/mongodb/release-contracts.json" | cut -d' ' -f1)\""
echo "}"
} > "${MANIFEST_DIR}/promotion.json"
echo "promotion manifest: ${MANIFEST_DIR}/promotion.json"
echo "---------------------------------------------------------------"
if (( ${#FAILED[@]} > 0 )); then
echo "STABLE GATE: FAILED"
exit 1
fi
if (( ${#SKIPPED[@]} > 0 )); then
echo "STABLE GATE: INCOMPLETE -- lanes above were not run, so their evidence categories are absent."
echo "A release requires every category. Re-run with MONGODB_DOCKER=1 on a host with Docker."
exit 2
fi
echo "STABLE GATE: PASSED -- every evidence category produced."