Something went wrong. Try again.
A community based topic aggregation platform built on atproto
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173#!/usr/bin/env bash# The hermetic merge gate. Driven by `make ci`.## WHAT THIS DOES THAT THE PER-TIER TARGETS DO NOT## * Creates its own infrastructure instead of asserting that a human already# started it. `make test-integration` grades whatever the dev stack happens# to be serving; this builds the stack it grades against. (`make test-e2e`# now shares this script's bring-up — see scripts/lib/ci-stack.sh — so the# pipeline tier runs the same way in both.)## * Tests a binary built from the current working tree, rather than whatever# long-running `make run` started in another terminal, which may be many# edits stale. A gate that grades the wrong binary is worse than no gate.## * Starts from empty state every run: fresh PDS, fresh PLC registry, fresh# databases. No accumulated accounts, no handle collisions, no fixtures from# a previous run.## * Publishes no host ports, so it runs concurrently with `make dev-up` and# cannot interfere with it in either direction. Keep hacking while it runs.## * Fails on any lint or formatting issue (`make lint`).## * Refuses to report success when the suite silently shrank. See# cmd/ci-report — a skip is a failure unless the committed allowlist says# otherwise.## Every step is non-interactive: no `read -p` prompts anywhere in this path, so# an agent can run it unattended.## Environment overrides:# COVES_CI_PROJECT Compose project name (default derived from the# checkout dir: coves-ci for the main checkout,# coves-ci-<suffix> for a worktree named coves-<suffix>,# so concurrent worktrees never share a stack)# COVES_CI_KEEP_STACK 1 to leave the stack running for debugging# COVES_CI_ALLOW_STALE true to downgrade stale-allowlist entries to warningsset -euo pipefail
# Sets REPO_ROOT, cds to it, and defines compose/step/ok/warn/fail plus the# stack_* bring-up used identically by scripts/test-e2e.sh.# shellcheck source=scripts/lib/ci-stack.shsource "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/ci-stack.sh"
# ---------------------------------------------------------------------------# Teardown# ---------------------------------------------------------------------------# Registered before anything is created, so an interrupt or an early failure# still cleans up.teardown() { local exit_code=$? stack_control_stop if [[ ${COVES_CI_KEEP_STACK:-0} == 1 ]]; then stack_keep_notice return $exit_code fi stack_teardown return $exit_code}trap teardown EXIT
stack_preflight
# Snapshot the working tree so the post-run check can compare against how the# tree started, not against HEAD. Comparing against HEAD would flag every# uncommitted change the developer already had in progress, which says nothing# about whether the *run* modified anything.TREE_BEFORE=$(git status --porcelain --untracked-files=all | sort)
# ---------------------------------------------------------------------------# Build, lint, then bring up the system under test# ---------------------------------------------------------------------------# stack_up's steps, with lint between the module prefetch and the stack start,# so a lint failure costs a minute instead of a full stack bring-up.## make lint runs in the runner image (the toolchain the suite compiles with),# on Docker's default bridge because `go run` fetches the pinned golangci-lint# into the shared module cache. It is the full check: formatting plus every# linter, including files behind the integration, e2e and live tags.stack_discard_previousstack_buildstack_prefetch_modules
step "Linting"if ! docker run --rm \ -v "$REPO_ROOT:/src" -w /src \ -v coves-ci-go-mod-cache:/go/pkg/mod \ -v coves-ci-go-build-cache:/go-build-cache \ -e GOLANGCI_LINT_CACHE=/go-build-cache/golangci-lint \ --entrypoint make \ "$PROJECT-runner" --no-print-directory lint; then fail "make lint failed; 'make lint-fix' fixes formatting, the rest needs code changes" exit 1fiok "lint clean"
stack_start
# ---------------------------------------------------------------------------# Run the suite# ---------------------------------------------------------------------------# The pipeline tier's reliability suite restarts and reconfigures the AppView,# which only the host can do — see stack_control_start in lib/ci-stack.sh. It# serves for exactly as long as the suite runs, and the EXIT trap stops it.stack_control_start
step "Running the suite"set +ecompose run --rm runnerGATE_STATUS=$?set -e
stack_control_stop
# ---------------------------------------------------------------------------# Diagnostics on failure# ---------------------------------------------------------------------------# When an E2E test fails, the AppView's own logs are usually the only record of# what the server actually did. Capturing them unconditionally on failure means# the information is already there rather than requiring a re-run with# COVES_CI_KEEP_STACK=1.if [[ $GATE_STATUS -ne 0 ]]; then step "Capturing diagnostics" stack_capture_logs ok "wrote $(stack_captured_logs) to .ci-out/"fi
# ---------------------------------------------------------------------------# The run must not have modified the checkout# ---------------------------------------------------------------------------# The runner mounts the repository read-write, because the Go toolchain and# goose both expect a normal working tree. That makes it possible for a test to# write into the repo, which would be a real defect — a suite that mutates its# own source is not reproducible. .ci-out/ is gitignored, so a clean run leaves# no trace.step "Checking the run left the checkout unchanged"TREE_AFTER=$(git status --porcelain --untracked-files=all | sort)if [[ $TREE_BEFORE != "$TREE_AFTER" ]]; then warn "the run modified the working tree:" diff <(printf '%s\n' "$TREE_BEFORE") <(printf '%s\n' "$TREE_AFTER") | grep -E '^[<>]' | sed 's/^/ /' || true warn "a test writing into the checkout is a defect worth fixing"else ok "checkout unchanged by the run"fi
# ---------------------------------------------------------------------------# Result# ---------------------------------------------------------------------------printf "\n"if [[ $GATE_STATUS -eq 0 ]]; then printf "${GREEN}═══════════════════════════════════════════════════════════════${RESET}\n" printf "${GREEN} ✓ CI GATE PASSED${RESET}\n" printf "${GREEN}═══════════════════════════════════════════════════════════════${RESET}\n"else printf "${RED}═══════════════════════════════════════════════════════════════${RESET}\n" printf "${RED} ✗ CI GATE FAILED${RESET}\n" printf "${RED}═══════════════════════════════════════════════════════════════${RESET}\n"fiprintf "\n Machine-readable summary: .ci-out/summary.json\n"printf " Raw go test -json stream: .ci-out/gotest.json\n"if [[ $GATE_STATUS -ne 0 ]]; then printf " Service logs (.ci-out/): %s\n" "$(stack_captured_logs)" printf "\n To investigate against a live stack:\n" printf " COVES_CI_KEEP_STACK=1 make ci\n" printf " ...then iterate on the pipeline tier alone against that same stack:\n" printf " COVES_CI_REBUILD=1 make test-e2e\n"fiprintf "\n"
exit $GATE_STATUS