mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 15:23:12 +00:00
The gate computed changed files with a two-dot diff against the PR base tip, so everything main gained after the branch point counted as this change. A branch behind main that touched C# failed G13 whenever main had merged Terraform in between, which is how #152 failed after #154, #156 and #158 landed. The merge queue no longer requires branches to be current, so the false positive would have hit every stale PR. Both diffs now start at the merge base. Push and merge-group runs are unchanged because their base is an ancestor of the head.
108 lines
3.8 KiB
Bash
Executable file
108 lines
3.8 KiB
Bash
Executable file
#!/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=<base-sha> HEAD_REF=<head-sha> 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
|
|
|
|
# Diff the change set from the merge base, not from the base tip. A two-dot
|
|
# diff against a moving base reports everything the base gained after the
|
|
# branch point as if this change reverted it, so a branch behind main that
|
|
# touches C# would fail G13 whenever main had merged Terraform in the meantime.
|
|
# The merge queue no longer requires branches to be current, so this matters.
|
|
DIFF_BASE="$(git merge-base "${BASE_REF}" "${HEAD_REF}")" || {
|
|
bad "G3: no merge base between '${BASE_REF}' and '${HEAD_REF}'."
|
|
exit 1
|
|
}
|
|
|
|
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}, merge base ${DIFF_BASE:0:7})"
|
|
changed_cs=()
|
|
while IFS= read -r f; do
|
|
changed_cs+=("$f")
|
|
done < <(
|
|
git diff --name-only --diff-filter=ACMR "${DIFF_BASE}" "${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}, merge base ${DIFF_BASE:0:7})"
|
|
python3 scripts/check_app_terraform_isolation.py < <(
|
|
git diff --name-only --diff-filter=ACMR "${DIFF_BASE}" "${HEAD_REF}"
|
|
)
|
|
ok "G13: application and Terraform isolation"
|
|
|
|
log "governance-check: all required repository gates passed"
|