Ctrl K
ComunidadGuías…

scripts/repair-prod-migration-squash.sh

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env bash
# Repair Capgo-EU / Alpha migration history after a *_baseline.sql squash.
# Updates supabase_migrations history only — never runs baseline DDL.
#
# Usage:
#   bunx supabase link --project-ref <PROJECT_REF>
#   bash scripts/repair-prod-migration-squash.sh            # dry-run
#   bash scripts/repair-prod-migration-squash.sh --execute  # apply repair
#
# Optional:
#   --db-url 'postgresql://...'   # instead of --linked
#   --baseline 20260708000000     # default: sole local migration version
#   --batch-size 80

set -euo pipefail

EXECUTE=0
DB_TARGET=(--linked)
BASELINE_VERSION=''
BATCH_SIZE=80
MIGRATIONS_DIR='supabase/migrations'

while [[ $# -gt 0 ]]; do
  case "$1" in
    --execute) EXECUTE=1; shift ;;
    --dry-run) EXECUTE=0; shift ;;
    --linked) DB_TARGET=(--linked); shift ;;
    --local) DB_TARGET=(--local); shift ;;
    --db-url)
      [[ $# -ge 2 ]] || { echo "missing value for --db-url" >&2; exit 1; }
      DB_TARGET=(--db-url "$2"); shift 2
      ;;
    --baseline)
      [[ $# -ge 2 ]] || { echo "missing value for --baseline" >&2; exit 1; }
      BASELINE_VERSION="$2"; shift 2
      ;;
    --batch-size)
      [[ $# -ge 2 ]] || { echo "missing value for --batch-size" >&2; exit 1; }
      BATCH_SIZE="$2"; shift 2
      ;;
    -h|--help)
      sed -n '2,16p' "$0"
      exit 0
      ;;
    *)
      echo "Unknown arg: $1" >&2
      exit 1
      ;;
  esac
done

if ! command -v bunx >/dev/null 2>&1; then
  echo "bunx is required" >&2
  exit 1
fi

mapfile -t LOCAL_FILES < <(find "$MIGRATIONS_DIR" -maxdepth 1 -type f -name '*.sql' | sort)
if [[ ${#LOCAL_FILES[@]} -eq 0 ]]; then
  echo "No local migrations under $MIGRATIONS_DIR" >&2
  exit 1
fi

declare -A LOCAL_VERSIONS=()
for file in "${LOCAL_FILES[@]}"; do
  base="$(basename "$file")"
  if [[ "$base" =~ ^([0-9]{14})_ ]]; then
    LOCAL_VERSIONS["${BASH_REMATCH[1]}"]=1
  fi
done

if [[ -z "$BASELINE_VERSION" ]]; then
  if [[ ${#LOCAL_VERSIONS[@]} -ne 1 ]]; then
    echo "Expected exactly one local migration for a squash repair, found ${#LOCAL_VERSIONS[@]}." >&2
    echo "Pass --baseline <version> explicitly if this is intentional." >&2
    printf '  %s\n' "${!LOCAL_VERSIONS[@]}" | sort >&2
    exit 1
  fi
  BASELINE_VERSION="$(printf '%s\n' "${!LOCAL_VERSIONS[@]}" | head -1)"
fi

if [[ -z "${LOCAL_VERSIONS[$BASELINE_VERSION]+x}" ]]; then
  echo "Baseline version $BASELINE_VERSION is not present locally." >&2
  exit 1
fi

echo "Fetching remote migration list..."
LIST_OUT="$(mktemp)"
trap 'rm -f "$LIST_OUT"' EXIT
bunx supabase migration list "${DB_TARGET[@]}" >"$LIST_OUT"

# Parse version tokens from CLI table/text output.
mapfile -t REMOTE_VERSIONS < <(
  # shellcheck disable=SC2016
  sed -E 's/\x1B\[[0-9;]*[A-Za-z]//g' "$LIST_OUT" \
    | grep -oE '[0-9]{14}' \
    | sort -u
)

if [[ ${#REMOTE_VERSIONS[@]} -eq 0 ]]; then
  echo "Could not parse any remote migration versions from:" >&2
  cat "$LIST_OUT" >&2
  exit 1
fi

TO_REVERT=()
for version in "${REMOTE_VERSIONS[@]}"; do
  if [[ -z "${LOCAL_VERSIONS[$version]+x}" ]]; then
    TO_REVERT+=("$version")
  fi
done

TO_MARK_APPLIED=()
if ! printf '%s\n' "${REMOTE_VERSIONS[@]}" | grep -qxF "$BASELINE_VERSION"; then
  TO_MARK_APPLIED+=("$BASELINE_VERSION")
fi

echo
echo "Local migrations: ${#LOCAL_VERSIONS[@]} (baseline $BASELINE_VERSION)"
echo "Remote versions parsed: ${#REMOTE_VERSIONS[@]}"
echo "Will mark reverted: ${#TO_REVERT[@]}"
echo "Will mark applied: ${#TO_MARK_APPLIED[@]}"
echo

if [[ ${#TO_REVERT[@]} -eq 0 && ${#TO_MARK_APPLIED[@]} -eq 0 ]]; then
  echo "Nothing to repair. History already matches the squash."
  exit 0
fi

run_repair() {
  local status="$1"
  shift
  local versions=("$@")
  local i=0
  local batch=()
  for version in "${versions[@]}"; do
    batch+=("$version")
    i=$((i + 1))
    if (( i % BATCH_SIZE == 0 )); then
      echo "-> migration repair --status $status (${#batch[@]} versions)"
      if (( EXECUTE == 1 )); then
        bunx supabase migration repair "${DB_TARGET[@]}" --status "$status" --yes "${batch[@]}"
      fi
      batch=()
    fi
  done
  if (( ${#batch[@]} > 0 )); then
    echo "-> migration repair --status $status (${#batch[@]} versions)"
    if (( EXECUTE == 1 )); then
      bunx supabase migration repair "${DB_TARGET[@]}" --status "$status" --yes "${batch[@]}"
    fi
  fi
}

if (( ${#TO_REVERT[@]} > 0 )); then
  echo "Reverting remote-only versions..."
  run_repair reverted "${TO_REVERT[@]}"
fi

if (( ${#TO_MARK_APPLIED[@]} > 0 )); then
  echo "Marking baseline applied (no DDL)..."
  run_repair applied "${TO_MARK_APPLIED[@]}"
fi

if (( EXECUTE == 0 )); then
  echo
  echo "Dry-run only. Re-run with --execute to apply."
  exit 0
fi

echo
echo "Repair finished. Verifying..."
bunx supabase migration list "${DB_TARGET[@]}"
echo
echo "Confirm db push would apply nothing before merging/deploying:"
echo "  bunx supabase db push ${DB_TARGET[*]} --dry-run"