From 48dc5ac8e4ba069c11512f01304f3f9507cb2dd7 Mon Sep 17 00:00:00 2001 From: dongzi Date: Thu, 4 Jun 2026 16:57:08 +0800 Subject: [PATCH] =?UTF-8?q?py=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/checker/comparator.py | 99 +++++++++++++++++++++++++----------- .gitea/checker/notifier.py | 41 +++++++++++---- 2 files changed, 101 insertions(+), 39 deletions(-) diff --git a/.gitea/checker/comparator.py b/.gitea/checker/comparator.py index 1b73e66..418168f 100644 --- a/.gitea/checker/comparator.py +++ b/.gitea/checker/comparator.py @@ -86,6 +86,8 @@ class EndpointChangeReport: parameter_changes: List[ParameterChange] = field(default_factory=list) is_new_endpoint: bool = False is_removed_endpoint: bool = False + is_renamed_endpoint: bool = False + old_uri: Optional[str] = None @property def has_changes(self) -> bool: @@ -93,6 +95,7 @@ class EndpointChangeReport: return ( self.is_new_endpoint or self.is_removed_endpoint + or self.is_renamed_endpoint or len(self.parameter_changes) > 0 ) @@ -215,26 +218,75 @@ def compare_endpoints( """ 对比新旧两个版本的全部 Controller 端点,生成变更报告列表。 - :param old_endpoints: 旧版本 { endpoint_key: ApiEndpoint } - :param new_endpoints: 新版本 { endpoint_key: ApiEndpoint } - :return: 有变更的接口报告列表 + 支持 URI 重命名检测(路径变更)。 """ reports: List[EndpointChangeReport] = [] - all_keys = set(old_endpoints.keys()) | set(new_endpoints.keys()) + old_keys = set(old_endpoints.keys()) + new_keys = set(new_endpoints.keys()) - for key in sorted(all_keys): - old_ep = old_endpoints.get(key) - new_ep = new_endpoints.get(key) + removed_keys = old_keys - new_keys + added_keys = new_keys - old_keys + common_keys = old_keys & new_keys - if old_ep is None and new_ep is not None: - # 全新接口 + # 1. URI 重命名检测:在 removed + added 中找 method+controller+method_name 相同的配对 + unmatched_removed: List[Tuple[str, ApiEndpoint]] = [] + unmatched_added: List[Tuple[str, ApiEndpoint]] = [] + + for key in removed_keys: + unmatched_removed.append((key, old_endpoints[key])) + for key in added_keys: + unmatched_added.append((key, new_endpoints[key])) + + matched_removed: Set[str] = set() + matched_added: Set[str] = set() + + for r_key, r_ep in unmatched_removed: + for a_key, a_ep in unmatched_added: + if a_key in matched_added: + continue + # 匹配条件:method 相同 + controller 相同 + method_name 相同 + if ( + r_ep.http_method == a_ep.http_method + and r_ep.controller_class == a_ep.controller_class + and r_ep.method_name == a_ep.method_name + ): + reports.append( + EndpointChangeReport( + uri=a_ep.uri, + http_method=a_ep.http_method, + controller_class=a_ep.controller_class, + method_name=a_ep.method_name, + is_renamed_endpoint=True, + old_uri=r_ep.uri, + ) + ) + matched_removed.add(r_key) + matched_added.add(a_key) + break + + # 2. 剩余未匹配的 removed → 删除接口 + for key, ep in unmatched_removed: + if key not in matched_removed: reports.append( EndpointChangeReport( - uri=new_ep.uri, - http_method=new_ep.http_method, - controller_class=new_ep.controller_class, - method_name=new_ep.method_name, + uri=ep.uri, + http_method=ep.http_method, + controller_class=ep.controller_class, + method_name=ep.method_name, + is_removed_endpoint=True, + ) + ) + + # 3. 剩余未匹配的 added → 新增接口 + for key, ep in unmatched_added: + if key not in matched_added: + reports.append( + EndpointChangeReport( + uri=ep.uri, + http_method=ep.http_method, + controller_class=ep.controller_class, + method_name=ep.method_name, is_new_endpoint=True, parameter_changes=[ ParameterChange( @@ -243,26 +295,15 @@ def compare_endpoints( param_type=p.type, required=p.required, ) - for p in new_ep.parameters + for p in ep.parameters ], ) ) - continue - if new_ep is None and old_ep is not None: - # 接口被删除 - reports.append( - EndpointChangeReport( - uri=old_ep.uri, - http_method=old_ep.http_method, - controller_class=old_ep.controller_class, - method_name=old_ep.method_name, - is_removed_endpoint=True, - ) - ) - continue - - # 同 URI 对比参数 + # 4. 共同 URI:对比参数变更 + for key in common_keys: + old_ep = old_endpoints[key] + new_ep = new_endpoints[key] param_changes = compare_parameters(old_ep.parameters, new_ep.parameters) if param_changes: reports.append( diff --git a/.gitea/checker/notifier.py b/.gitea/checker/notifier.py index 80b1c7e..8cd4a4c 100644 --- a/.gitea/checker/notifier.py +++ b/.gitea/checker/notifier.py @@ -47,7 +47,6 @@ def _format_endpoint_block(report: EndpointChangeReport) -> str: detail_lines.append("### 参数变更明细") if report.parameter_changes: - # 简化:使用列表格式匹配模板 for change in report.parameter_changes: md = change.to_markdown_line(plain=report.is_new_endpoint) detail_lines.append(md) @@ -72,19 +71,41 @@ def build_markdown_notification( :param llm_summary: LLM 兼容性摘要(可选,简短) :return: Markdown 文本 """ - parts = [ - "# API参数变更通知", - f"- **变更类型:** 修改参数", - f"- **修改人:** {push_user}", - f"- **修改时间:** {push_time}", - "", - ] + parts: List[str] = [] - # 新增 Controller(全部为新接口)与变更接口分组 + # 分组:路径变更、参数变更、新增、删除 + renamed_reports = [r for r in reports if r.is_renamed_endpoint] new_reports = [r for r in reports if r.is_new_endpoint] - changed_reports = [r for r in reports if not r.is_new_endpoint and not r.is_removed_endpoint] + changed_reports = [ + r for r in reports + if not r.is_new_endpoint and not r.is_removed_endpoint and not r.is_renamed_endpoint + ] removed_reports = [r for r in reports if r.is_removed_endpoint] + # 路径变更优先使用 model1.md 模板 + for report in renamed_reports: + old_uri = report.old_uri or "-" + new_uri = report.uri or "已删除" + path_md = build_path_change_markdown( + old_uri=old_uri, + new_uri=new_uri, + change_type="修改路径", + push_user=push_user, + push_time=push_time, + file_name=report.controller_class, + ) + parts.append(path_md) + parts.append("") + + if new_reports or changed_reports or removed_reports: + parts.extend([ + "# API参数变更通知", + f"- **变更类型:** 修改参数", + f"- **修改人:** {push_user}", + f"- **修改时间:** {push_time}", + "", + ]) + for report in new_reports: parts.append(_format_endpoint_block(report)) parts.append("")