This commit is contained in:
@@ -37,10 +37,12 @@ Push 触发 CI 后,按变更类的后缀(`Dto` / `Vo` / `Entity` / `Model`
|
||||
|
||||
| 类类型 | request | response | 类转换 |
|
||||
|--------|:-------:|:--------:|:------:|
|
||||
| Dto | ✅ | ❌ | ✅ |
|
||||
| Vo | ❌ | ✅ | ✅ |
|
||||
| Dto | ✅ | ✅ | ✅ |
|
||||
| Vo | ✅ | ✅ | ✅ |
|
||||
| Entity / Model | ❌ | ❌ | ✅ |
|
||||
|
||||
Dto/Vo 均固定展示 request、response 两栏;无匹配接口时显示「无」。类转换栏仅在 `dto_entity_conversion.enabled: true` 时展示,关闭时不出现该小节。实际影响由接口索引 + 嵌套关系传播,不假定 Dto 仅 request、Vo 仅 response。
|
||||
|
||||
## 模版文件
|
||||
|
||||
| 文件 | 场景 |
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# Dto 类变更通知模版
|
||||
|
||||
**识别规则**:类名以 `Dto` 结尾。
|
||||
**影响范围**:request + 类转换。
|
||||
**影响范围**:request + response + 类转换(无匹配时对应栏显示「无」)。
|
||||
**嵌套标识**:被其他 Dto/Vo 嵌套时在「变更对象」行追加 `(嵌套对象)`;若同时直接作接口入参/返回值根类型,再追加 `(顶层对象)`。纯顶层不标注。
|
||||
|
||||
---
|
||||
|
||||
@@ -39,6 +40,20 @@
|
||||
|
||||
---
|
||||
|
||||
## 示例(嵌套对象)
|
||||
|
||||
```
|
||||
> **变更对象: <font color="info">UserSelfDto</font>(<font color="comment">嵌套对象</font>)**
|
||||
```
|
||||
|
||||
若该类同时直接出现在某接口 `@RequestBody` 或返回值类型中:
|
||||
|
||||
```
|
||||
> **变更对象: <font color="info">SomeDto</font>(<font color="comment">说明</font>)(<font color="comment">嵌套对象</font>)(<font color="comment">顶层对象</font>)**
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 示例(类删除)
|
||||
|
||||
```
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# Vo 类变更通知模版
|
||||
|
||||
**识别规则**:类名以 `Vo` 或 `VO` 结尾。
|
||||
**影响范围**:response + 类转换。
|
||||
**影响范围**:request + response + 类转换(无匹配时对应栏显示「无」)。
|
||||
**嵌套标识**:规则同 Dto——仅嵌套时标注 `(嵌套对象)`,嵌套且直接作接口根类型时追加 `(顶层对象)`。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -81,6 +81,12 @@ public class DtoNestIndex {
|
||||
return names;
|
||||
}
|
||||
|
||||
/** 是否被其他 Dto/Vo 嵌套引用(存在至少一个祖先容器) */
|
||||
public boolean hasAncestors(String className) {
|
||||
Set<String> ancestors = ancestorsOf.get(className);
|
||||
return ancestors != null && !ancestors.isEmpty();
|
||||
}
|
||||
|
||||
/** 嵌套类型的 @RequestBody 根 Dto 祖先(仅 Dto 后缀) */
|
||||
public Set<String> findRequestBodyRoots(String className) {
|
||||
Set<String> roots = new LinkedHashSet<>();
|
||||
|
||||
@@ -35,6 +35,8 @@ public class ImpactAnalyzer {
|
||||
matchEndpoints(report, endpointIndex, matchNames);
|
||||
}
|
||||
|
||||
report.setObjectRoleLabels(NestedObjectRoleResolver.resolve(report, nestIndex, endpointIndex));
|
||||
|
||||
if (!config.isDtoEntityConversionEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.codechecker.analyzer;
|
||||
|
||||
import com.codechecker.model.ApiEndpoint;
|
||||
import com.codechecker.model.ClassChangeReport;
|
||||
import com.codechecker.model.ClassType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 判定 Dto/Vo 在类变更通知中的对象角色标签(方案 B:嵌套 + 可选顶层)。
|
||||
* <p>
|
||||
* 仅当存在嵌套祖先时标注;纯顶层不标注;既嵌套又直接作接口根类型时同时标注。
|
||||
*/
|
||||
public final class NestedObjectRoleResolver {
|
||||
|
||||
private NestedObjectRoleResolver() {
|
||||
}
|
||||
|
||||
public static List<String> resolve(ClassChangeReport report, DtoNestIndex nestIndex,
|
||||
Map<String, ApiEndpoint> endpointIndex) {
|
||||
if (report.getClassType() != ClassType.DTO && report.getClassType() != ClassType.VO) {
|
||||
return List.of();
|
||||
}
|
||||
if (nestIndex == null) {
|
||||
return List.of();
|
||||
}
|
||||
String className = report.getClassName();
|
||||
if (!nestIndex.hasAncestors(className)) {
|
||||
return List.of();
|
||||
}
|
||||
List<String> labels = new ArrayList<>();
|
||||
labels.add("嵌套对象");
|
||||
if (isDirectEndpointType(className, endpointIndex)) {
|
||||
labels.add("顶层对象");
|
||||
}
|
||||
return List.copyOf(labels);
|
||||
}
|
||||
|
||||
/** 是否直接出现在接口入参或返回值类型(非仅经祖先传播) */
|
||||
private static boolean isDirectEndpointType(String className, Map<String, ApiEndpoint> endpointIndex) {
|
||||
if (className == null || className.isBlank() || endpointIndex == null) {
|
||||
return false;
|
||||
}
|
||||
for (ApiEndpoint endpoint : endpointIndex.values()) {
|
||||
if (endpoint.getParamTypes().contains(className)
|
||||
|| endpoint.getReturnTypes().contains(className)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ public class ClassChangeReport {
|
||||
private final List<String> conversionEntities = new ArrayList<>();
|
||||
private final List<ApiEndpoint> frontendImpactEndpoints = new ArrayList<>();
|
||||
private final boolean conversionCheckEnabled;
|
||||
private List<String> objectRoleLabels = List.of();
|
||||
|
||||
public ClassChangeReport(String className, String oldClassName, ClassType classType,
|
||||
ClassChangeKind changeKind, String sourceFile,
|
||||
@@ -98,6 +99,15 @@ public class ClassChangeReport {
|
||||
return conversionCheckEnabled;
|
||||
}
|
||||
|
||||
/** 对象角色标签(如「嵌套对象」「顶层对象」),仅 Dto/Vo 且存在嵌套时非空 */
|
||||
public List<String> getObjectRoleLabels() {
|
||||
return objectRoleLabels;
|
||||
}
|
||||
|
||||
public void setObjectRoleLabels(List<String> labels) {
|
||||
this.objectRoleLabels = labels == null || labels.isEmpty() ? List.of() : List.copyOf(labels);
|
||||
}
|
||||
|
||||
/** 追加一条字段变更 */
|
||||
public void addFieldChange(FieldChange change) {
|
||||
fieldChanges.add(change);
|
||||
|
||||
@@ -82,14 +82,17 @@ public class WeComNotifier {
|
||||
return truncate(sb.toString());
|
||||
}
|
||||
|
||||
/** 变更对象行:类名(绿)+ 可选中文说明(灰,整行加粗) */
|
||||
/** 变更对象行:类名(绿)+ 可选中文说明 + 嵌套角色标签(灰,整行加粗) */
|
||||
private String formatChangeTarget(ClassChangeReport report) {
|
||||
String name = colorInfo(safe(report.getClassName()));
|
||||
StringBuilder line = new StringBuilder(colorInfo(safe(report.getClassName())));
|
||||
String description = report.getClassDescription();
|
||||
if (description == null || description.isBlank()) {
|
||||
return name;
|
||||
if (description != null && !description.isBlank()) {
|
||||
line.append("(").append(colorComment(description)).append(")");
|
||||
}
|
||||
return name + "(" + colorComment(description) + ")";
|
||||
for (String role : report.getObjectRoleLabels()) {
|
||||
line.append("(").append(colorComment(role)).append(")");
|
||||
}
|
||||
return line.toString();
|
||||
}
|
||||
|
||||
/** 头部元信息,每项一行引用(加粗) */
|
||||
@@ -139,14 +142,12 @@ public class WeComNotifier {
|
||||
appendImpactByType(sb, report);
|
||||
}
|
||||
|
||||
/** Dto/Vo/Entity/Model 各展示不同的 request/response/转换段落 */
|
||||
/** Dto/Vo 均展示 request + response(二者可能交叉);Entity/Model 仅类转换 */
|
||||
private void appendImpactByType(StringBuilder sb, ClassChangeReport report) {
|
||||
switch (report.getClassType()) {
|
||||
case DTO:
|
||||
appendSectionIfNeeded(sb, report, true, false, true);
|
||||
break;
|
||||
case VO:
|
||||
appendSectionIfNeeded(sb, report, false, true, true);
|
||||
appendSectionIfNeeded(sb, report, true, true, true);
|
||||
break;
|
||||
case ENTITY:
|
||||
case MODEL:
|
||||
@@ -170,7 +171,7 @@ public class WeComNotifier {
|
||||
appendEndpointList(sb, report.getFrontendImpactEndpoints());
|
||||
sb.append("\n");
|
||||
}
|
||||
if (showConversion) {
|
||||
if (showConversion && report.isConversionCheckEnabled()) {
|
||||
sb.append("### 类转换影响").append("\n");
|
||||
appendConversionList(sb, report);
|
||||
}
|
||||
@@ -178,10 +179,6 @@ public class WeComNotifier {
|
||||
|
||||
/** 渲染关联 Entity,每项一行 */
|
||||
private void appendConversionList(StringBuilder sb, ClassChangeReport report) {
|
||||
if (!report.isConversionCheckEnabled()) {
|
||||
sb.append(quoteLine(colorComment("未开启检测"))).append("\n");
|
||||
return;
|
||||
}
|
||||
if (report.getConversionEntities().isEmpty()) {
|
||||
sb.append(quoteLine(colorComment("无"))).append("\n");
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user