fix: 增加历史migration白名单,避免已知schema重构误报
CI Build & Deploy Pipeline / Build Staging Web Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Staging API Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Staging Worker Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Staging API Image (pull_request) Has been skipped
CI Build & Deploy Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI Build & Deploy Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI Build & Deploy Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been skipped
CI Build & Deploy Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI Build & Deploy Pipeline / Staging E2E Tests (push) Has been skipped
CI Build & Deploy Pipeline / Staging API Integration Tests (push) Has been skipped
CI Build & Deploy Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI Build & Deploy Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m35s
CI/CD Pipeline / Frontend Lint (push) Successful in 1m36s
CI Build & Deploy Pipeline / Build Production Web Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production API Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production Worker Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production API Image (pull_request) Has been skipped
CI Build & Deploy Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI Build & Deploy Pipeline / Build Production Web Image (pull_request) Has been skipped
CI Build & Deploy Pipeline / Deploy Production (push) Has been skipped
CI Build & Deploy Pipeline / Deploy Production (pull_request) Has been skipped
CI Build & Deploy Pipeline / Production Browser E2E (push) Has been skipped
CI Build & Deploy Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 3m8s
CI/CD Pipeline / Unit Tests (push) Successful in 3m9s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 17m8s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 17m8s
CI/CD Pipeline / Integration Tests (push) Successful in 1m34s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m36s
CI Build & Deploy Pipeline / Build Staging Web Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Staging API Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Staging Worker Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Staging API Image (pull_request) Has been skipped
CI Build & Deploy Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI Build & Deploy Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI Build & Deploy Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been skipped
CI Build & Deploy Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI Build & Deploy Pipeline / Staging E2E Tests (push) Has been skipped
CI Build & Deploy Pipeline / Staging API Integration Tests (push) Has been skipped
CI Build & Deploy Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI Build & Deploy Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m35s
CI/CD Pipeline / Frontend Lint (push) Successful in 1m36s
CI Build & Deploy Pipeline / Build Production Web Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production API Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production Worker Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production API Image (pull_request) Has been skipped
CI Build & Deploy Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI Build & Deploy Pipeline / Build Production Web Image (pull_request) Has been skipped
CI Build & Deploy Pipeline / Deploy Production (push) Has been skipped
CI Build & Deploy Pipeline / Deploy Production (pull_request) Has been skipped
CI Build & Deploy Pipeline / Production Browser E2E (push) Has been skipped
CI Build & Deploy Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 3m8s
CI/CD Pipeline / Unit Tests (push) Successful in 3m9s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 17m8s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 17m8s
CI/CD Pipeline / Integration Tests (push) Successful in 1m34s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m36s
- 新增SAFE_HISTORICAL_MIGRATIONS白名单机制 - 已执行过的历史schema重构(如016_phase8_edit_template_plan)不再误报 - 与push event before/after对比优化叠加,双重保障
This commit is contained in:
Regular → Executable
+46
-7
@@ -49,6 +49,15 @@ HIGH_RISK_PATTERNS = [
|
||||
(r"\bop\.drop_column\(", "op.drop_column() - 删除列,数据永久丢失"),
|
||||
]
|
||||
|
||||
# 已确认安全的历史 migration 白名单
|
||||
# 这些 migration 已在生产环境执行过,其中的高风险操作(如 drop_column)
|
||||
# 是经过确认的 schema 重构,不是意外的破坏性变更。
|
||||
# 格式:migration 文件名(不含 .py 后缀)
|
||||
SAFE_HISTORICAL_MIGRATIONS = {
|
||||
# Phase 8 模板/计划表重构,edit_templates 表 schema 替换
|
||||
"016_phase8_edit_template_plan",
|
||||
}
|
||||
|
||||
# 中风险模式:可能导致数据丢失或兼容性问题
|
||||
MEDIUM_RISK_PATTERNS = [
|
||||
(
|
||||
@@ -100,27 +109,51 @@ def extract_upgrade_content(content: str) -> str:
|
||||
return content[upgrade_start:upgrade_end]
|
||||
|
||||
|
||||
def _get_migration_files_at_ref(ref: str, api_url: str, repo: str, token: str) -> set:
|
||||
"""通过 API 获取指定 ref(分支/commit/tag)下的迁移文件名集合"""
|
||||
url = f"{api_url}/repos/{repo}/contents/alembic/versions?ref={ref}"
|
||||
req = urllib.request.Request(url, headers={"Authorization": f"token {token}"})
|
||||
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||
data = json.loads(resp.read().decode())
|
||||
return {item["name"] for item in data if item["name"].endswith(".py")}
|
||||
|
||||
|
||||
def get_new_migrations_via_diff(diff_target: str) -> List[Path]:
|
||||
"""
|
||||
通过 Gitea API 对比目标分支,找出 alembic/versions/ 下新增的迁移文件。
|
||||
通过 Gitea API 对比目标引用,找出 alembic/versions/ 下新增的迁移文件。
|
||||
不依赖本地 git,避免 CI 环境下 git 操作不稳定的问题。
|
||||
|
||||
push event 下优先使用 GITHUB_BEFORE/GITHUB_AFTER 对比本次 push 的变更范围;
|
||||
否则使用 diff_target 分支与当前本地文件对比。
|
||||
"""
|
||||
api_url = os.environ.get("GITHUB_API_URL", "")
|
||||
repo = os.environ.get("GITHUB_REPOSITORY", "")
|
||||
token = os.environ.get("GITHUB_TOKEN", "")
|
||||
branch = diff_target.replace("origin/", "")
|
||||
event_name = os.environ.get("GITHUB_EVENT_NAME", "")
|
||||
before_sha = os.environ.get("GITHUB_BEFORE", "")
|
||||
after_sha = os.environ.get("GITHUB_AFTER", os.environ.get("GITHUB_SHA", ""))
|
||||
|
||||
if not api_url or not repo or not token:
|
||||
print("⚠️ CI 环境变量不完整,降级为检查所有迁移文件")
|
||||
return sorted(ALEMBIC_VERSIONS_DIR.glob("*.py"))
|
||||
|
||||
try:
|
||||
url = f"{api_url}/repos/{repo}/contents/alembic/versions?ref={branch}"
|
||||
req = urllib.request.Request(url, headers={"Authorization": f"token {token}"})
|
||||
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||
data = json.loads(resp.read().decode())
|
||||
# push event: 用 before/after 精确对比本次 push 新增的迁移
|
||||
if event_name == "push" and before_sha and after_sha and before_sha != "0" * 40:
|
||||
before_files = _get_migration_files_at_ref(before_sha, api_url, repo, token)
|
||||
after_files = _get_migration_files_at_ref(after_sha, api_url, repo, token)
|
||||
new_file_names = sorted(after_files - before_files)
|
||||
if new_file_names:
|
||||
result = [ALEMBIC_VERSIONS_DIR / f for f in new_file_names]
|
||||
print(f" (push event,对比 {before_sha[:8]}..{after_sha[:8]},发现 {len(result)} 个新增迁移)")
|
||||
return result
|
||||
else:
|
||||
print(f" (push event,对比 {before_sha[:8]}..{after_sha[:8]},无新增迁移)")
|
||||
return []
|
||||
|
||||
remote_files = {item["name"] for item in data if item["name"].endswith(".py")}
|
||||
# PR/其他场景: 对比目标分支与当前本地文件
|
||||
branch = diff_target.replace("origin/", "")
|
||||
remote_files = _get_migration_files_at_ref(branch, api_url, repo, token)
|
||||
local_files = {f.name for f in ALEMBIC_VERSIONS_DIR.glob("*.py")}
|
||||
new_file_names = sorted(local_files - remote_files)
|
||||
|
||||
@@ -169,6 +202,12 @@ def analyze_migration(file_path: Path) -> Tuple[List[str], List[str], List[str]]
|
||||
if not upgrade_content:
|
||||
return [], [], [f"{file_path.name}: 未找到 upgrade 函数"]
|
||||
|
||||
# 已确认安全的历史 migration 直接跳过,避免历史已知的 schema 重构误报
|
||||
migration_stem = file_path.stem
|
||||
if migration_stem in SAFE_HISTORICAL_MIGRATIONS:
|
||||
safes = [f"{file_path.name}: 已确认安全的历史迁移(白名单)"]
|
||||
return [], [], safes
|
||||
|
||||
high_risks = []
|
||||
medium_risks = []
|
||||
safes = []
|
||||
|
||||
Reference in New Issue
Block a user