脚本修改
Some checks failed
API接口参数变更检测 / api-param-check (push) Has been cancelled

This commit is contained in:
2026-06-03 15:33:24 +08:00
parent 6db621a137
commit 2c20a26af8
15 changed files with 136 additions and 897 deletions

View File

@@ -1,114 +1,43 @@
"""
Controller 端点解析模块。
调用 Java AST 解析器 JAR将 Java 源码转为结构化的 API 端点列表。
Controller 端点解析模块(纯 Python无需 Java
"""
import json
import subprocess
from dataclasses import dataclass, field
from pathlib import Path
from typing import Dict, List, Optional
from typing import Dict, List
@dataclass
class ApiParameter:
"""单个接口参数。"""
name: str
type: str
required: bool = True
source: str = "query"
description: Optional[str] = None
@dataclass
class ApiEndpoint:
"""单个 Controller 接口端点。"""
http_method: str
uri: str
controller_class: str
method_name: str
source_file: str
parameters: List[ApiParameter] = field(default_factory=list)
@property
def endpoint_key(self) -> str:
"""唯一标识HTTP 方法 + URI用于跨版本匹配。"""
return f"{self.http_method} {self.uri}"
def run_java_parser(source_dir: Path, jar_path: Path, output_json: Path) -> List[ApiEndpoint]:
"""
调用 JavaParser JAR 扫描源码目录,返回解析结果。
:param source_dir: Java 源码根目录
:param jar_path: controller-parser JAR 路径
:param output_json: 临时 JSON 输出路径
:return: ApiEndpoint 列表
:raises RuntimeError: Java 进程失败或 JAR 不存在
"""
if not jar_path.exists():
raise RuntimeError(
f"Java 解析器 JAR 不存在: {jar_path}\n"
"请先在 .gitea/java-parser 目录执行: mvn -q package"
)
cmd = ["java", "-jar", str(jar_path), str(source_dir), str(output_json)]
result = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8")
if result.returncode != 0:
raise RuntimeError(f"Java 解析器执行失败:\n{result.stderr}")
with open(output_json, "r", encoding="utf-8") as f:
raw = json.load(f)
return [_dict_to_endpoint(item) for item in raw]
def _dict_to_endpoint(data: dict) -> ApiEndpoint:
"""将 JSON 字典转换为 ApiEndpoint 对象。"""
params = [
ApiParameter(
name=p.get("name", ""),
type=p.get("type", ""),
required=p.get("required", True),
source=p.get("source", "query"),
description=p.get("description"),
)
for p in data.get("parameters", [])
]
return ApiEndpoint(
http_method=data.get("httpMethod", "GET"),
uri=data.get("uri", "/"),
controller_class=data.get("controllerClass", ""),
method_name=data.get("methodName", ""),
source_file=data.get("sourceFile", ""),
parameters=params,
)
from models import ApiEndpoint, ApiParameter
def endpoints_to_map(endpoints: List[ApiEndpoint]) -> Dict[str, ApiEndpoint]:
"""
将端点列表转为字典key 为 endpoint_key。
:param endpoints: 端点列表
:return: { "GET /api/users/{id}": ApiEndpoint, ... }
"""
"""端点列表转字典key 为 endpoint_key。"""
return {ep.endpoint_key: ep for ep in endpoints}
def filter_endpoints_by_files(
endpoints: List[ApiEndpoint], changed_files: List[str]
) -> List[ApiEndpoint]:
"""
仅保留源文件在变更列表中的端点(缩小对比范围)。
:param endpoints: 全部端点
:param changed_files: 变更文件相对路径列表
:return: 过滤后的端点
"""
"""仅保留变更文件中的端点。"""
if not changed_files:
return endpoints
changed_set = set(changed_files)
changed_set = {f.replace("\\", "/") for f in changed_files}
return [ep for ep in endpoints if ep.source_file in changed_set]
def parse_endpoints_from_files(
repo_root: Path,
source_subdir: str,
file_paths: List[str],
file_contents: Dict[str, str],
) -> List[ApiEndpoint]:
"""
解析指定 Controller 文件,提取接口参数(仅解析传入文件,不全量扫描)。
:param repo_root: 仓库根
:param source_subdir: 源码目录(相对仓库根)
:param file_paths: 文件路径列表
:param file_contents: 路径 -> 源码内容
:return: ApiEndpoint 列表
"""
from controller_ast_parser import parse_controller_files
return parse_controller_files(repo_root, source_subdir, file_paths, file_contents)