yggdrasil/scripts/migrate.sh

105 lines
3.2 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
#
# 数据库迁移脚本(手动 / CI 备用)。
#
# 注意:服务器二进制现在会在启动时自动执行迁移(见 src/db/migrate.rs
# 正常情况下无需手动运行本脚本。保留它是为了:
# - 运维 escape hatch二进制因迁移失败起不来时手动救库
# - CI/CD 中“先迁移再滚动发布”的工作流
#
# 本脚本与服务器内置运行器读取相同的 migrations/*.sql 文件,且这些 SQL
# 都是幂等的IF NOT EXISTS / IF EXISTS / ON CONFLICT DO NOTHING
# 因此两者混用安全。
#
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