fix(db): 禁止修改已发布迁移并分批兼容旧库

This commit is contained in:
yml2213
2026-11-07 17:51:34 +08:00
parent 7b68d9b60a
commit 8ef8c61862
12 changed files with 253 additions and 123 deletions
+6 -16
View File
@@ -7,6 +7,8 @@ import path from 'node:path'
import { execFileSync } from 'node:child_process'
import { fileURLToPath } from 'node:url'
import { changedPublishedMigrations } from '../src/db/migration-integrity.js'
const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url))
const BACKEND_ROOT = path.resolve(SCRIPT_DIR, '..')
@@ -92,11 +94,6 @@ const failures: string[] = []
// 用「已发布基线」而不是 HEAD 做比较,是因为以 HEAD 为基线时,本次提交新增的
// 迁移也会被算成历史迁移,合并提交后必然自相矛盾。
const MIGRATION_BASELINE_REF = resolveMigrationBaselineRef()
// 生产当前已发布到 119;120+ 仍允许在部署前重写。部署 120 后应将此值提升到 120。
const PUBLISHED_MIGRATION_MAX_VERSION = Math.max(
0,
Math.trunc(Number(process.env.PUBLISHED_MIGRATION_MAX_VERSION) || 119),
)
function resolveMigrationBaselineRef(): string | null {
const candidates = [process.env.MIGRATION_BASELINE_REF, 'main', 'origin/main'].filter(
@@ -124,25 +121,18 @@ for (const file of listSourceFiles(path.join(BACKEND_ROOT, 'src'))) {
}
}
// 已发布的历史迁移必须保持字节不变,所有结构或数据修复都必须新增迁移文件。
// 基线分支中存在的所有迁移都必须保持字节不变;新增文件不受影响。
// 这样保护范围会随着 main 的发布自动扩展,不再依赖手工维护版本号。
if (!MIGRATION_BASELINE_REF) {
console.warn('[check-sql] 未找到迁移基线分支(main / origin/main),跳过迁移字节检查')
} else {
try {
const diffOutput = execFileSync(
'git',
['diff', '--name-status', MIGRATION_BASELINE_REF, '--', 'src/db/migrations'],
['diff', '--name-status', '--no-renames', MIGRATION_BASELINE_REF, '--', 'src/db/migrations'],
{ cwd: BACKEND_ROOT, encoding: 'utf8' },
)
const changedHistoricalMigrations = diffOutput
.split('\n')
.map((line) => line.trim().split(/\s+/))
.filter(([status, file]) => {
if (!status || !file?.endsWith('.sql') || status === 'A') return false
const version = Number(path.basename(file).slice(0, 3))
return Number.isFinite(version) && version <= PUBLISHED_MIGRATION_MAX_VERSION
})
.map(([status, file]) => `${status} ${file}`)
const changedHistoricalMigrations = changedPublishedMigrations(diffOutput)
if (changedHistoricalMigrations.length > 0) {
failures.push(
`已发布迁移文件不可修改(基线 ${MIGRATION_BASELINE_REF}): ${changedHistoricalMigrations.join(', ')}`,