#!/usr/bin/env bash # # governance-check.sh — local/CI parity governance gate for the Seahaven backend. # # Runs G1 restore, G2 ArchitectureTests, G3 changed-file formatting, G4 Release # build, and G5 full tests exactly as the `architecture-quality` workflow does. # A green run here means the same thing locally and in that CI workflow. # # Usage: # bash scripts/governance-check.sh # BASE_REF=origin/main bash scripts/governance-check.sh # BASE_REF= HEAD_REF= bash scripts/governance-check.sh set -euo pipefail SOLUTION="SeaHavenIndustries.sln" ARCH_TEST_PROJECT="Api.SeaHavenIndustries.Tests/Api.SeaHavenIndustries.Tests.csproj" log() { printf '\n\033[1m== %s ==\033[0m\n' "$1"; } ok() { printf '\033[32mPASS\033[0m %s\n' "$1"; } bad() { printf '\033[31mFAIL\033[0m %s\n' "$1"; } if [[ -n "${DOTNET_BIN:-}" ]]; then DOTNET="$DOTNET_BIN" elif command -v dotnet >/dev/null 2>&1; then DOTNET="$(command -v dotnet)" elif [[ -x "$HOME/.dotnet/dotnet" ]]; then DOTNET="$HOME/.dotnet/dotnet" else bad "dotnet is unavailable; set DOTNET_BIN or install the repository SDK." exit 1 fi # Comparison point for changed-file formatting. Default to main locally; CI # overrides BASE_REF/HEAD_REF with the PR base/head SHAs. BASE_REF="${BASE_REF:-origin/main}" HEAD_REF="${HEAD_REF:-HEAD}" # Resolve the base ref before using it for a diff. if ! git rev-parse --verify --quiet "${BASE_REF}^{commit}" >/dev/null; then bad "G3: BASE_REF '${BASE_REF}' does not resolve to a commit (run: git fetch origin)." exit 1 fi log "G1: restore" "$DOTNET" restore "$SOLUTION" ok "G1: restore" log "G2: architecture boundary tests (dependency direction)" "$DOTNET" test "$ARCH_TEST_PROJECT" \ --no-restore \ --filter "FullyQualifiedName~ArchitectureTests" \ --nologo ok "G2: ArchitectureTests" log "G3: changed-file formatting (${BASE_REF}..${HEAD_REF})" changed_cs=() while IFS= read -r f; do changed_cs+=("$f") done < <( git diff --name-only --diff-filter=ACMR "${BASE_REF}" "${HEAD_REF}" -- '*.cs' ) if (( ${#changed_cs[@]} == 0 )); then printf '\033[33mSKIP\033[0m G3: no changed C# files between %s..%s\n' "${BASE_REF}" "${HEAD_REF}" else printf ' checking %d changed C# file(s)\n' "${#changed_cs[@]}" "$DOTNET" format "$SOLUTION" \ --no-restore \ --verify-no-changes \ --include "${changed_cs[@]}" ok "G3: changed-file formatting" fi log "G4: Release build" "$DOTNET" build "$SOLUTION" -c Release --no-restore --nologo ok "G4: Release build" log "G5: full test suite" "$DOTNET" test "$SOLUTION" -c Release --no-build --nologo ok "G5: full test suite" log "G10: Terraform import plan safety" python scripts/test-terraform-import-plan-check.py ok "G10: Terraform import plan safety" log "Release promotion scripts" python3 scripts/test_next_release_tag.py python3 scripts/test_require_commit_checks.py python3 scripts/test_check_app_terraform_isolation.py ok "Release promotion scripts" log "G13: application and Terraform isolation (${BASE_REF}..${HEAD_REF})" python3 scripts/check_app_terraform_isolation.py < <( git diff --name-only --diff-filter=ACMR "${BASE_REF}" "${HEAD_REF}" ) ok "G13: application and Terraform isolation" log "governance-check: all required repository gates passed"