Some checks failed
API Parameter Change Check / api-param-check (push) Failing after 3s
166 lines
5.1 KiB
Python
166 lines
5.1 KiB
Python
"""
|
||
变更日志持久化模块。
|
||
受 log.enabled 开关控制,默认关闭;仅记录接口参数变更及 LLM 审核结果。
|
||
"""
|
||
|
||
import json
|
||
from datetime import datetime
|
||
from pathlib import Path
|
||
from typing import Any, Dict, List, Optional
|
||
|
||
from comparator import EndpointChangeReport
|
||
from git_utils import CommitInfo
|
||
|
||
|
||
def is_log_enabled(config: Dict[str, Any]) -> bool:
|
||
"""判断日志总开关是否开启。"""
|
||
return config.get("log", {}).get("enabled", False)
|
||
|
||
|
||
def _serialize_reports(reports: List[EndpointChangeReport]) -> List[dict]:
|
||
"""将参数变更报告序列化为 JSON 结构。"""
|
||
result = []
|
||
for r in reports:
|
||
result.append(
|
||
{
|
||
"uri": r.uri,
|
||
"http_method": r.http_method,
|
||
"controller_class": r.controller_class,
|
||
"method_name": r.method_name,
|
||
"is_new_endpoint": r.is_new_endpoint,
|
||
"is_removed_endpoint": r.is_removed_endpoint,
|
||
"parameter_changes": [
|
||
{
|
||
"change_type": c.change_type.value,
|
||
"param_name": c.param_name,
|
||
"param_type": c.param_type,
|
||
"old_name": c.old_name,
|
||
"old_type": c.old_type,
|
||
"required": c.required,
|
||
"detail": c.detail,
|
||
}
|
||
for c in r.parameter_changes
|
||
],
|
||
}
|
||
)
|
||
return result
|
||
|
||
|
||
def save_to_file(
|
||
reports: List[EndpointChangeReport],
|
||
commit_info: CommitInfo,
|
||
log_dir: str,
|
||
llm_review: Optional[str] = None,
|
||
) -> Path:
|
||
"""写入 JSON 日志文件。"""
|
||
log_path = Path(log_dir)
|
||
log_path.mkdir(parents=True, exist_ok=True)
|
||
|
||
short_sha = commit_info.sha[:8]
|
||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||
output = log_path / f"{timestamp}_{short_sha}.json"
|
||
|
||
record = {
|
||
"commit_sha": commit_info.sha,
|
||
"author": commit_info.author,
|
||
"commit_time": commit_info.commit_time,
|
||
"message": commit_info.message,
|
||
"detected_at": datetime.now().isoformat(),
|
||
"change_count": len(reports),
|
||
"parameter_changes": _serialize_reports(reports),
|
||
"llm_review": llm_review,
|
||
}
|
||
|
||
with open(output, "w", encoding="utf-8") as f:
|
||
json.dump(record, f, ensure_ascii=False, indent=2)
|
||
|
||
print(f"[日志] 参数变更记录已写入: {output}")
|
||
return output
|
||
|
||
|
||
def save_to_mysql(
|
||
reports: List[EndpointChangeReport],
|
||
commit_info: CommitInfo,
|
||
mysql_config: Dict[str, Any],
|
||
llm_review: Optional[str] = None,
|
||
) -> bool:
|
||
"""写入 MySQL。"""
|
||
try:
|
||
import pymysql
|
||
except ImportError:
|
||
print("[错误] MySQL 模式需要: pip install pymysql")
|
||
return False
|
||
|
||
host = mysql_config.get("host", "")
|
||
if not host or host == "YOUR_MYSQL_HOST":
|
||
print("[警告] 未配置 MySQL,跳过写入。")
|
||
return False
|
||
|
||
try:
|
||
conn = pymysql.connect(
|
||
host=host,
|
||
port=int(mysql_config.get("port", 3306)),
|
||
user=mysql_config.get("user"),
|
||
password=mysql_config.get("password"),
|
||
database=mysql_config.get("database"),
|
||
charset="utf8mb4",
|
||
)
|
||
table = mysql_config.get("table", "api_change_logs")
|
||
payload = json.dumps(_serialize_reports(reports), ensure_ascii=False)
|
||
|
||
with conn.cursor() as cursor:
|
||
sql = f"""
|
||
INSERT INTO `{table}`
|
||
(commit_sha, author, commit_time, commit_message, change_count, reports_json, llm_review, created_at)
|
||
VALUES (%s, %s, %s, %s, %s, %s, %s, NOW())
|
||
"""
|
||
cursor.execute(
|
||
sql,
|
||
(
|
||
commit_info.sha,
|
||
commit_info.author,
|
||
commit_info.commit_time,
|
||
commit_info.message,
|
||
len(reports),
|
||
payload,
|
||
llm_review,
|
||
),
|
||
)
|
||
conn.commit()
|
||
conn.close()
|
||
print(f"[日志] 已写入 MySQL: {table}")
|
||
return True
|
||
except Exception as exc:
|
||
print(f"[错误] MySQL 写入失败: {exc}")
|
||
return False
|
||
|
||
|
||
def persist_change_log(
|
||
reports: List[EndpointChangeReport],
|
||
commit_info: CommitInfo,
|
||
config: Dict[str, Any],
|
||
llm_review: Optional[str] = None,
|
||
) -> None:
|
||
"""
|
||
根据 log.enabled 决定是否持久化接口参数变更日志。
|
||
|
||
:param reports: 参数变更报告
|
||
:param commit_info: 提交信息
|
||
:param config: 完整配置
|
||
:param llm_review: LLM 参数变更审核结论
|
||
"""
|
||
if not is_log_enabled(config):
|
||
print("[日志] 日志开关已关闭(log.enabled=false),跳过写入。")
|
||
return
|
||
|
||
log_cfg = config.get("log", {})
|
||
if log_cfg.get("storage") == "mysql":
|
||
save_to_mysql(reports, commit_info, log_cfg.get("mysql", {}), llm_review)
|
||
else:
|
||
save_to_file(
|
||
reports,
|
||
commit_info,
|
||
log_cfg.get("file_dir", ".gitea/logs/api-changes"),
|
||
llm_review,
|
||
)
|