API 版本与破坏性变更检测引擎(专业版)
输入
detect_breaking(old,new);is_breaking_change(old,new);semver_bump(breaking,added_optional,patch_only)
字段值可写类型字符串,或 {{"type":"string","required":True}}
输出
破坏性变更元组列表 (类型, 详情);是否 breaking;major/minor/patch
硬性规则
- 破坏性四类:field_removed/type_changed/became_required/new_required_field。
- 有任一破坏性→major;仅新增可选→minor;否则 patch。
- 字段缺失与类型变化分开报告,不合并。
示例
detect_breaking({{"id":"string"}},{{}}) → [("field_removed","id")]
is_breaking_change({{"a":"string"}},{{"a":"integer"}}) → True
semver_bump(False, added_optional=True) → "minor"
Python 引擎(可独立运行)
# -*- coding: utf-8 -*-
def detect_breaking(old, new):
"""old/new: {字段: 类型或 {'type':..,'required':bool}};返回破坏性变更列表"""
def norm(f):
if isinstance(f, dict): return f.get("type"), bool(f.get("required", False))
return f, False
breaks = []
for name, spec in old.items():
ot, oreq = norm(spec)
if name not in new:
breaks.append(("field_removed", name)); continue
nt, nreq = norm(new[name])
if ot != nt:
breaks.append(("type_changed", f"{name}:{ot}->{nt}"))
if (not oreq) and nreq:
breaks.append(("became_required", name))
for name, spec in new.items():
if name not in old and norm(spec)[1]:
breaks.append(("new_required_field", name))
return breaks
def semver_bump(breaking, added_optional=False, patch_only=False):
if breaking: return "major"
if added_optional: return "minor"
if patch_only: return "patch"
return "patch"
def is_breaking_change(old, new):
return len(detect_breaking(old, new)) > 0