@@ -1,272 +0,0 @@
|
||||
package com.codechecker.api.notify;
|
||||
|
||||
import com.codechecker.api.model.ApiChangeKind;
|
||||
import com.codechecker.api.model.EndpointChangeReport;
|
||||
import com.codechecker.api.model.ParameterChange;
|
||||
import com.codechecker.common.MarkdownStyles;
|
||||
import com.codechecker.common.WeComMarkdownSender;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* API 变更通知(路径 / 请求方式 / 参数分类型、分条发送,与类变更通知解耦)。
|
||||
*/
|
||||
public class ApiChangeNotifier {
|
||||
private final WeComMarkdownSender sender = new WeComMarkdownSender();
|
||||
|
||||
public int sendAll(String webhookUrl, List<EndpointChangeReport> reports,
|
||||
String modifier, String modifyTime, boolean wecomEnabled) {
|
||||
if (reports == null || reports.isEmpty()) {
|
||||
System.out.println("无 API 变更,不发送通知");
|
||||
return 0;
|
||||
}
|
||||
int sent = 0;
|
||||
for (EndpointChangeReport report : reports) {
|
||||
String markdown = buildMarkdown(report, modifier, modifyTime);
|
||||
if (wecomEnabled) {
|
||||
if (sender.send(webhookUrl, markdown)) {
|
||||
sent++;
|
||||
System.out.println("已发送 API 变更通知: " + report.getChangeKind()
|
||||
+ " " + report.getHttpMethod() + " " + report.getUri());
|
||||
}
|
||||
} else {
|
||||
sender.logPreview("API 变更 [" + report.getChangeKind() + "]", markdown);
|
||||
sent++;
|
||||
}
|
||||
}
|
||||
if (sent > 0) {
|
||||
System.out.println("总共发送 " + sent + " 条 API 变更通知");
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
public String buildMarkdown(EndpointChangeReport report, String modifier, String modifyTime) {
|
||||
ApiChangeKind kind = report.getChangeKind();
|
||||
if (kind == ApiChangeKind.PATH_CHANGED
|
||||
|| kind == ApiChangeKind.NEW_ENDPOINT
|
||||
|| kind == ApiChangeKind.REMOVED_ENDPOINT) {
|
||||
return buildPathMarkdown(report, modifier, modifyTime);
|
||||
}
|
||||
if (kind == ApiChangeKind.METHOD_CHANGED) {
|
||||
return buildMethodMarkdown(report, modifier, modifyTime);
|
||||
}
|
||||
return buildParamMarkdown(report, modifier, modifyTime);
|
||||
}
|
||||
|
||||
private String buildPathMarkdown(EndpointChangeReport report, String modifier, String modifyTime) {
|
||||
String changeLabel;
|
||||
switch (report.getChangeKind()) {
|
||||
case NEW_ENDPOINT:
|
||||
changeLabel = "新增接口";
|
||||
break;
|
||||
case REMOVED_ENDPOINT:
|
||||
changeLabel = "删除接口";
|
||||
break;
|
||||
default:
|
||||
changeLabel = "修改路径";
|
||||
break;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("# 【API路径变更通知】").append("\n\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("变更类型", MarkdownStyles.colorWarning(changeLabel))).append("\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("路径",
|
||||
MarkdownStyles.colorInfo(MarkdownStyles.safe(report.getSourceFile())))).append("\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("修改人", MarkdownStyles.colorComment(modifier))).append("\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("时间", MarkdownStyles.colorComment(modifyTime))).append("\n");
|
||||
sb.append("\n## 【URI变更详情】").append("\n\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("接口说明", formatEndpointDescription(report))).append("\n");
|
||||
appendPathUriLines(sb, report, changeLabel);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void appendPathUriLines(StringBuilder sb, EndpointChangeReport report, String changeLabel) {
|
||||
if ("新增接口".equals(changeLabel)) {
|
||||
sb.append(MarkdownStyles.quoteKvBold("原路径", "`-`")).append("\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("新路径",
|
||||
formatUriWithMethod(report.getHttpMethod(), report.getUri(), true)
|
||||
+ " " + MarkdownStyles.colorInfo("[新增]"))).append("\n");
|
||||
} else if ("删除接口".equals(changeLabel)) {
|
||||
sb.append(MarkdownStyles.quoteKvBold("原路径",
|
||||
formatUriWithMethod(report.getHttpMethod(), report.getUri(), false)
|
||||
+ " " + MarkdownStyles.colorWarning("[已删除]"))).append("\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("新路径", "`已删除`")).append("\n");
|
||||
} else {
|
||||
sb.append(MarkdownStyles.quoteKvBold("原路径",
|
||||
formatUriWithMethod(report.getHttpMethod(), report.getOldUri(), false)
|
||||
+ " " + MarkdownStyles.colorWarning("[旧路径]"))).append("\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("新路径",
|
||||
formatUriWithMethod(report.getHttpMethod(), report.getUri(), true)
|
||||
+ " " + MarkdownStyles.colorInfo("[新路径]"))).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
private String buildMethodMarkdown(EndpointChangeReport report, String modifier, String modifyTime) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("# 【API请求方式变更通知】").append("\n\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("变更类型", MarkdownStyles.colorWarning("修改请求方式"))).append("\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("路径",
|
||||
MarkdownStyles.colorInfo(MarkdownStyles.safe(report.getSourceFile())))).append("\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("修改人", MarkdownStyles.colorComment(modifier))).append("\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("时间", MarkdownStyles.colorComment(modifyTime))).append("\n");
|
||||
sb.append("\n## 【请求方式变更详情】").append("\n\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("接口说明", formatEndpointDescription(report))).append("\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("URI", MarkdownStyles.colorInfo(report.getUri()))).append("\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("原请求方式",
|
||||
MarkdownStyles.colorWarning(report.getOldHttpMethod()))).append("\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("新请求方式",
|
||||
MarkdownStyles.colorInfo(report.getHttpMethod()) + " "
|
||||
+ MarkdownStyles.colorInfo("[请求方式已变更]"))).append("\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String buildParamMarkdown(EndpointChangeReport report, String modifier, String modifyTime) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("# 【API参数变更通知】").append("\n\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("修改人", MarkdownStyles.colorComment(modifier))).append("\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("时间", MarkdownStyles.colorComment(modifyTime))).append("\n");
|
||||
//sb.append(MarkdownStyles.quoteKvBold("变更类型", MarkdownStyles.colorWarning("修改参数"))).append("\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("URI",
|
||||
MarkdownStyles.colorInfo(report.getHttpMethod()) + " "
|
||||
+ MarkdownStyles.inlineCode(report.getUri()))).append("\n");
|
||||
sb.append(MarkdownStyles.quoteKvBold("路径",
|
||||
MarkdownStyles.colorInfo(MarkdownStyles.safe(report.getSourceFile())))).append("\n");
|
||||
sb.append("\n## 【接口参数变动详情】").append("\n\n");
|
||||
appendParameterDetails(sb, report);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void appendParameterDetails(StringBuilder sb, EndpointChangeReport report) {
|
||||
List<ParameterChange> bodyChanges = new ArrayList<>();
|
||||
List<ParameterChange> regularChanges = new ArrayList<>();
|
||||
for (ParameterChange change : report.getParameterChanges()) {
|
||||
if (change.isBodyField()) {
|
||||
bodyChanges.add(change);
|
||||
} else {
|
||||
regularChanges.add(change);
|
||||
}
|
||||
}
|
||||
if (!bodyChanges.isEmpty()) {
|
||||
sb.append("**类对象变更(含嵌套对象字段)**").append("\n\n");
|
||||
appendBodyGroups(sb, bodyChanges);
|
||||
sb.append("\n");
|
||||
}
|
||||
if (!regularChanges.isEmpty()) {
|
||||
sb.append("**普通参数变更**").append("\n\n");
|
||||
sb.append(MarkdownStyles.quoteLine("**共 "
|
||||
+ MarkdownStyles.colorWarning(String.valueOf(regularChanges.size()))
|
||||
+ " 项变更**")).append("\n\n");
|
||||
for (ParameterChange change : regularChanges) {
|
||||
sb.append(formatParameterLine(change)).append("\n\n");
|
||||
}
|
||||
}
|
||||
if (bodyChanges.isEmpty() && regularChanges.isEmpty()) {
|
||||
sb.append(MarkdownStyles.quoteLine(MarkdownStyles.colorComment("无"))).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
private void appendBodyGroups(StringBuilder sb, List<ParameterChange> bodyChanges) {
|
||||
Map<String, List<ParameterChange>> groups = new LinkedHashMap<>();
|
||||
for (ParameterChange change : bodyChanges) {
|
||||
String key = change.getParentDto() == null || change.getParentDto().isBlank()
|
||||
? (change.getBodyParamName() == null ? "body" : change.getBodyParamName())
|
||||
: change.getParentDto();
|
||||
groups.computeIfAbsent(key, k -> new ArrayList<>()).add(change);
|
||||
}
|
||||
int total = bodyChanges.size();
|
||||
sb.append(MarkdownStyles.quoteLine("**共 "
|
||||
+ MarkdownStyles.colorWarning(String.valueOf(groups.size()))
|
||||
+ " 个类对象 · "
|
||||
+ MarkdownStyles.colorWarning(String.valueOf(total))
|
||||
+ " 项变更**")).append("\n\n");
|
||||
for (List<ParameterChange> group : groups.values()) {
|
||||
ParameterChange first = group.get(0);
|
||||
if (first.getParentDto() != null && !first.getParentDto().isBlank()) {
|
||||
sb.append("**").append(MarkdownStyles.inlineCode(first.getParentDto())).append("**");
|
||||
} else if (first.getBodyParamName() != null && !first.getBodyParamName().isBlank()) {
|
||||
sb.append("**").append(MarkdownStyles.inlineCode(first.getBodyParamName())).append("**");
|
||||
}
|
||||
sb.append("\n\n");
|
||||
for (ParameterChange change : group) {
|
||||
sb.append(formatParameterLine(change)).append("\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String formatParameterLine(ParameterChange change) {
|
||||
String tag;
|
||||
switch (change.getChangeType()) {
|
||||
case ADDED:
|
||||
tag = MarkdownStyles.colorInfo("[新增]");
|
||||
break;
|
||||
case REMOVED:
|
||||
tag = MarkdownStyles.colorWarning("[删除]");
|
||||
break;
|
||||
case RENAMED:
|
||||
tag = MarkdownStyles.colorWarning("[重命名]");
|
||||
break;
|
||||
case MODIFIED:
|
||||
tag = MarkdownStyles.colorWarning("[类型变更]");
|
||||
break;
|
||||
default:
|
||||
tag = MarkdownStyles.colorWarning("[修改]");
|
||||
break;
|
||||
}
|
||||
String name = MarkdownStyles.inlineCode(MarkdownStyles.safe(change.displayName()));
|
||||
String desc = change.getDescription() == null || change.getDescription().isBlank()
|
||||
? MarkdownStyles.colorComment("(无说明)")
|
||||
: MarkdownStyles.colorComment(change.getDescription());
|
||||
StringBuilder line = new StringBuilder();
|
||||
if (change.getChangeType() == ParameterChange.ChangeType.RENAMED) {
|
||||
line.append(tag).append(" ")
|
||||
.append(MarkdownStyles.colorComment(MarkdownStyles.safe(change.getOldName()))).append(" → ")
|
||||
.append(MarkdownStyles.colorInfo(MarkdownStyles.safe(change.getParamName())))
|
||||
.append(" 说明: ").append(desc);
|
||||
} else {
|
||||
line.append(tag).append(" ").append(name).append(" 说明: ").append(desc);
|
||||
}
|
||||
appendParameterType(line, change);
|
||||
return MarkdownStyles.quoteLine(line.toString());
|
||||
}
|
||||
|
||||
private void appendParameterType(StringBuilder line, ParameterChange change) {
|
||||
String typePart = resolveTypePart(change);
|
||||
if (!typePart.isBlank()) {
|
||||
line.append(" 类型: ").append(typePart);
|
||||
}
|
||||
}
|
||||
|
||||
private String formatUriWithMethod(String httpMethod, String uri, boolean isNew) {
|
||||
String path = MarkdownStyles.inlineCode(MarkdownStyles.safe(uri));
|
||||
if (httpMethod == null || httpMethod.isBlank()) {
|
||||
return path;
|
||||
}
|
||||
String methodPart = isNew
|
||||
? MarkdownStyles.colorInfo(httpMethod.toUpperCase())
|
||||
: MarkdownStyles.colorWarning(httpMethod.toUpperCase());
|
||||
return methodPart + " " + path;
|
||||
}
|
||||
|
||||
private String formatEndpointDescription(EndpointChangeReport report) {
|
||||
String desc = report.getEndpointDescription();
|
||||
if (desc == null || desc.isBlank()) {
|
||||
return MarkdownStyles.colorComment("(无说明)");
|
||||
}
|
||||
return MarkdownStyles.colorComment(MarkdownStyles.safe(desc));
|
||||
}
|
||||
|
||||
private String resolveTypePart(ParameterChange change) {
|
||||
if (change.getChangeType() == ParameterChange.ChangeType.MODIFIED
|
||||
&& change.getDetail() != null && !change.getDetail().isBlank()) {
|
||||
return MarkdownStyles.formatTypeChange(change.getDetail());
|
||||
}
|
||||
if (change.getParamType() != null && !change.getParamType().isBlank()) {
|
||||
boolean isNew = change.getChangeType() == ParameterChange.ChangeType.ADDED
|
||||
|| change.getChangeType() == ParameterChange.ChangeType.RENAMED;
|
||||
return MarkdownStyles.formatSingleType(change.getParamType(), isNew);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user