#!/usr/bin/env bash # ci-cd.yml › backend — flag destructive EF migrations introduced by this pull request. # # A failed deploy rolls the backend binaries back but never the database, so every release must # leave the PREVIOUS backend working on the NEW schema: add tables/columns now, drop or rename # them in a later release (expand → contract, docs/40-DEPLOYMENT.md §8). # into Dev → warning # into production → failure, unless the PR title contains [allow-destructive-migration] # shellcheck source=common.sh source "$(dirname "${BASH_SOURCE[0]}")/common.sh" : "${BASE_REF:?BASE_REF (the PR target branch) is required}" base="refs/remotes/origin/$BASE_REF" git_remote fetch -q --depth 1 "$REPO_GIT_URL" "+refs/heads/$BASE_REF:$base" # Two-dot tree diff: needs only the two commits, not their history (depth-1 friendly). mapfile -t files < <( git diff --name-only --diff-filter=AM "$base" HEAD -- "$MIGRATIONS_PATH" | grep -E '\.cs$' | grep -vE '\.Designer\.cs$|ModelSnapshot\.cs$' || true ) if ((${#files[@]} == 0)); then log "no new or changed migrations" exit 0 fi hits="" for f in "${files[@]}"; do # Only Up() matters — every Down() legitimately drops what its Up() created. found="$(awk ' /override void Up\(/ { up = 1 } /override void Down\(/ { up = 0 } up && /migrationBuilder\.(DropTable|DropColumn|RenameColumn|RenameTable|DropSchema|DropSequence)\(/ { printf " %s:%d: %s\n", FILENAME, FNR, $0 }' "$f")" hits+="$found" done if [[ -z "$hits" ]]; then log "checked ${#files[@]} migration file(s): additive only" exit 0 fi printf '%s\n' "$hits" msg="destructive operation in a migration's Up() — keep the previous release working on the new schema: expand now, contract in a later release (docs/40-DEPLOYMENT.md §8)" if [[ "$BASE_REF" == production ]]; then if [[ "${PR_TITLE:-}" == *"[allow-destructive-migration]"* ]]; then warn "$msg — allowed by the [allow-destructive-migration] PR title override" exit 0 fi fail "$msg" fi warn "$msg"