diff --git a/README.md b/README.md
index 12ba941..d4b2175 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,31 @@
# code-diff
-**用于java代码的code-dif && 覆盖数据收集**
+**用于java代码的code-diff && 覆盖数据合并收集**
+* 支持git仓库获取代码code-diff
+* 支持多个实例服务合并收集
+* 支持同分支不同commit代码覆盖率合并收集
+* 支持页面配置管理实例服务:配置jacoco端口;配置includes/excludes表达式
+* 支持实时生成查看报告:报告生成支持使用includes && excldes表达式过滤
+* 支持提供api配合jenkins pipeline集成使用
+* 支持收集函数调用链
-## 部署流程
+## linux部署
+> 需要部署server && web 2个服务
+> FBI warning!!!
+> 这2个服务都需要和jenkins部署在同一台linux上
+### server部署
+- 先执行sql文件:[ code-diff/sql/coverage.sql](https://github.com/alwans/code-diff/blob/main/sql/coverage.sql)
+- 修改数据库配置:[diff-services/src/main/resources/application.properties](https://github.com/alwans/code-diff/blob/main/diff-services/src/main/resources/application.properties)
+- 构建jar:mvn clean install -Dmaven.test.skip=true
+- 启动jar服务:java -jar diff-services-1.0.0.jar
+### web部署
+- nginx部署web服务,web文件:[code-diff/dist.zip](https://github.com/alwans/code-diff/tree/main/dist)
+- 访问wen站点
-> *1.通过nginx部署 /dist/dist.zip 站点*
+## docker部署
+
+
+
+待更新...
+
+
+## 示图
+
+### 1. 集成到jenkins的pipeline脚本中
+
+
+### 2. 页面配置应用的jacoco信息
+
+
+### 3. 收集状态控制
+#### 3.1 支持多台应用同时合并收集
+#### 3.2 支持不同commitId 合并收集
+
+
+### 4. 实时查看报告
+#### 4.1 支持增量 | 全量报告
+#### 4.2 支持分支增量 | commitId增量
+
+
+
+
+
diff --git a/diff-common/pom.xml b/diff-common/pom.xml
index 6071ddd..9aa64e4 100644
--- a/diff-common/pom.xml
+++ b/diff-common/pom.xml
@@ -51,6 +51,10 @@
junit
test
+
+ com.alibaba.fastjson2
+ fastjson2
+
diff --git a/diff-common/src/main/java/com/test/diff/common/util/FastJsonUtil.java b/diff-common/src/main/java/com/test/diff/common/util/FastJsonUtil.java
new file mode 100644
index 0000000..180fd6d
--- /dev/null
+++ b/diff-common/src/main/java/com/test/diff/common/util/FastJsonUtil.java
@@ -0,0 +1,19 @@
+package com.test.diff.common.util;
+
+import com.alibaba.fastjson2.JSON;
+
+/**
+ * @author wl
+ * @date 2022/8/2
+ */
+public class FastJsonUtil {
+
+
+ public static String serialize (Object object) {
+ return JSON.toJSONString(object);
+ }
+
+ public static T deserialize (String str, Class type) {
+ return JSON.parseObject(str, type);
+ }
+}
diff --git a/diff-common/src/test/java/com/test/diff/common/JacksonTest.java b/diff-common/src/test/java/com/test/diff/common/JacksonTest.java
index e4e6cfd..3705e03 100644
--- a/diff-common/src/test/java/com/test/diff/common/JacksonTest.java
+++ b/diff-common/src/test/java/com/test/diff/common/JacksonTest.java
@@ -1,5 +1,9 @@
package com.test.diff.common;
+import com.alibaba.fastjson2.JSON;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.test.diff.common.util.JacksonUtil;
+import lombok.Data;
import org.junit.Test;
import java.io.DataOutputStream;
@@ -9,8 +13,43 @@
public class JacksonTest {
+ int deep = 50;
+ int count = 1;
+ Node tailNode = null;
@Test
- public void testOutputStreamSerialize() throws FileNotFoundException {
+ public void testOutputStreamSerialize() throws FileNotFoundException, JsonProcessingException {
+ Node head = new Node();
+ head.setUri("com/icai/common/redis/RedisUtils.setRedisProperties(Lcom/icai/common/redis/RedisProperties;)V--" +count);
+ count++;
+ getNode(head);
+// System.out.println(tailNode);
+// String str = JacksonUtil.serialize(tailNode);
+ String str = JSON.toJSONString(tailNode);
+ System.out.println(str.length());
+ }
+ private void getNode(Node preNode) {
+ Node node = new Node();
+ node.setPreNode(preNode);
+ node.setCalledNode(preNode);
+ node.setUri("com/beitai/common/redis/RedisUtils.setRedisProperties(Lcom/beitai/common/redis/RedisProperties;)V--" +count);
+ count++;
+ if(count<=deep){
+ deep--;
+ getNode(node);
+ }
+ else {
+ tailNode = node;
+ }
}
}
+
+@Data
+class Node {
+
+ private Node preNode;
+
+ private Node calledNode;
+
+ private String uri;
+}
diff --git a/diff-services/src/main/java/com/test/diff/services/controller/FileController.java b/diff-services/src/main/java/com/test/diff/services/controller/FileController.java
index cdd557e..4cd2a9d 100644
--- a/diff-services/src/main/java/com/test/diff/services/controller/FileController.java
+++ b/diff-services/src/main/java/com/test/diff/services/controller/FileController.java
@@ -5,8 +5,10 @@
import com.test.diff.services.entity.ProjectInfo;
import com.test.diff.services.enums.StatusCode;
import com.test.diff.services.internal.source.SourceFileHandleFactory;
+import com.test.diff.services.params.CloneParamDto;
import com.test.diff.services.params.FileParams;
import com.test.diff.services.service.ProjectInfoService;
+import com.test.diff.services.task.CloneProjectTask;
import com.test.diff.services.utils.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@@ -34,31 +36,48 @@ public class FileController {
@Resource
private FileUtil fileUtil;
+ @Resource
+ private CloneProjectTask cloneProjectTask;
+
@PostMapping(value = "/class/path", produces = "application/json;charset=UTF-8")
public BaseResult getFileClassPath(@RequestBody @Validated FileParams fileParams){
ProjectInfo projectInfo = projectInfoService.getById(fileParams.getId());
if(Objects.isNull(projectInfo)){
return BaseResult.error(StatusCode.PROJECT_INFO_NOT_EXISTS);
}
+ String repoPath;
if(StringUtils.isNotBlank(fileParams.getCommitId())){
- fileParams.setBranch(fileParams.getBranch()+"_"+fileParams.getCommitId());
- }
- String repoPath = fileUtil.getRepoPath(projectInfo, fileParams.getBranch());
- String path = fileUtil.addPath(repoPath,
- FileConst.JAVA_CLASS_FILE_PARENT_DIR_NAME,
- FileConst.JAVA_CLASS_FILE_DIR_NAME);
- if(fileParams.getClassName().contains("/")){
- String[] arr = fileParams.getClassName().split("/");
- path = fileUtil.addPaths(path, arr);
+ repoPath = fileUtil.getRepoCommitPath(projectInfo, fileParams.getBranch(), fileParams.getCommitId());
+ }else{
+ repoPath = fileUtil.getRepoPath(projectInfo, fileParams.getBranch());
}
- path = path + GitConst.CLASS_FILE_SUFFIX;
- if(fileUtil.isExist(path)){
+ String classSubPath = fileParams.getClassName() + GitConst.CLASS_FILE_SUFFIX;
+ String path = fileUtil.getClassFilePath(repoPath, classSubPath);
+ if(!Objects.isNull(path) && fileUtil.isExist(path)){
return BaseResult.success(path);
}
+ log.error("未找到{} class文件路径,工程id: {}, branch: {}, commitId: {}", fileParams.getId(), fileParams.getClassName(),
+ fileParams.getBranch(), fileParams.getCommitId());
return BaseResult.error(StatusCode.OTHER_ERROR, "class文件不存在");
}
- @GetMapping(value = "copy/project")
+ /**
+ * 克隆指定工程的指定分支或者指定commit id代码
+ * @param cloneParamDto 克隆参数
+ * @return
+ */
+ @GetMapping("/clone/")
+ public BaseResult cloneProject(@Validated CloneParamDto cloneParamDto){
+ ProjectInfo projectInfo = projectInfoService.getById(cloneParamDto.getId());
+ if (projectInfo == null){
+ return BaseResult.error(StatusCode.OTHER_ERROR, "id="+cloneParamDto.getId().toString()+"的工程不存在, 请检查参数");
+ }
+ cloneProjectTask.checkClone(projectInfo, cloneParamDto.getBranchName(), cloneParamDto.getCommitId());
+ cloneProjectTask.cloneProjectTask(projectInfo, cloneParamDto.getBranchName(), cloneParamDto.getCommitId());
+ return BaseResult.success(null);
+ }
+
+ @GetMapping( "copy/project")
public BaseResult copyProjectFile(@RequestParam("path") String path,
@RequestParam("branch") String branch,
@RequestParam("id") int projectId){
diff --git a/diff-services/src/main/java/com/test/diff/services/controller/WebSiteController.java b/diff-services/src/main/java/com/test/diff/services/controller/WebSiteController.java
index f288442..ec7c13a 100644
--- a/diff-services/src/main/java/com/test/diff/services/controller/WebSiteController.java
+++ b/diff-services/src/main/java/com/test/diff/services/controller/WebSiteController.java
@@ -123,6 +123,15 @@ public BaseResult generateReport(@Validated @RequestBody ReportParams params){
return coverageReportService.report(params);
}
+ @GetMapping( "/getReportUri")
+ public BaseResult getReportUrl(@RequestParam("id") int projectId){
+ if(projectId == 0){
+ return BaseResult.error(StatusCode.PARAMS_ERROR, "项目id不允许为空");
+ }
+ return coverageReportService.getReportURI(projectId);
+ }
+
+
/**
* 开始或继续收集
* @param apps 应用id列表
diff --git a/diff-services/src/main/java/com/test/diff/services/entity/CoverageApp.java b/diff-services/src/main/java/com/test/diff/services/entity/CoverageApp.java
index 5e479be..116d743 100644
--- a/diff-services/src/main/java/com/test/diff/services/entity/CoverageApp.java
+++ b/diff-services/src/main/java/com/test/diff/services/entity/CoverageApp.java
@@ -51,6 +51,18 @@ public class CoverageApp implements Serializable {
@TableField(value = "port")
private String port;
+ /**
+ * 匹配通配符
+ */
+ @TableField(value = "includes")
+ private String includes;
+
+ /**
+ * 排除通配符
+ */
+ @TableField(value = "excludes")
+ private String excludes;
+
/**
* 是否禁用
*/
@@ -96,6 +108,8 @@ public boolean equals(Object that) {
&& (this.getStatus() == null ? other.getStatus() == null : this.getStatus().equals(other.getStatus()))
&& (this.getHost() == null ? other.getHost() == null : this.getHost().equals(other.getHost()))
&& (this.getPort() == null ? other.getPort() == null : this.getPort().equals(other.getPort()))
+ && (this.getIncludes() == null ? other.getIncludes() == null : this.getIncludes().equals(other.getIncludes()))
+ && (this.getExcludes() == null ? other.getExcludes() == null : this.getExcludes().equals(other.getExcludes()))
&& (this.getIsDisable() == null ? other.getIsDisable() == null : this.getIsDisable().equals(other.getIsDisable()))
&& (this.getIsDelete() == null ? other.getIsDelete() == null : this.getIsDelete().equals(other.getIsDelete()))
&& (this.getAddTime() == null ? other.getAddTime() == null : this.getAddTime().equals(other.getAddTime()))
@@ -112,6 +126,8 @@ public int hashCode() {
result = prime * result + ((getStatus() == null) ? 0 : getStatus().hashCode());
result = prime * result + ((getHost() == null) ? 0 : getHost().hashCode());
result = prime * result + ((getPort() == null) ? 0 : getPort().hashCode());
+ result = prime * result + ((getIncludes() == null) ? 0 : getIncludes().hashCode());
+ result = prime * result + ((getExcludes() == null) ? 0 : getExcludes().hashCode());
result = prime * result + ((getIsDisable() == null) ? 0 : getIsDisable().hashCode());
result = prime * result + ((getIsDelete() == null) ? 0 : getIsDelete().hashCode());
result = prime * result + ((getAddTime() == null) ? 0 : getAddTime().hashCode());
@@ -131,6 +147,8 @@ public String toString() {
sb.append(", status=").append(status);
sb.append(", host=").append(host);
sb.append(", port=").append(port);
+ sb.append(", includes=").append(includes);
+ sb.append(", excludes=").append(excludes);
sb.append(", isDisable=").append(isDisable);
sb.append(", isDelete=").append(isDelete);
sb.append(", addTime=").append(addTime);
diff --git a/diff-services/src/main/java/com/test/diff/services/entity/CoverageReport.java b/diff-services/src/main/java/com/test/diff/services/entity/CoverageReport.java
index 739018f..0086fee 100644
--- a/diff-services/src/main/java/com/test/diff/services/entity/CoverageReport.java
+++ b/diff-services/src/main/java/com/test/diff/services/entity/CoverageReport.java
@@ -35,7 +35,6 @@ public class CoverageReport implements Serializable {
/**
* 报告类型:0:全量,1:增量
- * {@link com.test.diff.services.enums.ReportTypeEnum}
*/
@TableField(value = "report_type")
private Integer reportType;
@@ -64,6 +63,12 @@ public class CoverageReport implements Serializable {
@TableField(value = "new_branch")
private String newBranch;
+ /**
+ * 报告绝对路径
+ */
+ @TableField(value = "report_uri")
+ private String reportUri;
+
/**
* 是否删除
*/
@@ -101,9 +106,11 @@ public boolean equals(Object that) {
&& (this.getProjectId() == null ? other.getProjectId() == null : this.getProjectId().equals(other.getProjectId()))
&& (this.getUuid() == null ? other.getUuid() == null : this.getUuid().equals(other.getUuid()))
&& (this.getReportType() == null ? other.getReportType() == null : this.getReportType().equals(other.getReportType()))
+ && (this.getDiffType() == null ? other.getDiffType() == null : this.getDiffType().equals(other.getDiffType()))
&& (this.getIsUsed() == null ? other.getIsUsed() == null : this.getIsUsed().equals(other.getIsUsed()))
&& (this.getOldBranch() == null ? other.getOldBranch() == null : this.getOldBranch().equals(other.getOldBranch()))
&& (this.getNewBranch() == null ? other.getNewBranch() == null : this.getNewBranch().equals(other.getNewBranch()))
+ && (this.getReportUri() == null ? other.getReportUri() == null : this.getReportUri().equals(other.getReportUri()))
&& (this.getIsDelete() == null ? other.getIsDelete() == null : this.getIsDelete().equals(other.getIsDelete()))
&& (this.getAddTime() == null ? other.getAddTime() == null : this.getAddTime().equals(other.getAddTime()))
&& (this.getLastTime() == null ? other.getLastTime() == null : this.getLastTime().equals(other.getLastTime()));
@@ -117,9 +124,11 @@ public int hashCode() {
result = prime * result + ((getProjectId() == null) ? 0 : getProjectId().hashCode());
result = prime * result + ((getUuid() == null) ? 0 : getUuid().hashCode());
result = prime * result + ((getReportType() == null) ? 0 : getReportType().hashCode());
+ result = prime * result + ((getDiffType() == null) ? 0 : getDiffType().hashCode());
result = prime * result + ((getIsUsed() == null) ? 0 : getIsUsed().hashCode());
result = prime * result + ((getOldBranch() == null) ? 0 : getOldBranch().hashCode());
result = prime * result + ((getNewBranch() == null) ? 0 : getNewBranch().hashCode());
+ result = prime * result + ((getReportUri() == null) ? 0 : getReportUri().hashCode());
result = prime * result + ((getIsDelete() == null) ? 0 : getIsDelete().hashCode());
result = prime * result + ((getAddTime() == null) ? 0 : getAddTime().hashCode());
result = prime * result + ((getLastTime() == null) ? 0 : getLastTime().hashCode());
@@ -136,9 +145,11 @@ public String toString() {
sb.append(", projectId=").append(projectId);
sb.append(", uuid=").append(uuid);
sb.append(", reportType=").append(reportType);
+ sb.append(", diffType=").append(diffType);
sb.append(", isUsed=").append(isUsed);
sb.append(", oldBranch=").append(oldBranch);
sb.append(", newBranch=").append(newBranch);
+ sb.append(", reportUri=").append(reportUri);
sb.append(", isDelete=").append(isDelete);
sb.append(", addTime=").append(addTime);
sb.append(", lastTime=").append(lastTime);
diff --git a/diff-services/src/main/java/com/test/diff/services/enums/StatusCode.java b/diff-services/src/main/java/com/test/diff/services/enums/StatusCode.java
index c90865c..2bb6292 100644
--- a/diff-services/src/main/java/com/test/diff/services/enums/StatusCode.java
+++ b/diff-services/src/main/java/com/test/diff/services/enums/StatusCode.java
@@ -35,6 +35,8 @@ public enum StatusCode {
//数据库信息相关
PROJECT_INFO_NOT_EXISTS(30010, "项目信息不存在"),
REPO_INFO_NOT_EXITS(30020, "项目对应的仓库信息不存在"),
+ APP_INFO_NOT_EXISTS(30030, "应用信息不存在"),
+ REPORT_NOT_EXISTS(30040, "报告不存在"),
//操作文件相关
File_ERROR(40010, "文件操作异常"),
diff --git a/diff-services/src/main/java/com/test/diff/services/internal/DiffWorkFlow.java b/diff-services/src/main/java/com/test/diff/services/internal/DiffWorkFlow.java
index f7789bd..5dc1bc0 100644
--- a/diff-services/src/main/java/com/test/diff/services/internal/DiffWorkFlow.java
+++ b/diff-services/src/main/java/com/test/diff/services/internal/DiffWorkFlow.java
@@ -156,18 +156,27 @@ private List getDiffCodeClasses(Git newGit,AbstractTreeIterator baseT
private Git syncCode(BaseRepository baseRepository, ProjectInfo projectInfo,
- String branch,String commitId, boolean isBranchDiff) throws IOException {
- return updateCode(baseRepository, FileConst.DEFAULT_EMPTY_PATH,
+ String branch, String commitId, boolean isBranchDiff) throws IOException {
+ //这里直接生成路径
+ String branch_path = fileUtil.getRepoPath(projectInfo, branch);
+ if(!isBranchDiff){
+ branch_path = branch_path + "_" + commitId;
+ }
+ return updateCode(baseRepository, branch_path,
projectInfo.getProjectName(),projectInfo.getProjectUrl(), branch, commitId, isBranchDiff);
}
/**
+ * 暂时不用了,这里是直接从code-diff根目录开始建项目文件夹的
+ * 后期都改成了由group/env/project,这里就不适用了,没有传group和env,所以直接不用
+ * 改为上游方法中直接调用fileUtil类中方法直接生成path
* 检查项目路径是否正确
* @param path 项目路径
* @param projectName 项目名
* @param branch 分支名
* @return
*/
+ @Deprecated
private String checkProjectPath(String path, String projectName, String branch,
String commitId, boolean isBranchDiff){
if(!path.startsWith(FileConst.DIFF_ROOT_PATH)){
@@ -194,7 +203,7 @@ private String checkProjectPath(String path, String projectName, String branch,
private Git updateCode(BaseRepository repository, String path,
String projectName, String projectUrl,
String branch, String commitId, boolean isBranchDiff) throws IOException {
- path = checkProjectPath(path, projectName, branch, commitId, isBranchDiff);
+// path = checkProjectPath(path, projectName, branch, commitId, isBranchDiff);
String gitPath = fileUtil.addPath(path, GitConst.GIT_FILE_SUFFIX);
if(new File(path).exists()){
if(this.threadLocal.get().isUpdateCode() && isBranchDiff){
diff --git a/diff-services/src/main/java/com/test/diff/services/internal/JavaFileCodeComparator.java b/diff-services/src/main/java/com/test/diff/services/internal/JavaFileCodeComparator.java
index eeac639..53aa18e 100644
--- a/diff-services/src/main/java/com/test/diff/services/internal/JavaFileCodeComparator.java
+++ b/diff-services/src/main/java/com/test/diff/services/internal/JavaFileCodeComparator.java
@@ -148,16 +148,14 @@ public void visit(MethodDeclaration n, List list) {
StringBuilder params = new StringBuilder();
NodeList parameters = n.getParameters();
if(!CollectionUtils.isEmpty(parameters)){
- params.append("(");
for (int i = 0; i < parameters.size(); i++) {
String param = parameters.get(i).getType().toString();
params.append(param.replaceAll(" ", ""));
- //和asm一致,每个参数都使用分号结尾
- params.append(";");
+ //和asm一致,每个参数都使用分号结尾
+ params.append(";");
}
- params.append(")");
}else{
- params.append("()");
+ params.append("");
}
MethodInfo methodInfo = MethodInfo.builder()
.md5(md5)
diff --git a/diff-services/src/main/java/com/test/diff/services/internal/jacoco/JacocoHandle.java b/diff-services/src/main/java/com/test/diff/services/internal/jacoco/JacocoHandle.java
index 6346836..95cd34f 100644
--- a/diff-services/src/main/java/com/test/diff/services/internal/jacoco/JacocoHandle.java
+++ b/diff-services/src/main/java/com/test/diff/services/internal/jacoco/JacocoHandle.java
@@ -9,6 +9,7 @@
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -45,7 +46,7 @@ public static ExecFileLoader getLoader(String execFilePath){
* @return
*/
public static String getBranchName(ExecFileLoader loader){
- return loader.getExecutionDataStore().getBranchName();
+ return loader.getBranchName();
}
/**
@@ -54,7 +55,7 @@ public static String getBranchName(ExecFileLoader loader){
* @return
*/
public static String getCommitId(ExecFileLoader loader){
- return loader.getExecutionDataStore().getCommitId();
+ return loader.getCommitId();
}
/**
@@ -98,20 +99,24 @@ public static void merge(String newSaveFilePath, String... execFilesPath) throws
/**
* merge 合并多个exec数据文件,
* 2中情况可合并:一:同分支同commit id ;二:同分支,不同commit id
+ * @param projectId 项目id 不同commit id合并时,需要知道项目id来找出差异类,针对差异类做合并; 同commit可传0
+ * @param localPort 本服务对应的端口 --> @Value("${server.port}")
* @param newSaveFilePath 合并后保存的文件绝对路径
* @param execFiles exec文件数组
* @throws Exception
*/
- public static void merge(String newSaveFilePath, File... execFiles) throws Exception {
+ public static void merge(long projectId, String localPort, String newSaveFilePath, File... execFiles) throws Exception {
List params = new ArrayList<>();
params.add("merge");
+ params.add("--id");
+ params.add(projectId+"");
params.add("--destfile");
params.add(newSaveFilePath);
for(File file : execFiles){
params.add(file.getAbsolutePath());
}
params.add("--diffPort");
- params.add("1990");
+ params.add(localPort);
int result = JacocoApi.execute(params.toArray(new String[params.size()]));
if(result == -1){
throw new BizException("merge 失败");
@@ -131,7 +136,8 @@ public static void report(String execFilePath,
List classFilePaths,
List sourceFilePaths,
String reportPath,
- String diffResult) throws Exception {
+ String diffResult,
+ String filterRules) throws Exception {
List params = new ArrayList<>();
params.add("report");
params.add(execFilePath);
@@ -149,7 +155,12 @@ public static void report(String execFilePath,
params.add("--diffFiles");
params.add(diffResult);
}
- int result = JacocoApi.execute(params.toArray(new String[params.size()]));
+ if(StringUtils.isNotBlank(filterRules)){
+ params.add("--filterRules");
+ params.add(filterRules);
+ }
+ log.info("jacoco report 参数:"+params);
+ int result = JacocoApi.execute(params.toArray(new String[0]));
if(result == -1){
throw new BizException("报告生成失败");
}
diff --git a/diff-services/src/main/java/com/test/diff/services/openapi/controller/AppInfoController.java b/diff-services/src/main/java/com/test/diff/services/openapi/controller/AppInfoController.java
new file mode 100644
index 0000000..bc0b001
--- /dev/null
+++ b/diff-services/src/main/java/com/test/diff/services/openapi/controller/AppInfoController.java
@@ -0,0 +1,57 @@
+package com.test.diff.services.openapi.controller;
+
+import com.test.diff.services.entity.CoverageApp;
+import com.test.diff.services.entity.ProjectInfo;
+import com.test.diff.services.enums.StatusCode;
+import com.test.diff.services.service.CoverageAppService;
+import com.test.diff.services.service.ProjectInfoService;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.test.diff.services.base.controller.result.BaseResult;
+
+import javax.annotation.Resource;
+import java.util.Collections;
+import java.util.List;
+
+@RestController
+@RequestMapping("api/app")
+public class AppInfoController {
+
+
+ @Resource
+ private ProjectInfoService projectInfoService;
+
+ @Resource
+ private CoverageAppService coverageAppService;
+
+ @GetMapping(value = "/info")
+ public BaseResult getInfo(@RequestParam("groupName") String groupName,
+ @RequestParam("projectName") String projectName){
+ if(StringUtils.isEmpty(groupName)
+ || StringUtils.isEmpty(projectName) ){
+ return BaseResult.error(StatusCode.PARAMS_ERROR, "参数不允许为空");
+ }
+ List list = projectInfoService.getInfoByName(groupName);
+ if(CollectionUtils.isEmpty(list)){
+ return BaseResult.error(StatusCode.PROJECT_INFO_NOT_EXISTS);
+ }
+ for (ProjectInfo projectInfo : list) {
+ List apps = coverageAppService.getListByProjectId(projectInfo.getId());
+// if(CollectionUtils.isEmpty(apps)){
+// return BaseResult.error(StatusCode.APP_INFO_NOT_EXISTS);
+// }
+ for(CoverageApp app : apps){
+ if(app.getAppName().equalsIgnoreCase(projectName)){
+ return BaseResult.success(app);
+ }
+ }
+ }
+ return BaseResult.error(StatusCode.APP_INFO_NOT_EXISTS);
+ }
+
+}
diff --git a/diff-services/src/main/java/com/test/diff/services/params/CloneParamDto.java b/diff-services/src/main/java/com/test/diff/services/params/CloneParamDto.java
new file mode 100644
index 0000000..20fc598
--- /dev/null
+++ b/diff-services/src/main/java/com/test/diff/services/params/CloneParamDto.java
@@ -0,0 +1,39 @@
+package com.test.diff.services.params;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author wl
+ * @date 2022/10/1
+ * @Description 克隆项目请求参数
+ **/
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class CloneParamDto extends BaseParams {
+
+ @NotNull(message = "工程id不可为空")
+ private Integer id;
+
+ @NotEmpty(message = "分支名不可为空")
+ private String branchName;
+
+ private String commitId;
+
+// @ApiModelProperty(value = "编译命令")
+// private String compileInstruction;
+//
+// /**
+// * {@link BuildToolTypeEnum#getValue()}
+// */
+// @ApiModelProperty(value = "编译工具类型")
+// private Integer buildToolType;
+//
+// @ApiModelProperty("是否需要编译")
+// private Boolean isNeedCompile;
+}
diff --git a/diff-services/src/main/java/com/test/diff/services/params/CompileParamDto.java b/diff-services/src/main/java/com/test/diff/services/params/CompileParamDto.java
new file mode 100644
index 0000000..b0b51fe
--- /dev/null
+++ b/diff-services/src/main/java/com/test/diff/services/params/CompileParamDto.java
@@ -0,0 +1,35 @@
+package com.test.diff.services.params;
+;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author wl
+ * @date 2022/9/30
+ * @Description 编译参数
+ **/
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class CompileParamDto extends BaseParams {
+
+ @NotNull(message = "工程id不可为空")
+ private Integer id;
+
+ @NotEmpty(message = "分支名不可为空")
+ private String branchName;
+
+ private String commitId;
+
+ private String compileInstruction;
+
+
+ private Integer buildToolType;
+
+ private Boolean isRecompile;
+
+}
diff --git a/diff-services/src/main/java/com/test/diff/services/service/CoverageReportService.java b/diff-services/src/main/java/com/test/diff/services/service/CoverageReportService.java
index e1bfadf..b53f37c 100644
--- a/diff-services/src/main/java/com/test/diff/services/service/CoverageReportService.java
+++ b/diff-services/src/main/java/com/test/diff/services/service/CoverageReportService.java
@@ -6,6 +6,8 @@
import com.test.diff.services.params.ProjectDiffParams;
import com.test.diff.services.params.ReportParams;
+import java.util.List;
+
/**
*
* @author wl
@@ -26,10 +28,27 @@ public interface CoverageReportService extends IService {
*/
CoverageReport selectUsedByProjectId(long projectId);
+ /**
+ * 正序| 倒序 返回指定项目的所有未删除报告记录列表
+ * @param projectId 项目id
+ * @param isDesc 是否倒序
+ * @return
+ */
+ List selectListByProjectId(long projectId, boolean isDesc);
+
/**
* 生成全量/增量报告
* @param params
* @return
*/
BaseResult report(ReportParams params);
+
+ /**
+ * 获取指定项目的报告地址
+ * 如果该项目有收集中的记录,且该记录有生成过报告,那么就返回这条收集中的报告记录;如果收集中且未生成过报告,即返回为空
+ * 如果该项目没有收集中的记录,那么返回最近一条报告,状态成功:返回报告地址,状态失败:返回空
+ * @param projectId
+ * @return
+ */
+ BaseResult getReportURI(long projectId);
}
diff --git a/diff-services/src/main/java/com/test/diff/services/service/impl/CoverageReportServiceImpl.java b/diff-services/src/main/java/com/test/diff/services/service/impl/CoverageReportServiceImpl.java
index 70cf66d..15b2f9b 100644
--- a/diff-services/src/main/java/com/test/diff/services/service/impl/CoverageReportServiceImpl.java
+++ b/diff-services/src/main/java/com/test/diff/services/service/impl/CoverageReportServiceImpl.java
@@ -2,12 +2,14 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.test.diff.common.util.CollectionUtil;
import com.test.diff.common.util.JacksonUtil;
import com.test.diff.services.base.controller.result.BaseResult;
import com.test.diff.services.consts.FileConst;
import com.test.diff.services.consts.GitConst;
import com.test.diff.services.consts.JacocoConst;
import com.test.diff.services.convert.ModelConvert;
+import com.test.diff.services.entity.CoverageApp;
import com.test.diff.services.entity.CoverageReport;
import com.test.diff.services.entity.ProjectInfo;
import com.test.diff.services.enums.DiffTypeEnum;
@@ -18,31 +20,37 @@
import com.test.diff.services.internal.jacoco.JacocoHandle;
import com.test.diff.services.params.ProjectDiffParams;
import com.test.diff.services.params.ReportParams;
+import com.test.diff.services.service.CoverageAppService;
import com.test.diff.services.service.CoverageReportService;
import com.test.diff.services.mapper.CoverageReportMapper;
import com.test.diff.services.service.ProjectInfoService;
import com.test.diff.services.utils.CommonUtil;
import com.test.diff.services.utils.FileUtil;
+import com.test.diff.services.utils.WildcardMatcher;
import com.test.diff.services.vo.ProjectVo;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Result;
import org.jacoco.cli.internal.JacocoApi;
import org.jacoco.cli.internal.core.tools.ExecFileLoader;
import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.io.File;
-import java.util.Date;
-import java.util.List;
-import java.util.Objects;
+import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.Collectors;
@Service
@Slf4j
public class CoverageReportServiceImpl extends ServiceImpl
implements CoverageReportService{
+ @Value("${report.domain}")
+ private String reportDomain;
@Resource
private CoverageReportMapper coverageReportMapper;
@@ -50,6 +58,9 @@ public class CoverageReportServiceImpl extends ServiceImpl selectListByProjectId(long projectId, boolean isDesc) {
+ LambdaQueryWrapper query = new LambdaQueryWrapper<>();
+ query.eq(CoverageReport::getProjectId, projectId);
+ query.eq(CoverageReport::getIsDelete, false);
+ if(isDesc){
+ query.orderByDesc(CoverageReport::getId);
+ }
+ return coverageReportMapper.selectList(query);
+ }
+
/**
* 这个方法要重新写
* @param params
@@ -94,7 +116,7 @@ public BaseResult report(ReportParams params) {
projectInfoService.updateById(projectInfo);
CoverageReport report = selectUsedByProjectId(params.getProjectId());
- //没有使用中的记录,说明没有点开始收集,而是手机点击生成报告。所以先创建一条使用的report记录
+ //没有使用中的记录,说明没有点开始收集,而是直接点击生成报告。所以先创建一条使用的report记录
if(Objects.isNull(report)){
create(params.getProjectId());
}
@@ -148,7 +170,11 @@ public BaseResult report(ReportParams params) {
report.setNewBranch(branch);
report.setReportType(ReportTypeEnum.FULL.getCode());
}
- JacocoHandle.report(execFilePath, classFilePaths, sourcePaths, uuidDir, diffResult);
+ //获取匹配规则
+ List filters = getAppFilterRules(projectInfo.getId());
+ String filterRules = JacksonUtil.serialize(filters);
+
+ JacocoHandle.report(execFilePath, classFilePaths, sourcePaths, uuidDir, diffResult, filterRules);
log.info("报告生成完成!");
projectInfo.setReportStatus(ReportStatusEnum.REPORT_SUCCESS.getCode());
projectInfoService.updateById(projectInfo);
@@ -160,10 +186,76 @@ public BaseResult report(ReportParams params) {
return BaseResult.error(StatusCode.OTHER_ERROR, "报告生成失败");
}
report.setLastTime(new Date());
+ report.setReportUri(uuidDir);
coverageReportMapper.updateById(report);
log.info("{}项目报告生成成功", projectInfo.getProjectName());
return BaseResult.success("操作成功");
}
+
+ @Override
+ public BaseResult getReportURI(long projectId) {
+ ProjectInfo projectInfo = projectInfoService.getById(projectId);
+ if(Objects.isNull(projectInfo)){
+ return BaseResult.error(StatusCode.PARAMS_ERROR, "id= "+projectId+" 的项目不存在");
+ }
+ CoverageReport report = selectUsedByProjectId(projectId);
+ if(Objects.isNull(report)){
+ List historyReports = selectListByProjectId(projectId, true);
+ if(CollectionUtils.isEmpty(historyReports)){
+ return BaseResult.error(StatusCode.REPORT_NOT_EXISTS);
+ }
+ CoverageReport lastReport = historyReports.get(historyReports.size()-1);
+ if(StringUtils.isEmpty(lastReport.getReportUri())){
+ return BaseResult.error(StatusCode.REPORT_NOT_EXISTS, "最新报告记录未生成或生成失败");
+ }
+ return BaseResult.success(reportDomain + lastReport.getReportUri() + "/index.html");
+ }
+ if(StringUtils.isEmpty(report.getReportUri())){
+ return BaseResult.error(StatusCode.REPORT_NOT_EXISTS, "请先点击生成报告再查看");
+ }
+ //返回路径不考虑是windows路径
+ return BaseResult.success(reportDomain + report.getReportUri() + "/index.html");
+ }
+
+ /**
+ * 获取指定工程:收集中的应用匹配类表达式
+ * @param projectId
+ * @return 返回list格式:[app1-includes, app1-excludes, app2-includes, app2-excludes, ...]
+ */
+ private List getAppFilterRules(long projectId){
+ List apps = coverageAppService.getListByProjectId(projectId).stream()
+ .filter(app -> app.getStatus())
+ .collect(Collectors.toList());
+ List list = new ArrayList();
+ for(CoverageApp app: apps){
+ list.add(app.getIncludes());
+ list.add(app.getExcludes()==null? "" : app.getExcludes());
+ }
+ return list;
+ }
+
+
+ @Deprecated //(files是文件路径,匹配规则是针对全限定类名的,所以没法用) = 白写
+ private List filter(List files, ProjectInfo projectInfo){
+ //找出对应项目,收集中的所有应用
+ List apps = coverageAppService.getListByProjectId(projectInfo.getId()).stream()
+ .filter(app -> app.getStatus()).collect(Collectors.toList());
+ List list = new ArrayList();
+ //过滤无效文件
+ for(String file: files){
+ //匹配任一一个应用中的includes && excludes 表达式,即为有效文件
+ boolean flag = apps.stream().anyMatch(app -> {
+ WildcardMatcher includes = new WildcardMatcher(app.getIncludes());
+ WildcardMatcher excludes = new WildcardMatcher(app.getExcludes());
+ return includes.matches(file) &&
+ !excludes.matches(file);
+ });
+ if(flag){
+ list.add(file);
+ }
+ }
+ return list;
+ }
}
diff --git a/diff-services/src/main/java/com/test/diff/services/service/impl/ProjectInfoServiceImpl.java b/diff-services/src/main/java/com/test/diff/services/service/impl/ProjectInfoServiceImpl.java
index 2d9401d..21b315b 100644
--- a/diff-services/src/main/java/com/test/diff/services/service/impl/ProjectInfoServiceImpl.java
+++ b/diff-services/src/main/java/com/test/diff/services/service/impl/ProjectInfoServiceImpl.java
@@ -22,6 +22,7 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.jacoco.cli.internal.core.tools.ExecFileLoader;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
@@ -42,6 +43,9 @@
public class ProjectInfoServiceImpl extends ServiceImpl
implements ProjectInfoService {
+ @Value("${server.port}")
+ private String localPort;
+
@Resource
private FileUtil fileUtil;
@@ -68,6 +72,7 @@ public Long create(ProjectInfo projectInfo) {
public List getInfoByName(String projectName) {
LambdaQueryWrapper query = new LambdaQueryWrapper();
query.eq(ProjectInfo::getProjectName, projectName);
+ query.eq(ProjectInfo::getIsDelete, false);
return projectInfoMapper.selectList(query);
}
@@ -106,7 +111,7 @@ private void pullSingleExec(ProjectInfo projectInfo, CoverageApp coverageApp, C
//1.获取数据,先存放在uuid目录中
String execUuidPath = dumpData(coverageApp, projectInfo, report.getUuid(), execName);
//2.合并uuid目录中的exec文件
- mergeExec(execUuidPath);
+ mergeExec(execUuidPath, projectInfo.getId());
//3.把第一步dump下来的数据移至对应分支文件夹中 && 合并分支目录中的exec文件,并删除老数据
String oriExecPath = fileUtil.addPath(execUuidPath, execName);
String branchDir = getBranchPath(projectInfo,
@@ -118,7 +123,7 @@ private void pullSingleExec(ProjectInfo projectInfo, CoverageApp coverageApp, C
log.error("{}文件移动至{}目录失败, 停止合并操作分支目录中相关exec数据", oriExecPath, branchDir, e);
return;
}
- mergeExec(branchDir);
+ mergeExec(branchDir, projectInfo.getId());
deleteOldExec(branchDir);
log.info("{}应用探针数据拉取合并完成...", coverageApp.getAppName());
}
@@ -138,7 +143,7 @@ public boolean accept(File pathname) {
}
}
- private void mergeExec(String dirPath){
+ private void mergeExec(String dirPath, long projectId){
File dir = new File(dirPath);
if(!dir.exists()){
log.error("合并数据的{}目录不存在", dir.getAbsolutePath());
@@ -156,7 +161,7 @@ public boolean accept(File pathname) {
}
String newFilePath = fileUtil.addPath(dirPath, JacocoConst.EXEC_MERGE_FILE_NAME);
try {
- JacocoHandle.merge(newFilePath, execFiles);
+ JacocoHandle.merge(projectId, localPort, newFilePath, execFiles);
} catch (Exception e) {
e.printStackTrace();
log.error("合并{}目录中的exec文件失败", dirPath, e);
diff --git a/diff-services/src/main/java/com/test/diff/services/task/CloneProjectTask.java b/diff-services/src/main/java/com/test/diff/services/task/CloneProjectTask.java
new file mode 100644
index 0000000..d12fdb3
--- /dev/null
+++ b/diff-services/src/main/java/com/test/diff/services/task/CloneProjectTask.java
@@ -0,0 +1,213 @@
+package com.test.diff.services.task;
+
+
+import com.sun.prism.impl.BaseResourceFactory;
+import com.test.diff.services.entity.ProjectInfo;
+import com.test.diff.services.entity.RepoInfo;
+import com.test.diff.services.exceptions.BizException;
+import com.test.diff.services.internal.BaseRepository;
+import com.test.diff.services.internal.RepositoryFactory;
+import com.test.diff.services.params.CompileParamDto;
+import com.test.diff.services.service.ProjectInfoService;
+import com.test.diff.services.service.RepoInfoService;
+import com.test.diff.services.utils.CMDUtils;
+import com.test.diff.services.utils.FileUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jgit.api.Git;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StopWatch;
+
+import javax.annotation.Resource;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * @author wl
+ * @date 2022/9/30
+ */
+@Slf4j
+@Component
+public class CloneProjectTask {
+
+ /**
+ * clone失败的历史任务
+ */
+ public static final List failedTasks = new ArrayList<>();
+
+ /**
+ * 克隆中的项目
+ */
+ public static final Map taskMap = new ConcurrentHashMap<>();
+
+ /**
+ * 仓库实例
+ */
+ private static final Map repoInstances = new ConcurrentHashMap<>();
+
+ @Resource
+ private RepoInfoService repoInfoService;
+
+
+
+ /**
+ * 异步克隆工程代码
+ * @param projectInfo 覆盖工程信息
+ * @param branch 分支信息
+ */
+ @Async("compileExecutor")
+ public void cloneProjectTask(ProjectInfo projectInfo, String branch){
+ cloneProject(projectInfo, branch, null, true);
+ }
+
+ @Async("compileExecutor")
+ public void cloneProjectTask(ProjectInfo projectInfo, String branch, String commitId){
+ cloneProject(projectInfo, branch, commitId, true);
+ }
+
+ /**
+ * 检查是否可以克隆
+ * @param projectInfo
+ */
+ public void checkClone(ProjectInfo projectInfo,
+ String branch, String commitId){
+ String compileKey = projectInfo.getProjectName() + projectInfo.getEnv()
+ + branch + commitId;
+ if (failedTasks.contains(projectInfo.getProjectName())){
+ new BizException(projectInfo.getProjectName()+"工程克隆异常, 不再继续尝试");
+ }
+ synchronized (this){
+ if (taskMap.get(compileKey) != null){
+ throw new BizException(projectInfo.getProjectName()+"项目正在clone中..., 请稍后再试");
+ }
+ taskMap.put(compileKey, projectInfo.getProjectName());
+ if (repoInstances.get(projectInfo.getRepoId()) == null){
+ RepoInfo repoInfo = repoInfoService.getById(projectInfo.getRepoId());
+ if (repoInfo == null){
+ throw new BizException(projectInfo.getProjectName() + "项目的仓库信息不存在,克隆失败");
+ }
+ repoInstances.put(projectInfo.getRepoId(), repoInfo);
+ }
+ }
+ }
+
+ /**
+ * 克隆工程
+ * @param projectInfo
+ * @param branch
+ * @param commitId
+ * @param isNeedCompile 是否需要编译
+ */
+ public void cloneProject(ProjectInfo projectInfo, String branch, String commitId, Boolean isNeedCompile){
+ // 手动调用clone检查
+// checkClone(coverageProject, branch, commitId);
+ RepoInfo repoDto = repoInstances.get(projectInfo.getRepoId());
+ String new_branch = "";
+ if (StringUtils.isEmpty(commitId)){
+ new_branch = branch;
+ }else {
+ new_branch = fixBranch(branch, commitId);
+ }
+ StopWatch stopWatch = new StopWatch();
+ try {
+ String repoPath = FileUtil.getRepoPath(projectInfo, new_branch);
+ log.info("开始克隆"+projectInfo.getProjectName()+"工程,仓库路径: "+repoPath);
+ stopWatch.start();
+ BaseRepository repository = RepositoryFactory.create(repoDto);
+ Git git = repository.clone(projectInfo.getProjectUrl(), repoPath, branch);
+ git.getRepository().close();
+ git.close();
+ if (StringUtils.isNotEmpty(commitId)){
+ repository.pullByCommitId(repoPath, branch, commitId);
+ }
+ stopWatch.stop();
+ log.info("{}工程clone完成, 耗时: {}秒", projectInfo.getProjectName(), stopWatch.getTotalTimeSeconds());
+ } catch (Exception e) {
+ stopWatch.stop();
+ failedTasks.add(projectInfo.getProjectName());
+ log.error("克隆{}项目异常, 耗时: {}秒, 异常原因: {}", projectInfo.getProjectName(),
+ stopWatch.getTotalTimeSeconds(),
+ e.getMessage());
+ } finally {
+ String compileKey = projectInfo.getProjectName() + projectInfo.getEnv()
+ + branch + commitId;
+ taskMap.remove(compileKey);
+ }
+ if (isNeedCompile){
+ // 克隆完,顺便编译一下
+ CompileParamDto compileParamDto = new CompileParamDto();
+ compileParamDto.setId(projectInfo.getId().intValue());
+ compileParamDto.setBranchName(branch);
+ compileParamDto.setCommitId(commitId);
+ compileSource(projectInfo, compileParamDto);
+ }
+ }
+
+ public void compileSource(ProjectInfo projectInfo, CompileParamDto compileParamDto){
+ // 计时
+ StopWatch stopWatch = new StopWatch();
+ stopWatch.start();
+ String branchPath = compileParamDto.getBranchName();
+ if (StringUtils.isNotEmpty(compileParamDto.getCommitId())){
+ branchPath = fixBranch(compileParamDto.getBranchName(), compileParamDto.getCommitId());
+ }
+ String repoPath = FileUtil.getRepoPath(projectInfo, branchPath);
+ log.info("{}工程开始编译...., 分支: {}, commit id: {}", projectInfo.getProjectName(),
+ compileParamDto.getBranchName(),
+ compileParamDto.getCommitId());
+ // 判断代码是不是存在
+ if (!new File(repoPath).exists()){
+ log.info("{}项目的{}分支代码不存在,开始clone项目...", projectInfo.getProjectName(), repoPath);
+ checkClone(projectInfo, compileParamDto.getBranchName(), compileParamDto.getCommitId());
+ log.info("{}项目的{}克隆结束,开始编译项目...", projectInfo.getProjectName(), repoPath);
+ }
+ try {
+ // 开始编译
+ String execCommand = "cd "+repoPath+" && mvn clean package -Dmaven.test.skip=true";
+ CMDUtils.CmdResult result = CMDUtils.exec(execCommand);
+ if (result.getIsSuccess()) {
+ log.info("{}工程编译成功", projectInfo.getProjectName());
+ } else {
+ log.error("{}工程编译失败, 编译信息: {}", projectInfo.getProjectName(), result.getContext());
+ }
+ stopWatch.stop();
+ log.info("{}工程编译完成, 耗时:{}秒", projectInfo.getProjectName(), stopWatch.getTotalTimeSeconds());
+ }finally {
+ String compileKey = projectInfo.getProjectName() + projectInfo.getEnv()
+ + compileParamDto.getBranchName() + compileParamDto.getCommitId();
+// compileMap.remove(compileKey);
+ }
+
+ }
+
+ @Bean("compileExecutor")
+ public Executor compileExecutor(){
+ return Executors.newFixedThreadPool(2, new ThreadFactory() {
+ @Override
+ public Thread newThread(@NotNull Runnable r) {
+ Thread thread = new Thread(r);
+ thread.setName("compile async thread --" + thread.getId());
+ return thread;
+ }
+ });
+ }
+
+
+ public String fixBranch(String branch, String commitId){
+ if (branch.contains("/")){
+ branch = branch.replaceAll("/", "_" );
+ }
+ return branch + "_" + commitId;
+ }
+
+}
diff --git a/diff-services/src/main/java/com/test/diff/services/utils/AsmUtil.java b/diff-services/src/main/java/com/test/diff/services/utils/AsmUtil.java
new file mode 100644
index 0000000..0fc31b0
--- /dev/null
+++ b/diff-services/src/main/java/com/test/diff/services/utils/AsmUtil.java
@@ -0,0 +1,11 @@
+package com.test.diff.services.utils;
+
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class AsmUtil {
+
+// public String getC
+
+}
diff --git a/diff-services/src/main/java/com/test/diff/services/utils/CMDUtils.java b/diff-services/src/main/java/com/test/diff/services/utils/CMDUtils.java
new file mode 100644
index 0000000..b9c8c06
--- /dev/null
+++ b/diff-services/src/main/java/com/test/diff/services/utils/CMDUtils.java
@@ -0,0 +1,196 @@
+package com.test.diff.services.utils;
+
+import com.test.diff.services.exceptions.BizException;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * @author wl
+ * @date 2022/8/17
+ */
+@Slf4j
+public class CMDUtils {
+
+ public static CmdResult exec (String cmdCommand) {
+ cmdCommand = fixWinCmd(cmdCommand);
+ StringBuilder stringBuilder = new StringBuilder();
+ Process process = null;
+ try {
+ process = Runtime.getRuntime().exec(getOsCmd() + cmdCommand );
+ BufferedReader bufferedReader = new BufferedReader(
+ new InputStreamReader(process.getInputStream(), "GBK"));
+ String line = null;
+ while((line=bufferedReader.readLine()) != null)
+ {
+ stringBuilder.append(line+"\n");
+ }
+ return CmdResult.builder()
+ .isSuccess(process.exitValue() == 0 ? true : false )
+ .status(process.exitValue())
+ .context(stringBuilder.toString())
+ .build();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static String execShell(String scriptPath, String... params) {
+ String[] cmd = new String[]{scriptPath};
+ cmd = ArrayUtils.addAll(cmd, params);
+ //解决脚本没有执行权限
+ ProcessBuilder builder = new ProcessBuilder("/bin/chmod", "777", scriptPath);
+ Process process = null;
+ int runningStatus = 0;
+ try {
+ process = builder.start();
+ process.waitFor();
+ Process ps = Runtime.getRuntime().exec(cmd);
+ runningStatus = ps.waitFor();
+ BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
+ BufferedReader err = new BufferedReader(new InputStreamReader(ps.getErrorStream()));
+ StringBuffer sb = new StringBuffer();
+ String line;
+ while ((line = br.readLine()) != null) {
+ sb.append(line).append("\n");
+ }
+ while ((line = err.readLine()) != null) {
+ log.error("shell log error...." + line);
+ sb.append(line).append("\n");
+ }
+ if (runningStatus != 0){
+ throw new BizException("exec shell script failed, result: " + sb.toString());
+ }
+ //执行结果
+ return sb.toString();
+ } catch (IOException e) {
+ log.error("Failed to exec {}, sandbox load failed", scriptPath);
+ e.printStackTrace();
+ throw new RuntimeException("shell script exec failed, sandbox load failed");
+ } catch (InterruptedException e) {
+ log.error("Failed to exec {}, sandbox load failed", scriptPath);
+ e.printStackTrace();
+ throw new RuntimeException("shell script exec failed, sandbox load failed");
+ }
+ }
+
+ /**
+ * windows系统,如果指令是cd, 需要先D: ,然后再执行cd D:\home 才能正确进入到home目录下
+ * 所以这里特殊处理下
+ * @param cmdCommand
+ * @return
+ */
+ private static String fixWinCmd(String cmdCommand){
+ if (OsUtils.isWindows() && cmdCommand.contains("cd")){
+ String driveLetter = "";
+ // 1.先把多条指令拆分
+ String[] commands = cmdCommand.split("&&");
+ List commandList = new ArrayList<>();
+ for (int i = 0; i < commands.length; i++) {
+ // 2.找出cd操作的指令
+ if (commands[i].trim().startsWith("cd")){
+ driveLetter = getDriveLetter(commands[i]);
+ if (StringUtils.isNotEmpty(driveLetter)){
+ commandList.add( driveLetter + ":"); // D:
+ }
+
+ }
+ commandList.add(commands[i]);
+ }
+ return String.join(" && ", commandList.toArray(new String[0]));
+ }
+ return cmdCommand;
+ }
+
+ /**
+ * 获取windows系统下,cd命令中的盘符
+ * @param command 指令
+ * @return
+ */
+ private static String getDriveLetter(String command){
+ String driveLetter = "";
+ String[] arr = command.split(" ");
+ for (String s: arr){
+ if (s.trim().contains(":\\")){
+ driveLetter = s.split(":")[0];
+ }
+ }
+ return driveLetter.toUpperCase(Locale.ROOT).trim();
+ }
+
+ /**
+ * 获取根指令信息
+ * @return
+ */
+ private static String getOsCmd(){
+ if (OsUtils.isLinux()){
+ return "/bin/sh -c ";
+ }
+ else if(OsUtils.isWindows()){
+ return "cmd /c ";
+ }
+ throw new BizException("系统不支持");
+ }
+
+ /**
+ * 执行结果
+ */
+ @Data
+ @Builder
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class CmdResult{
+
+ /**
+ * 是否成功
+ */
+ private Boolean isSuccess;
+
+ /**
+ * 执行返回状态码
+ */
+ private Integer status;
+
+ /**
+ * 执行返回内容
+ */
+ private String context;
+
+ }
+
+ class inputStreamThread implements Runnable{
+ private InputStream ins = null;
+ private BufferedReader bfr = null;
+ public inputStreamThread(InputStream ins){
+ this.ins = ins;
+ this.bfr = new BufferedReader(new InputStreamReader(ins));
+ }
+ @Override
+ public void run() {
+ String line = null;
+ byte[] b = new byte[100];
+ int num = 0;
+ try {
+ while((num=ins.read(b))!=-1){
+ System.out.println(new String(b,"gb2312"));
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+}
diff --git a/diff-services/src/main/java/com/test/diff/services/utils/FileUtil.java b/diff-services/src/main/java/com/test/diff/services/utils/FileUtil.java
index 81a1005..c57c08c 100644
--- a/diff-services/src/main/java/com/test/diff/services/utils/FileUtil.java
+++ b/diff-services/src/main/java/com/test/diff/services/utils/FileUtil.java
@@ -44,7 +44,7 @@ public void createDir(String path) throws FileException {
* @param subPath
* @return
*/
- public String addPath(String... subPath){
+ public static String addPath(String... subPath){
StringBuilder sb = new StringBuilder();
for(String path: subPath){
if(StringUtils.isBlank(path)){
@@ -59,9 +59,9 @@ public String addPath(String... subPath){
return sb.toString().substring(0, sb.lastIndexOf(File.separator));
}
- public String addPaths(String root, String... sunPath){
+ public String addPaths(String root, String... subPath){
StringBuilder path = new StringBuilder(root);
- for(String p: sunPath){
+ for(String p: subPath){
p = p.replaceAll("/", "_");
path.append(File.separator)
.append(p);
@@ -79,19 +79,71 @@ public String addPaths(String root, String... sunPath){
* @param branch
* @return
*/
- public String getRepoPath(String group, String env, String projectName, String branch){
+ public static String getRepoPath(String group, String env, String projectName, String branch){
if(branch.contains("/")){
branch = branch.replaceAll("/", "_");
}
return addPath(FileConst.DIFF_ROOT_PATH, group, env, projectName, branch);
}
- public String getRepoPath(ProjectInfo projectInfo, String branch){
+ public static String getRepoPath(ProjectInfo projectInfo, String branch){
return getRepoPath(projectInfo.getProjectGroup(), projectInfo.getEnv(),
projectInfo.getProjectName(),
branch);
}
+ /**
+ * 返回指定commit id绝对路径
+ * @param projectInfo
+ * @param branch
+ * @param commit
+ * @return
+ */
+ public String getRepoCommitPath(ProjectInfo projectInfo, String branch, String commit){
+ String path = getRepoPath(projectInfo, branch);
+ path = path + "_" + commit;
+ return path;
+ }
+
+ /**
+ * 根据关键字获取单个指定class文件绝对路径
+ * @param rootPath 搜索根目录
+ * @param key 关键字符串
+ * @return
+ */
+ public String getClassFilePath(String rootPath, String key){
+ //简单做下windows平台处理
+ if(!key.contains(File.separator)){
+ key = key.replace("/", File.separator);
+ }
+ String path = null;
+ List files = getAllClassFilePathsByProject(rootPath);
+ for(String file : files){
+ path = findClassFileByKey(new File(file), key);
+ }
+ return path;
+ }
+
+ private String findClassFileByKey(File file, String key){
+ String path = null;
+ if(file.isDirectory()){
+ for(File f: file.listFiles()){
+ path = findClassFileByKey(f, key);
+ if(path != null){
+ return path;
+ }
+ }
+ }else{
+ if(file.getAbsolutePath().contains(key)){
+ return file.getAbsolutePath();
+ }
+ }
+ if(path!= null){
+ return path;
+ }
+ return null;
+ }
+
public boolean isExist(String path){
return new File(path).exists() ? true : false;
}
@@ -109,9 +161,17 @@ public List getAllSourcePathsByProject(String branchDirPath){
}
public List getAllClassFilePathsByProject(String branchDirPath){
+ /**
+ * gradle编译的路径是build/classes/
+ * maven编译的路径是target/classes/
+ * 之前没考虑gradle这种,写死了target/classes
+ * 现在改为只检查是否包含classes
+ */
+// return getListDirByKey(branchDirPath,
+// addPath(FileConst.JAVA_CLASS_FILE_PARENT_DIR_NAME,
+// FileConst.JAVA_CLASS_FILE_DIR_NAME));
return getListDirByKey(branchDirPath,
- addPath(FileConst.JAVA_CLASS_FILE_PARENT_DIR_NAME,
- FileConst.JAVA_CLASS_FILE_DIR_NAME));
+ FileConst.JAVA_CLASS_FILE_DIR_NAME);
}
public List getListDirByKey(String dirPath, String key){
diff --git a/diff-services/src/main/java/com/test/diff/services/utils/OsUtils.java b/diff-services/src/main/java/com/test/diff/services/utils/OsUtils.java
new file mode 100644
index 0000000..1f23621
--- /dev/null
+++ b/diff-services/src/main/java/com/test/diff/services/utils/OsUtils.java
@@ -0,0 +1,20 @@
+package com.test.diff.services.utils;
+
+/**
+ * @author wl
+ * @date 2022/9/29
+ */
+public class OsUtils {
+
+ public static final String OS_NAME = System.getProperty("os.name").toLowerCase();
+ public static final String WINDOWS_PREFIX = "window";
+ public static final String LINUX_PREFIX = "linux";
+
+ public static Boolean isWindows() {
+ return OS_NAME.contains(WINDOWS_PREFIX);
+ }
+
+ public static Boolean isLinux() {
+ return OS_NAME.contains(LINUX_PREFIX);
+ }
+}
diff --git a/diff-services/src/main/java/com/test/diff/services/utils/WildcardMatcher.java b/diff-services/src/main/java/com/test/diff/services/utils/WildcardMatcher.java
new file mode 100644
index 0000000..e94a911
--- /dev/null
+++ b/diff-services/src/main/java/com/test/diff/services/utils/WildcardMatcher.java
@@ -0,0 +1,57 @@
+package com.test.diff.services.utils;
+
+import java.util.regex.Pattern;
+
+public class WildcardMatcher {
+
+ private final Pattern pattern;
+
+ /**
+ * Creates a new matcher with the given expression.
+ *
+ * @param expression
+ * wildcard expressions
+ */
+ public WildcardMatcher(final String expression) {
+ final String[] parts = expression.split("\\:");
+ final StringBuilder regex = new StringBuilder(expression.length() * 2);
+ boolean next = false;
+ for (final String part : parts) {
+ if (next) {
+ regex.append('|');
+ }
+ regex.append('(').append(toRegex(part)).append(')');
+ next = true;
+ }
+ pattern = Pattern.compile(regex.toString());
+ }
+
+ private static CharSequence toRegex(final String expression) {
+ final StringBuilder regex = new StringBuilder(expression.length() * 2);
+ for (final char c : expression.toCharArray()) {
+ switch (c) {
+ case '?':
+ regex.append(".");
+ break;
+ case '*':
+ regex.append(".*");
+ break;
+ default:
+ regex.append(Pattern.quote(String.valueOf(c)));
+ break;
+ }
+ }
+ return regex;
+ }
+
+ /**
+ * Matches the given string against the expressions of this matcher.
+ *
+ * @param s
+ * string to test
+ * @return true, if the expression matches
+ */
+ public boolean matches(final String s) {
+ return pattern.matcher(s).matches();
+ }
+}
diff --git a/diff-services/src/main/resources/application.properties b/diff-services/src/main/resources/application.properties
index 58fbbe8..45f5a0d 100644
--- a/diff-services/src/main/resources/application.properties
+++ b/diff-services/src/main/resources/application.properties
@@ -1,7 +1,8 @@
server.port=1990
-spring.datasource.url=
-spring.datasource.username=
-spring.datasource.password=
+spring.datasource.url=jdbc:mysql://127.0.0.1.158:3306/test_platform?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false
+spring.datasource.username=root
+spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
+#logging.level.com.test.diff.services=trace
diff --git a/diff-services/src/main/resources/application.yml b/diff-services/src/main/resources/application.yml
new file mode 100644
index 0000000..b5425a8
--- /dev/null
+++ b/diff-services/src/main/resources/application.yml
@@ -0,0 +1,2 @@
+report:
+ domain: "http://192.168.100.25:1991"
\ No newline at end of file
diff --git a/diff-services/src/main/resources/mapper/CoverageAppMapper.xml b/diff-services/src/main/resources/mapper/CoverageAppMapper.xml
index e1b8da2..c865fce 100644
--- a/diff-services/src/main/resources/mapper/CoverageAppMapper.xml
+++ b/diff-services/src/main/resources/mapper/CoverageAppMapper.xml
@@ -11,6 +11,8 @@
+
+
@@ -20,7 +22,7 @@
id,project_id,app_name,
status,host,port,
- is_disable,is_delete,add_time,
- last_time
+ includes,excludes,is_disable,
+ is_delete,add_time,last_time
diff --git a/diff-services/src/main/resources/mapper/CoverageReportMapper.xml b/diff-services/src/main/resources/mapper/CoverageReportMapper.xml
index d474161..c617554 100644
--- a/diff-services/src/main/resources/mapper/CoverageReportMapper.xml
+++ b/diff-services/src/main/resources/mapper/CoverageReportMapper.xml
@@ -8,11 +8,12 @@
-
+
+
@@ -20,8 +21,8 @@
id,project_id,uuid,
- report_type,diff_type,is_used,old_branch,
- new_branch,is_delete,add_time,
- last_time
+ report_type,diff_type,is_used,
+ old_branch,new_branch,report_uri,
+ is_delete,add_time,last_time
diff --git a/diff-services/src/test/java/com/test/diff/services/CollectionTest.java b/diff-services/src/test/java/com/test/diff/services/CollectionTest.java
index 0c6e4f7..3740097 100644
--- a/diff-services/src/test/java/com/test/diff/services/CollectionTest.java
+++ b/diff-services/src/test/java/com/test/diff/services/CollectionTest.java
@@ -1,23 +1,12 @@
package com.test.diff.services;
-import org.jacoco.cli.internal.core.data.ChainNode;
import org.junit.Test;
import java.util.*;
+import java.util.stream.Collectors;
public class CollectionTest {
- @Test
- public void testSetClear(){
- Set sets = new HashSet<>();
- ChainNode node = new ChainNode();
- node.setUri("test");
- sets.add(node);
- System.out.println(sets.size());
- sets.clear();
- System.out.println(sets.size());
- }
-
@Test
public void testSetArrayClear(){
Set[] sets = new Set[10];
@@ -40,11 +29,45 @@ public void testStream(){
.forEach(item -> System.out.println(item));
}
+ @Test
+ public void testFilter(){
+ List list = new ArrayList<>();
+ list.add(false);
+ list.add(true);
+ List new_list = list.stream().filter(item -> item).collect(Collectors.toList());
+ System.out.println(list);
+ System.out.println(new_list);
+ }
+
+ @Test
+ public void testAnyMatch(){
+ List list = new ArrayList<>();
+ list.add(1);
+ list.add(2);
+// boolean flag = list.stream().anyMatch(item -> item==1);
+ boolean flag = list.stream().anyMatch(item -> { return item==1;} ); //2中写法
+ System.out.println(list);
+ System.out.println(flag);
+ }
+
@Test
public void testArraySplit(){
-// String str = "String;String;Integer;";
- String str = "Ljava/lang/String;Lcom/beitai/iot/data/enums/SourceType;";
+ String str = "String;String;Integer;";
String[] arr = str.split(";");
System.out.println(arr);
}
+
+ @Test
+ public void testRepeatFilter(){
+ HashSet set1 = new HashSet<>();
+ HashSet set2 = new HashSet<>();
+ set1.add("a");
+ set1.add("b");
+ set1.add("c");
+ //------------
+ set2.add("a");
+ set2.add("d");
+ set1.addAll(set2);
+ System.out.println(set1);
+ }
}
diff --git a/diff-services/src/test/java/com/test/diff/services/ConfigTest.java b/diff-services/src/test/java/com/test/diff/services/ConfigTest.java
new file mode 100644
index 0000000..3b41840
--- /dev/null
+++ b/diff-services/src/test/java/com/test/diff/services/ConfigTest.java
@@ -0,0 +1,29 @@
+package com.test.diff.services;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@SpringBootTest
+@RunWith(SpringRunner.class)
+public class ConfigTest {
+
+ @Value("${report.domain}")
+ private String reportDomain;
+
+ @Value("${server.port}")
+ private String port;
+
+ @Test
+ public void testReportDomain(){
+ System.out.println(reportDomain);
+ }
+
+ @Test
+ public void testServerPort(){
+ System.out.println(port);
+ }
+}
diff --git a/diff-services/src/test/java/com/test/diff/services/CoverageReportTest.java b/diff-services/src/test/java/com/test/diff/services/CoverageReportTest.java
index 57f33d5..430ebe5 100644
--- a/diff-services/src/test/java/com/test/diff/services/CoverageReportTest.java
+++ b/diff-services/src/test/java/com/test/diff/services/CoverageReportTest.java
@@ -2,6 +2,7 @@
import com.test.diff.services.entity.CoverageReport;
import com.test.diff.services.service.CoverageReportService;
+import com.test.diff.services.service.impl.CoverageReportServiceImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
@@ -17,7 +18,7 @@
public class CoverageReportTest {
@Resource
- private CoverageReportService coverageReportService;
+ private CoverageReportServiceImpl coverageReportService;
@Test
public void testInsert(){
diff --git a/diff-services/src/test/java/com/test/diff/services/FileTest.java b/diff-services/src/test/java/com/test/diff/services/FileTest.java
index cb1be88..ecaa694 100644
--- a/diff-services/src/test/java/com/test/diff/services/FileTest.java
+++ b/diff-services/src/test/java/com/test/diff/services/FileTest.java
@@ -22,6 +22,8 @@
import java.util.concurrent.locks.ReentrantLock;
public class FileTest {
+
+ private static final String USER_HOME = System.getProperty("user.home");
private FileUtil fileUtil;
@@ -75,20 +77,20 @@ public void testFilePathTest(){
@Test
public void testRename(){
- String newPath = "C:\\Users\\wl\\code-diff\\dump.txt";
- String oldPath = "C:\\Users\\wl\\code-diff\\merge.txt";
+ String newPath = USER_HOME + "\\code-diff\\dump.txt";
+ String oldPath = USER_HOME + "\\code-diff\\merge.txt";
fileUtil.reName(newPath, oldPath);
}
@Test
public void testDelDir() throws IOException {
- FileUtils.deleteDirectory(new File("C:\\Users\\wl\\code-diff\\jvmTest\\master_35c27bd393e1f92efb757dfff8d2029bd3163849"));
+ FileUtils.deleteDirectory(new File(USER_HOME + "\\code-diff\\jvmTest\\master_35c27bd393e1f92efb757dfff8d2029bd3163849"));
}
@Test
public void testAsyncWrite() {
ReentrantLock lock = new ReentrantLock();
- File file = new File("C:\\Users\\wl\\code-diff\\12.txt");
+ File file = new File(USER_HOME + "\\code-diff\\12.txt");
Thread t1 = new Thread(){
@SneakyThrows
@Override
@@ -154,7 +156,7 @@ public void testSourcePaths(){
@Test
public void testClassPaths(){
- String branPath = "C:\\Users\\wl\\code-diff\\11\\yami-server";
+ String branPath = USER_HOME + "\\code-diff\\11\\yami-server";
List list = fileUtil.getAllClassFilePathsByProject(branPath);
System.out.println(list.size());
list.stream().forEach(path -> System.out.println(path));
@@ -162,8 +164,8 @@ public void testClassPaths(){
@Test
public void testCopyProject() throws IOException {
- String oriPath = "C:\\Users\\wl\\code-diff\\yami-server";
- String newPath = "C:\\Users\\wl\\code-diff\\122";
+ String oriPath = USER_HOME + "\\code-diff\\yami-server";
+ String newPath = USER_HOME + "\\code-diff\\122";
//拷贝.git目录
String oriGitPath = fileUtil.addPath(oriPath, ".git");
String newGitPath = fileUtil.addPath(newPath, ".git");
@@ -194,4 +196,16 @@ public void testCopyProject() throws IOException {
});
}
+ @Test
+ public void testFindSelectedClassFilePath(){
+ String key = "CoverageAppServiceImpl.class";
+ if(!key.contains(File.separator)){
+ key = key.replace("/", File.separator);
+ }
+ System.out.println(key);
+ String path = fileUtil.getClassFilePath(USER_HOME + "\\code-diff",
+ key);
+ System.out.println(path);
+ }
+
}
diff --git a/diff-services/src/test/java/com/test/diff/services/GitFileHandleTest.java b/diff-services/src/test/java/com/test/diff/services/GitFileHandleTest.java
index 9fe11f9..276f276 100644
--- a/diff-services/src/test/java/com/test/diff/services/GitFileHandleTest.java
+++ b/diff-services/src/test/java/com/test/diff/services/GitFileHandleTest.java
@@ -14,6 +14,8 @@
@RunWith(SpringRunner.class)
public class GitFileHandleTest {
+ private static final String USER_HOME = System.getProperty("user.home");
+
@Autowired
protected ApplicationContext ctx;
@@ -21,7 +23,7 @@ public class GitFileHandleTest {
public void testCopyProject(){
SpringUtil.setContext(ctx);
ISourceFileHandle handle = SourceFileHandleFactory.build();
- String commitId = handle.copyProjectFile(null, "master", "C:\\Users\\wl\\code-diff\\jvmTest", 1);
+ String commitId = handle.copyProjectFile(null, "master", USER_HOME + "\\code-diff\\jvmTest", 1);
System.out.println(commitId);
}
}
diff --git a/diff-services/src/test/java/com/test/diff/services/GitWorkFlowTest.java b/diff-services/src/test/java/com/test/diff/services/GitWorkFlowTest.java
index 90b1ac5..273dc76 100644
--- a/diff-services/src/test/java/com/test/diff/services/GitWorkFlowTest.java
+++ b/diff-services/src/test/java/com/test/diff/services/GitWorkFlowTest.java
@@ -107,7 +107,7 @@ public void testGetCommitList() throws IOException, GitAPIException {
ProjectInfo projectInfo = projectInfoService.getById(1);
String brandDir = fileUtil.getRepoPath(projectInfo, branch);
// String gitPath = fileUtil.addPath(brandDir, ".git");
- String gitPath = "C:\\Users\\wl\\code-diff\\11\\yami-server\\.git";
+ String gitPath = System.getProperty("user.home")+"\\code-diff\\11\\test-server\\.git";
Repository repo = new FileRepository(gitPath);
Git git = new Git(repo);
RevWalk walk = new RevWalk(repo);
diff --git a/diff-services/src/test/java/com/test/diff/services/JacksonTest.java b/diff-services/src/test/java/com/test/diff/services/JacksonTest.java
deleted file mode 100644
index aba0e12..0000000
--- a/diff-services/src/test/java/com/test/diff/services/JacksonTest.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.test.diff.services;
-
-import com.test.diff.common.util.JacksonUtil;
-import org.jacoco.cli.internal.core.data.ChainNode;
-import org.junit.Test;
-
-import java.io.*;
-import java.nio.charset.StandardCharsets;
-
-public class JacksonTest {
-
- @Test
- public void testStreamSerialize() throws IOException {
- ChainNode node = new ChainNode();
- node.setUri("12dfj");
- String str = JacksonUtil.serialize(node);
- byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
- String ss = new String(bytes, StandardCharsets.UTF_8);
- ChainNode n = JacksonUtil.deserialize(ss, ChainNode.class);
-// ChainNode n = JacksonUtil.deserialize(bytes, ChainNode.class);
-// ChainNode n = JacksonUtil.deserialize(str, ChainNode.class);
- System.out.println(n.toString());
- }
-}
diff --git a/diff-services/src/test/java/com/test/diff/services/JacocoHandleTest.java b/diff-services/src/test/java/com/test/diff/services/JacocoHandleTest.java
index a827f54..2d8ecab 100644
--- a/diff-services/src/test/java/com/test/diff/services/JacocoHandleTest.java
+++ b/diff-services/src/test/java/com/test/diff/services/JacocoHandleTest.java
@@ -8,12 +8,12 @@
import com.test.diff.services.params.ProjectDiffParams;
import com.test.diff.services.utils.FileUtil;
-import org.jacoco.cli.internal.core.data.ChainNode;
import org.jacoco.cli.internal.core.data.ExecutionData;
import org.jacoco.cli.internal.core.data.ExecutionDataStore;
import org.jacoco.cli.internal.core.tools.ExecFileLoader;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@@ -27,50 +27,47 @@
@RunWith(SpringRunner.class)
public class JacocoHandleTest {
+ private static final String USER_HOME = System.getProperty("user.home");
+
@Resource
private DiffWorkFlow diffWorkFlow;
+ @Value("${server.port}")
+ private String port;
+
@Test
public void testDump() throws Exception {
File execfile = new File(
- "C:\\Users\\wl\\Desktop\\dump2.exec");
+ USER_HOME+ "\\dump2.exec");
- JacocoHandle.dump("192.168.100.83", "6300", execfile.getAbsolutePath());
+ JacocoHandle.dump("127.0.0.1", "6300", execfile.getAbsolutePath());
}
@Test
public void testMerge() throws Exception {
- String newEexcFilePath = "C:\\Users\\wl\\Desktop\\merge.exec";
- File[] files = new File("C:\\Users\\wl\\Desktop").listFiles(new FileFilter() {
+ String newEexcFilePath = USER_HOME + "\\merge.exec";
+ File[] files = new File("").listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getAbsolutePath().endsWith(".exec");
}
});
- JacocoHandle.merge(newEexcFilePath, files);
- }
-
- @Test
- public void testChainNode() throws IOException, ClassNotFoundException {
- File file = new File("C:\\Users\\wl\\Desktop\\obj.txt");
- InputStream is = new FileInputStream(file);
- ObjectInputStream ois = new ObjectInputStream(is);
- ChainNode node =(ChainNode) ois.readObject();
- System.out.println(node);
+ JacocoHandle.merge(0, port, newEexcFilePath, files);
}
@Test
public void testLoadExecFile(){
- String execFilePath = "C:\\Users\\wl\\Desktop\\dump.exec";
+ String execFilePath = USER_HOME + "\\dump2.exec";
ExecFileLoader loader = JacocoHandle.getLoader(execFilePath);
ExecutionDataStore store = loader.getExecutionDataStore();
Collection data = store.getContents();
data.stream()
.forEach(exec -> {
- if(exec.getName().equals("com/beitai/inventory/managment/service/impl/ImmMerchandiseInventoryServiceImpl")
- || exec.getName().equals("com/beitai/inventory/managment/service/impl/ImmSingleProductRecordServiceImpl")){
- System.out.println(exec);
- }
+// if(exec.getName().equals(" com/scm/financial/service/api/receipt/entity/FundCollectionRegisterImport")
+// || exec.getName().equals("com/beitai/inventory/managment/service/impl/ImmSingleProductRecordServiceImpl")){
+// System.out.println(exec);
+// }
+ System.out.println(exec.getName());
});
}
@@ -90,12 +87,12 @@ public void testReport() throws Exception {
List classInfos = diffWorkFlow.diff(params);
- String execFilePath = "C:\\Users\\wl\\Desktop\\dump.exec";
- String projectDir = "C:\\Users\\wl\\Desktop\\feature_v1.1.1_17602254b3c491c2f4c3dcc693db6f41ec5af8e7";
- String reportPath = "C:\\Users\\wl\\Desktop\\report";
+ String execFilePath = USER_HOME + "\\dump.exec";
+ String projectDir = USER_HOME + "\\feature_v1.1.1_17602254b3c491c2f4c3dcc693db6f41ec5af8e7";
+ String reportPath = USER_HOME + "\\report";
FileUtil fileUtil = new FileUtil();
JacocoHandle.report(execFilePath, fileUtil.getAllClassFilePathsByProject(projectDir),
- fileUtil.getAllSourcePathsByProject(projectDir),reportPath, JacksonUtil.serialize(classInfos));
+ fileUtil.getAllSourcePathsByProject(projectDir),reportPath, JacksonUtil.serialize(classInfos), null);
}
}
diff --git a/diff-services/src/test/java/com/test/diff/services/StringTest.java b/diff-services/src/test/java/com/test/diff/services/StringTest.java
new file mode 100644
index 0000000..4ef7b1a
--- /dev/null
+++ b/diff-services/src/test/java/com/test/diff/services/StringTest.java
@@ -0,0 +1,45 @@
+package com.test.diff.services;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Queue;
+
+public class StringTest {
+
+ @Test
+ public void testReplace(){
+ String str = "/root/code-diff/test/test/test-server/feature_1.0_f7eb21efa925a7588ae424ea3033d3805936fb23/sc-test/sc-job/src/main/java";
+ str = str.replaceAll("/", ".");
+ System.out.println(str);
+
+ }
+
+ @Test
+ public void testIterator(){
+ List list = new ArrayList<>();
+ list.add("a");
+ list.add("b");
+ list.add("c");
+ list.add("d");
+ for(int i=0; i> local = new ThreadLocal<>();
+ System.out.println(local.get()==null);
+ local.set(new ArrayList<>());
+ System.out.println(local.get());
+ }
+
+ @Test
+ public void testLen(){
+ System.out.println("".length());
+ }
+}
diff --git a/dist/dist.zip b/dist/dist.zip
index b942499..5ea62a2 100644
Binary files a/dist/dist.zip and b/dist/dist.zip differ
diff --git a/lib/jacoco-cli.jar b/lib/jacoco-cli.jar
index 452fcfb..72cda10 100644
Binary files a/lib/jacoco-cli.jar and b/lib/jacoco-cli.jar differ
diff --git a/lib/jacocoagent.jar b/lib/jacocoagent.jar
index 8a74553..c4ee486 100644
Binary files a/lib/jacocoagent.jar and b/lib/jacocoagent.jar differ
diff --git a/pom.xml b/pom.xml
index e0c7ce1..428e535 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,9 +35,10 @@
2.0.2
3.18.0
5.6.3
- 2.12.4
+ 2.13.3
4.9.0
2.8.6
+ 2.0.10
@@ -128,7 +129,11 @@
gson
${gson.version}
-
+
+ com.alibaba.fastjson2
+ fastjson2
+ ${fastjson2.version}
+
diff --git a/sql/coverage.sql b/sql/coverage.sql
index 7f7342c..a61e952 100644
--- a/sql/coverage.sql
+++ b/sql/coverage.sql
@@ -1,113 +1,112 @@
/*
- Navicat Premium Data Transfer
+Navicat MySQL Data Transfer
- Source Server : 158
- Source Server Type : MySQL
- Source Server Version : 50730
- Source Host : 127.0.0.1:3306
- Source Schema : test_platform
+Source Server : 158
+Source Server Version : 50730
+Source Host : 192.168.100.158:3306
+Source Database : test_platform
- Target Server Type : MySQL
- Target Server Version : 50730
- File Encoding : 65001
+Target Server Type : MYSQL
+Target Server Version : 50730
+File Encoding : 65001
- Date: 24/09/2021 10:56:21
+Date: 2022-01-07 09:47:43
*/
-SET NAMES utf8mb4;
-SET FOREIGN_KEY_CHECKS = 0;
+SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for coverage_app
-- ----------------------------
DROP TABLE IF EXISTS `coverage_app`;
-CREATE TABLE `coverage_app` (
- `id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '自增id',
- `project_id` int(10) NOT NULL COMMENT '项目id',
- `app_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用名',
- `status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '收集状态:收集中:未收集',
- `host` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '服务器ip',
- `port` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'jacoco端口',
- `is_disable` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否禁用',
- `is_delete` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
- `add_time` datetime(0) NULL DEFAULT NULL COMMENT '添加时间',
- `last_time` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
- PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
+CREATE TABLE `coverage_app` (
+ `id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '自增id',
+ `project_id` int(10) NOT NULL COMMENT '项目id',
+ `app_name` varchar(255) DEFAULT NULL COMMENT '应用名',
+ `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '收集状态:收集中:未收集',
+ `host` varchar(20) NOT NULL COMMENT '服务器ip',
+ `port` varchar(10) NOT NULL COMMENT 'jacoco端口',
+ `includes` varchar(255) DEFAULT NULL COMMENT '匹配通配符',
+ `excludes` varchar(255) DEFAULT NULL COMMENT '排除通配符',
+ `is_disable` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否禁用',
+ `is_delete` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除',
+ `add_time` datetime DEFAULT NULL COMMENT '添加时间',
+ `last_time` datetime DEFAULT NULL COMMENT '修改时间',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for coverage_report
-- ----------------------------
DROP TABLE IF EXISTS `coverage_report`;
-CREATE TABLE `coverage_report` (
- `id` bigint(10) NOT NULL AUTO_INCREMENT,
- `project_id` int(5) NOT NULL COMMENT '项目id',
- `uuid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '自动生成的uuid',
- `report_type` tinyint(1) NULL DEFAULT NULL COMMENT '报告类型:0:全量,1:增量',
- `diff_type` int(11) NULL DEFAULT NULL COMMENT 'diff类型:0:分支diff 1:commit diff',
- `is_used` bit(1) NOT NULL DEFAULT b'1' COMMENT '是否正被启用:0:未被使用,1:被使用',
- `old_branch` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '基线分支',
- `new_branch` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '当前分支',
- `is_delete` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
- `add_time` datetime(0) NOT NULL COMMENT '创建时间',
- `last_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
- PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
+CREATE TABLE `coverage_report` (
+ `id` bigint(10) NOT NULL AUTO_INCREMENT,
+ `project_id` int(5) NOT NULL COMMENT '项目id',
+ `uuid` varchar(255) NOT NULL COMMENT '自动生成的uuid',
+ `report_type` tinyint(1) DEFAULT NULL COMMENT '报告类型:0:全量,1:增量',
+ `diff_type` int(11) DEFAULT NULL COMMENT 'diff类型:0:分支diff 1:commit diff',
+ `is_used` bit(1) NOT NULL DEFAULT b'1' COMMENT '是否正被启用:0:未被使用,1:被使用',
+ `old_branch` varchar(255) DEFAULT NULL COMMENT '基线分支',
+ `new_branch` varchar(255) DEFAULT NULL COMMENT '当前分支',
+ `report_uri` varchar(255) DEFAULT NULL COMMENT '报告绝对路径',
+ `is_delete` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+ `add_time` datetime NOT NULL COMMENT '创建时间',
+ `last_time` datetime DEFAULT NULL COMMENT '更新时间',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for diff_project_info
-- ----------------------------
DROP TABLE IF EXISTS `diff_project_info`;
-CREATE TABLE `diff_project_info` (
- `id` bigint(5) NOT NULL AUTO_INCREMENT COMMENT '自增id',
- `repo_id` int(5) NOT NULL COMMENT '仓库id',
- `env` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '环境名',
- `project_group` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '所属项目组名',
- `project_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '项目名',
- `project_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '项目仓库地址',
- `collect_status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '收集状态:0:未收集,1:收集中,2:暂停收集',
- `report_status` tinyint(1) NOT NULL COMMENT '报告状态:0:未生成,1:生成中,2:生成成功,3:生成失败',
- `is_disable` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否启用',
- `is_delete` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
- `add_time` datetime(0) NOT NULL COMMENT '添加时间',
- `last_time` datetime(0) NOT NULL COMMENT '最后修改时间',
- PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;
+CREATE TABLE `diff_project_info` (
+ `id` bigint(5) NOT NULL AUTO_INCREMENT COMMENT '自增id',
+ `repo_id` int(5) NOT NULL COMMENT '仓库id',
+ `env` varchar(255) NOT NULL COMMENT '环境名',
+ `project_group` varchar(255) NOT NULL COMMENT '所属项目组名',
+ `project_name` varchar(255) NOT NULL COMMENT '项目名',
+ `project_url` varchar(255) NOT NULL COMMENT '项目仓库地址',
+ `collect_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '收集状态:0:未收集,1:收集中,2:暂停收集',
+ `report_status` tinyint(1) NOT NULL COMMENT '报告状态:0:未生成,1:生成中,2:生成成功,3:生成失败',
+ `is_disable` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否启用',
+ `is_delete` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+ `add_time` datetime NOT NULL COMMENT '添加时间',
+ `last_time` datetime NOT NULL COMMENT '最后修改时间',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Table structure for diff_repo_info
-- ----------------------------
DROP TABLE IF EXISTS `diff_repo_info`;
-CREATE TABLE `diff_repo_info` (
- `id` bigint(5) NOT NULL AUTO_INCREMENT COMMENT '自增id',
- `depot_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '仓库名',
- `depot_type` int(2) NOT NULL COMMENT '仓库类型:0:SVN, 1:GIT',
- `depot_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '仓库地址:例127.0.0.1:888',
- `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '登录账号',
- `passwd` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '登录密码',
- `is_disable` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否启用',
- `is_delete` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
- `add_time` datetime(0) NOT NULL COMMENT '创建时间',
- `last_time` datetime(0) NOT NULL COMMENT '最后修改时间',
- PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
+CREATE TABLE `diff_repo_info` (
+ `id` bigint(5) NOT NULL AUTO_INCREMENT COMMENT '自增id',
+ `depot_name` varchar(100) NOT NULL COMMENT '仓库名',
+ `depot_type` int(2) NOT NULL COMMENT '仓库类型:0:SVN, 1:GIT',
+ `depot_url` varchar(255) NOT NULL COMMENT '仓库地址:例127.0.0.1:888',
+ `user_name` varchar(255) NOT NULL COMMENT '登录账号',
+ `passwd` varchar(255) NOT NULL COMMENT '登录密码',
+ `is_disable` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否启用',
+ `is_delete` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+ `add_time` datetime NOT NULL COMMENT '创建时间',
+ `last_time` datetime NOT NULL COMMENT '最后修改时间',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for diff_result_info
-- ----------------------------
DROP TABLE IF EXISTS `diff_result_info`;
-CREATE TABLE `diff_result_info` (
- `id` bigint(100) NOT NULL AUTO_INCREMENT COMMENT '自增id',
- `project_id` int(5) NOT NULL COMMENT '项目id',
- `diff_type` int(1) NOT NULL COMMENT 'diff类型:0:分支diff,1:commit diff',
- `commit_branch` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'commit对应的分支名',
- `old_branch` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '对比分支名',
- `new_branch` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '目标分支名',
- `old_commit_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '对比commitId',
- `new_commit_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '目标commitId',
- `diff_result` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'diff结果',
- `add_time` datetime(0) NOT NULL COMMENT '创建时间',
- PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-
-SET FOREIGN_KEY_CHECKS = 1;
+CREATE TABLE `diff_result_info` (
+ `id` bigint(100) NOT NULL AUTO_INCREMENT COMMENT '自增id',
+ `project_id` int(5) NOT NULL COMMENT '项目id',
+ `diff_type` int(1) NOT NULL COMMENT 'diff类型:0:分支diff,1:commit diff',
+ `commit_branch` varchar(100) DEFAULT NULL COMMENT 'commit对应的分支名',
+ `old_branch` varchar(100) DEFAULT NULL COMMENT '对比分支名',
+ `new_branch` varchar(100) DEFAULT NULL COMMENT '目标分支名',
+ `old_commit_id` varchar(255) DEFAULT NULL COMMENT '对比commitId',
+ `new_commit_id` varchar(255) DEFAULT NULL COMMENT '目标commitId',
+ `diff_result` longtext NOT NULL COMMENT 'diff结果',
+ `add_time` datetime NOT NULL COMMENT '创建时间',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;