fix(ci): 修复数据库安全闸门误报,改为只对比main检查新增迁移
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (push) Failing after 15h3m16s
CI/CD Pipeline / Frontend Lint (push) Failing after 15h5m54s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 15h5m54s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1673h37m47s
CI/CD Pipeline / Deploy Production (push) Failing after 1673h39m19s
CI/CD Pipeline / Build Production Runtime Images (push) Failing after 1673h39m21s
CI/CD Pipeline / Production Browser E2E (push) Failing after 1674h10m45s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (push) Failing after 15h3m16s
CI/CD Pipeline / Frontend Lint (push) Failing after 15h5m54s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 15h5m54s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1673h37m47s
CI/CD Pipeline / Deploy Production (push) Failing after 1673h39m19s
CI/CD Pipeline / Build Production Runtime Images (push) Failing after 1673h39m21s
CI/CD Pipeline / Production Browser E2E (push) Failing after 1674h10m45s
- check_migration_safety.py 新增 --diff-against 参数,支持通过 git diff 只检查新增迁移 - CI 中 prepare git 环境并 fetch origin/main,安全闸门对比 main 分支 - 避免历史已执行迁移的破坏性操作导致误报
This commit is contained in:
@@ -129,11 +129,34 @@ jobs:
|
||||
grep -q "Running upgrade" /tmp/alembic-upgrade.sql
|
||||
python3 scripts/check_schema_metadata.py
|
||||
|
||||
- name: Prepare git for migration diff
|
||||
shell: sh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -eu
|
||||
if command -v git >/dev/null 2>&1; then
|
||||
git init -q
|
||||
git config user.email "ci@localhost"
|
||||
git config user.name "CI"
|
||||
git add .
|
||||
git commit -q -m "current"
|
||||
REPO_URL="https://x-access-token:${GITHUB_TOKEN}@${GITHUB_SERVER_URL#https://}/${GITHUB_REPOSITORY}.git"
|
||||
git remote add origin "$REPO_URL"
|
||||
git fetch origin main --depth=1 -q 2>/dev/null || echo "WARN: cannot fetch main, will check all migrations"
|
||||
else
|
||||
echo "WARN: git not available, will check all migrations"
|
||||
fi
|
||||
|
||||
- name: Check migration safety
|
||||
shell: sh
|
||||
run: |
|
||||
set -eu
|
||||
python3 scripts/check_migration_safety.py --allow-medium-risk
|
||||
if git rev-parse origin/main >/dev/null 2>&1; then
|
||||
python3 scripts/check_migration_safety.py --allow-medium-risk --diff-against origin/main
|
||||
else
|
||||
python3 scripts/check_migration_safety.py --allow-medium-risk
|
||||
fi
|
||||
|
||||
- name: Run unit tests
|
||||
shell: sh
|
||||
|
||||
@@ -11,6 +11,16 @@
|
||||
|
||||
忽略 downgrade 函数中的操作(那是回滚逻辑,正常的)。
|
||||
|
||||
使用方式:
|
||||
# 检查所有迁移(不推荐,会扫历史已执行的迁移)
|
||||
python3 scripts/check_migration_safety.py
|
||||
|
||||
# 只检查与目标分支相比新增的迁移(推荐用于CI)
|
||||
python3 scripts/check_migration_safety.py --diff-against origin/main
|
||||
|
||||
# 只检查指定版本之后的迁移
|
||||
python3 scripts/check_migration_safety.py --since 030_xxx
|
||||
|
||||
退出码:
|
||||
0 - 安全 / 只有非破坏性变更
|
||||
1 - 检测到高风险破坏性变更
|
||||
@@ -22,6 +32,7 @@ from __future__ import annotations
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple
|
||||
@@ -60,7 +71,6 @@ def extract_upgrade_content(content: str) -> str:
|
||||
从迁移文件中提取 upgrade 函数的内容。
|
||||
只检查 upgrade 中的操作,忽略 downgrade。
|
||||
"""
|
||||
# 匹配 def upgrade(): 或 def upgrade() -> None: 等格式
|
||||
upgrade_match = re.search(r"def upgrade\b[^:]*:", content)
|
||||
if not upgrade_match:
|
||||
return ""
|
||||
@@ -78,12 +88,35 @@ def extract_upgrade_content(content: str) -> str:
|
||||
return content[upgrade_start:upgrade_end]
|
||||
|
||||
|
||||
def find_new_migrations(since_revision: str | None = None) -> List[Path]:
|
||||
def get_new_migrations_via_diff(diff_target: str) -> List[Path]:
|
||||
"""
|
||||
找出新增的迁移文件。
|
||||
如果指定了 since_revision,则找出该版本之后的所有迁移;
|
||||
否则找出所有迁移文件。
|
||||
通过 git diff 对比目标分支/commit,找出 alembic/versions/ 下新增的迁移文件。
|
||||
只包含新增文件(A状态),不包含修改或删除的文件。
|
||||
"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["git", "diff", "--name-only", "--diff-filter=A", diff_target, "HEAD", "--", "alembic/versions/"],
|
||||
cwd=str(REPO_ROOT),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
files = [line.strip() for line in result.stdout.strip().split("\n") if line.strip()]
|
||||
return [REPO_ROOT / f for f in files]
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"⚠️ git diff 失败({diff_target}):{e.stderr.strip()}")
|
||||
print(f" 降级为检查所有迁移文件")
|
||||
return sorted(ALEMBIC_VERSIONS_DIR.glob("*.py"))
|
||||
|
||||
|
||||
def find_new_migrations(since_revision: str | None = None, diff_against: str | None = None) -> List[Path]:
|
||||
"""
|
||||
找出需要检查的迁移文件。
|
||||
优先级:diff_against > since_revision > 全部
|
||||
"""
|
||||
if diff_against:
|
||||
return get_new_migrations_via_diff(diff_against)
|
||||
|
||||
all_migrations = sorted(ALEMBIC_VERSIONS_DIR.glob("*.py"))
|
||||
if not since_revision:
|
||||
return all_migrations
|
||||
@@ -134,6 +167,11 @@ def main() -> int:
|
||||
default=os.getenv("MIGRATION_SINCE_REVISION"),
|
||||
help="只检查指定版本之后的迁移(如:030_xxx),不传则检查所有迁移",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--diff-against",
|
||||
default=os.getenv("MIGRATION_DIFF_AGAINST"),
|
||||
help="对比指定分支/commit,只检查新增的迁移文件(推荐用于CI,如 origin/main)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--warn-only",
|
||||
action="store_true",
|
||||
@@ -146,13 +184,15 @@ def main() -> int:
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
migrations = find_new_migrations(args.since)
|
||||
migrations = find_new_migrations(args.since, args.diff_against)
|
||||
|
||||
if not migrations:
|
||||
print("✅ 未找到需要检查的迁移文件")
|
||||
print("✅ 未找到需要检查的新增迁移文件,跳过")
|
||||
return 0
|
||||
|
||||
print(f"🔍 正在检查 {len(migrations)} 个迁移文件的 upgrade 操作...")
|
||||
if args.diff_against:
|
||||
print(f" (对比基准:{args.diff_against},仅检查新增迁移)")
|
||||
print()
|
||||
|
||||
all_high = []
|
||||
|
||||
Reference in New Issue
Block a user