food-market/deploy/db-schema-diff.sh
nns 843fc4bd03
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
feat(s21): stage→prod migration toolchain (7 скриптов + workflow)
1. deploy/check-prod-readiness.sh — pre-deploy gating: backup<60min,
   disk≥5GB на /opt+/var/lib/docker, /health/ready=Healthy, .env
   required-keys без placeholder'ов. --ssh-host для удалённой проверки.

2. deploy/prod-deploy.sh <api-tag> <web-tag> — blue-green release:
   pull → green-контейнер на :8088 → migrations (auto) → smoke
   (/health/ready + /api/me с тест-токеном) → nginx upstream switch
   → swap → docker compose up -d с обновлённым тэгом. Failure →
   удаление green, blue остаётся. --skip-web флаг.

3. deploy/prod-rollback.sh <to-tag> — docker pull (если нужно) →
   docker compose up -d --force-recreate с указанным tag'ом → wait
   /health/ready до 120с. --dry-run + --skip-web.

4. deploy/post-deploy-smoke.sh — 10 шагов (signup → login →
   /api/me → list products/counterparties/stores/stock → create+delete
   product → logout-via-session). JSON парсится через python3
   (не grep — споткнулись на пробеле перед `:` в access_token).
   Telegram-alert через FM_TG_TOKEN/CHAT при провале. Stage-тест: 10/10 ✓.

5. deploy/db-schema-diff.sh — pg_dump --schema-only с обоих хостов
   через ssh+docker exec, нормализация (sed), diff -u. Exit:
   0=идентичны, 1=разница, 2=ошибка.

6. deploy/generate-release-notes.sh <from-tag> <to-tag> — git log
   group by prefix через awk: feat→, fix→🐛, perf→, docs→📚,
   test/refactor/chore→<details>. Сохраняет docs/release-notes/<tag>.md.

7. .forgejo/workflows/auto-tag.yml — на push в main: если HEAD не
   помечен → создаёт v<YYYYMMDD>.<N> annotated tag, push в origin,
   генерирует release-notes для будущего деплоя.

Все скрипты идемпотентные, поддерживают --dry-run, не трогают прод.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 22:31:10 +05:00

104 lines
3.9 KiB
Bash
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
#
# Sprint 21: сравнение схемы БД stage vs prod.
#
# Делает `pg_dump --schema-only` с обеих БД, diff'ит. Если выводит
# непустой diff — миграция не доехала или local-only изменения.
#
# Подразумевает что обе БД доступны (например через SSH-туннель или
# pg_dump --host=<host>). Дефолтные подключения:
# stage = docker exec food-market-stage-postgres-1 pg_dump (через ssh dev-vm)
# prod = docker exec food-market-postgres pg_dump (через ssh prod-vm)
#
# Usage:
# deploy/db-schema-diff.sh [--stage-host HOST] [--prod-host HOST]
# [--quick] # без TOAST/sequence-details
# [--dry-run] # печать только команд
#
# Выход:
# 0 — схемы идентичны
# 1 — есть различия (печатает diff)
# 2 — ошибка получения дампа
set -uo pipefail
STAGE_HOST="${FM_STAGE_HOST:-nns@192.168.1.190}"
PROD_HOST="${FM_PROD_HOST:-nns@admin.food-market.kz}"
STAGE_CONT="${FM_STAGE_CONT:-food-market-stage-postgres-1}"
PROD_CONT="${FM_PROD_CONT:-food-market-postgres}"
DB="${FM_PG_DB:-food_market}"
DB_USER="${FM_PG_USER:-food_market}"
QUICK=0
DRY_RUN=0
while [[ $# -gt 0 ]]; do
case "$1" in
--stage-host) STAGE_HOST="$2"; shift 2 ;;
--prod-host) PROD_HOST="$2"; shift 2 ;;
--quick) QUICK=1; shift ;;
--dry-run) DRY_RUN=1; shift ;;
--help|-h) grep -E '^#( |$)' "$0" | sed 's/^# \?//'; exit 0 ;;
*) echo "Unknown: $1" >&2; exit 2 ;;
esac
done
# Флаги pg_dump для schema-only сравнения. --schema-only + --no-owner +
# --no-privileges чтобы дамп был стабильный без role-mismatch'ей между
# инстансами. --no-comments — выключаем COMMENT'ы (они часто шумят).
PGDUMP_FLAGS="--schema-only --no-owner --no-privileges --no-comments"
if [[ $QUICK -eq 1 ]]; then
PGDUMP_FLAGS="$PGDUMP_FLAGS --exclude-table-data=pg_*"
fi
TMP_DIR=$(mktemp -d)
trap "rm -rf $TMP_DIR" EXIT
STAGE_SQL="$TMP_DIR/stage.sql"
PROD_SQL="$TMP_DIR/prod.sql"
log() { echo "[$(date -Iseconds)] $*" >&2; }
dump_remote() {
local host="$1" container="$2" out="$3"
log "dump from $host (container $container) → $out"
if [[ $DRY_RUN -eq 1 ]]; then
echo "[dry-run] ssh $host docker exec $container pg_dump $PGDUMP_FLAGS -U $DB_USER -d $DB > $out"
touch "$out"
return
fi
ssh -o ConnectTimeout=10 "$host" "docker exec $container pg_dump $PGDUMP_FLAGS -U $DB_USER -d $DB" > "$out" 2>/dev/null \
|| { log "FAIL: dump from $host"; return 2; }
}
dump_remote "$STAGE_HOST" "$STAGE_CONT" "$STAGE_SQL" || exit 2
dump_remote "$PROD_HOST" "$PROD_CONT" "$PROD_SQL" || exit 2
# Нормализация: убираем строки которые всегда отличаются (комментарии,
# даты, version-header'ы, OID'ы):
normalize() {
sed -e '/^-- /d' \
-e '/^SET /d' \
-e '/^SELECT pg_catalog.set_config/d' \
-e '/^[[:space:]]*$/d' "$1"
}
# Применяем нормализацию ин-плейс и сравниваем.
normalize "$STAGE_SQL" > "$TMP_DIR/stage.norm"
normalize "$PROD_SQL" > "$TMP_DIR/prod.norm"
log "comparing…"
if diff -u "$TMP_DIR/prod.norm" "$TMP_DIR/stage.norm" > "$TMP_DIR/diff" 2>&1; then
echo "✓ Схемы идентичны (stage == prod)"
exit 0
fi
LINES=$(wc -l < "$TMP_DIR/diff")
echo "✗ Найдены различия: $LINES строк diff'a"
echo
echo "===== diff (prod → stage) ====="
cat "$TMP_DIR/diff"
echo "==============================="
echo
echo "Если разница — новые миграции stage → prod, применить их перед deploy."
echo "Если разница — local-only изменения на prod, разобраться вручную."
exit 1