yggdrasil/migrate.sh
xfy 179897ba6f fix(migrations): make all migrations idempotent; distinguish applied vs error
- 006: ADD COLUMN 补 IF NOT EXISTS
- 002: 5 个索引(status_published/slug_unique/post_tags_post/post_tags_tag/cover)补 IF NOT EXISTS
- migrate.sh: 区分「已应用」与「真出错」,真错误时打印输出并中止,不再静默吞掉(M6)

已验证:第二次运行全部 OK(幂等),不再出现重复对象错误。
2026-06-18 13:34:07 +08:00

93 lines
2.7 KiB
Bash
Executable File
Raw 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
set -euo pipefail
# 从 .env 加载环境变量
if [[ -f .env ]]; then
echo "Loading DATABASE_URL from .env..."
# shellcheck source=/dev/null
set -a
source .env
set +a
fi
# 检查 DATABASE_URL
if [[ -z "${DATABASE_URL:-}" ]]; then
echo "ERROR: DATABASE_URL is not set."
echo "Please create a .env file or set the DATABASE_URL environment variable."
echo "Example: export DATABASE_URL=postgres://postgres:postgres@localhost:5432/yggdrasil"
exit 1
fi
echo "Using database: $DATABASE_URL"
# 从 DATABASE_URL 中提取数据库名
DB_NAME=$(echo "$DATABASE_URL" | sed -n 's/.*\/\([^?]*\).*/\1/p')
# 提取不带数据库名的连接字符串(用于连接 postgres 系统库)
ADMIN_URL=$(echo "$DATABASE_URL" | sed "s|/${DB_NAME}|/postgres|")
echo "Target database: $DB_NAME"
# 检查目标数据库是否存在,不存在则创建
echo "Checking if database '$DB_NAME' exists..."
if ! psql "$ADMIN_URL" -tAc "SELECT 1 FROM pg_database WHERE datname='${DB_NAME}';" | grep -q 1; then
echo "Database '$DB_NAME' does not exist. Creating..."
psql "$ADMIN_URL" -c "CREATE DATABASE ${DB_NAME};"
echo "Database '$DB_NAME' created."
else
echo "Database '$DB_NAME' already exists."
fi
# 按顺序执行所有迁移文件
MIGRATIONS_DIR="migrations"
if [[ ! -d "$MIGRATIONS_DIR" ]]; then
echo "ERROR: Migrations directory '$MIGRATIONS_DIR' not found."
exit 1
fi
# 获取排序后的 SQL 文件列表
MIGRATION_FILES=""
for f in "$MIGRATIONS_DIR"/*.sql; do
[[ -f "$f" ]] && MIGRATION_FILES="$MIGRATION_FILES$f
"
done
if [[ -z "$MIGRATION_FILES" ]]; then
echo "No migration files found in $MIGRATIONS_DIR."
exit 0
fi
echo ""
echo "Running migrations..."
echo "====================="
echo "$MIGRATION_FILES" | sort | while IFS= read -r file; do
[[ -z "$file" ]] && continue
filename=$(basename "$file")
echo -n "[$filename] ... "
# 区分「已应用」与「真出错」迁移本身已幂等IF NOT EXISTS正常应返回 0。
# 非零退出码视为真错误打印输出并中止避免静默吞错M6
err_output=$(psql "$DATABASE_URL" -f "$file" 2>&1 >/dev/null)
rc=$?
if [[ $rc -eq 0 ]]; then
echo "OK"
elif echo "$err_output" | grep -qiE "already exists|duplicate|multiple primary keys"; then
echo "SKIPPED (already applied)"
else
echo "FAIL"
echo "$err_output" | head -5 | sed 's/^/ /'
echo "Migration aborted due to error in $filename"
exit 1
fi
done
echo "====================="
echo "Migration complete!"
echo ""
# 显示当前数据库中的表
echo "Tables in database '$DB_NAME':"
psql "$DATABASE_URL" -c "\dt" || true