فهرست منبع

fix: sonar java store check quality

claws 4 سال پیش
والد
کامیت
aa179f498d
19فایلهای تغییر یافته به همراه357 افزوده شده و 99 حذف شده
  1. 2 1
      api/src/main/java/cn/seecoder/api/k8s/impl/JobApiImpl.java
  2. 8 5
      web/src/main/java/cn/seecoder/web/controller/gitlab/CommitController.java
  3. 30 25
      web/src/main/java/cn/seecoder/web/core/pipeline/handler/K8sJobHandler.java
  4. 2 2
      web/src/main/java/cn/seecoder/web/dao/commit/CommitMapper.java
  5. 36 0
      web/src/main/java/cn/seecoder/web/dao/commit/CommitQualityMapper.java
  6. 25 0
      web/src/main/java/cn/seecoder/web/model/enums/CommitCheckResultEnum.java
  7. 1 1
      web/src/main/java/cn/seecoder/web/model/po/commit/CommitPO.java
  8. 26 0
      web/src/main/java/cn/seecoder/web/model/po/commit/CommitQualityPO.java
  9. 5 2
      web/src/main/java/cn/seecoder/web/model/vo/commit/CommitVO.java
  10. 8 6
      web/src/main/java/cn/seecoder/web/model/vo/hook/SonarResultHookVO.java
  11. 2 2
      web/src/main/java/cn/seecoder/web/model/vo/tree/TreeNodeVO.java
  12. 1 2
      web/src/main/java/cn/seecoder/web/service/impl/bug_list/BugListServiceImpl.java
  13. 55 44
      web/src/main/java/cn/seecoder/web/service/impl/pipeline/DeploymentServiceImpl.java
  14. 58 4
      web/src/main/java/cn/seecoder/web/service/impl/project/CommitServiceImpl.java
  15. 2 2
      web/src/main/java/cn/seecoder/web/service/impl/tree/TreeNodeServiceImpl.java
  16. 5 2
      web/src/main/java/cn/seecoder/web/service/project/CommitService.java
  17. 17 0
      web/src/main/resources/sql/table_init.sql
  18. 72 0
      web/src/test/java/cn/seecoder/web/dao/commit/CommitQualityMapperTest.java
  19. 2 1
      web/src/test/java/cn/seecoder/web/dao/project/CommitMapperTest.java

+ 2 - 1
api/src/main/java/cn/seecoder/api/k8s/impl/JobApiImpl.java

@@ -60,7 +60,8 @@ public class JobApiImpl implements JobApi {
 
     @Override
     public Job update(Job job) {
-        throw K8s_NOT_SUPPORT_METHOD;
+        delete(job);
+        return create(job);
     }
 
     @Override

+ 8 - 5
web/src/main/java/cn/seecoder/web/controller/gitlab/CommitController.java

@@ -7,11 +7,11 @@ import cn.seecoder.web.core.commit.CommitResolver;
 import cn.seecoder.web.core.commit.model.CommitRule;
 import cn.seecoder.web.dao.user.UserMapper;
 import cn.seecoder.web.model.enums.CommitRelatedEnum;
-import cn.seecoder.web.model.po.project.CommitPO;
+import cn.seecoder.web.model.po.commit.CommitPO;
 import cn.seecoder.web.model.vo.GitWebHookVO;
 import cn.seecoder.web.model.vo.Response;
 import cn.seecoder.web.model.vo.hook.SonarResultHookVO;
-import cn.seecoder.web.model.vo.project.CommitVO;
+import cn.seecoder.web.model.vo.commit.CommitVO;
 import cn.seecoder.web.service.bug_list.BugListService;
 import cn.seecoder.web.service.project.CommitService;
 import cn.seecoder.web.service.tree.TreeNodeService;
@@ -64,9 +64,12 @@ public class CommitController {
     @ApiOperation(value = "sonarqube回调接口", httpMethod = "POST")
     @PostMapping("/sonar_hook")
     @ApiImplicitParam(name = "hahaVO", dataType = "object", paramType = "body")
-    public Response<String> sonarHook(@RequestBody SonarResultHookVO sonarResultHookVO) throws ServiceException{
-        log.info(sonarResultHookVO.toString());
-        return Response.buildSuccess("yes");
+    public Response<Object> sonarHook(@RequestBody SonarResultHookVO sonarResultHookVO) throws ServiceException{
+        if (commitService.processSonarResult(sonarResultHookVO)) {
+            return Response.buildSuccess("ok");
+        } else {
+            return Response.buildFailure(500, "Post Body Process Error!");
+        }
     }
 
 

+ 30 - 25
web/src/main/java/cn/seecoder/web/core/pipeline/handler/K8sJobHandler.java

@@ -93,7 +93,7 @@ public class K8sJobHandler extends AbstractHandler{
         // deployName 是流水线的 name
         String deployName = context.getDeployName();
         // K8sConstants.JOB_SUFFIX = -job, 例如流水线叫做haha, jobname = haha-job
-        String jobName = String.format("%s-%s%s", deployName, imageTag, K8sConstants.JOB_SUFFIX);
+        String jobName = String.format("%s%s", deployName, K8sConstants.JOB_SUFFIX);
 
         context.appendSuccessResult("变量准备完成,开始配置容器");
         // 1 配置容器
@@ -142,7 +142,9 @@ public class K8sJobHandler extends AbstractHandler{
                 log.info(String.format("Job创建成功: [namespace: %s, deployName: %s]", namespace, deployName));
                 context.appendSuccessResult(String.format("Job创建成功: [namespace: %s, deployName: %s]", namespace, deployName));
             } else {
-                log.info("job已存在!放弃创建");
+                log.info("job已存在!执行删除重建操作");
+                jobApi.update(job);
+                log.info(String.format("Job重建成功: [namespace: %s, deployName: %s]", namespace, deployName));
                 context.appendErrorResult("Job已存在,放弃创建", new Exception());
             }
         } catch (K8sApiException e) {
@@ -151,28 +153,31 @@ public class K8sJobHandler extends AbstractHandler{
         }
 
         // 4 确认Job情况
-        try {
-            Thread.sleep(3000L);
-            List<Job> jobs = jobApi.getByCondition(K8sObjectRequest.builder()
-                    .name(jobName)
-                    .namespace(namespace)
-                    .build());
-            if (jobs.size() == 1){
-                Job k8s_job = jobs.get(0);
-                V1JobStatus status = k8s_job.getStatus();
-                if (status != null && status.getFailed() != null && status.getFailed() > 0) {
-                    throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.JOB_IMAGE_NOT_EXIST_ERROR);
-                }
-            }
-        } catch (InterruptedException e) {
-            e.printStackTrace();
-            throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.JOB_CREATE_ERROR);
-        } catch (K8sApiException e) {
-            context.appendErrorResult(PipelineException.JOB_CREATE_ERROR, e);
-            throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.JOB_CREATE_ERROR, e);
-        } catch (PipelineException e) {
-            context.appendErrorResult(PipelineException.JOB_IMAGE_NOT_EXIST_ERROR, e);
-            throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.JOB_IMAGE_NOT_EXIST_ERROR);
-        }
+        // 停用,如果镜像没有push成功的话,造成job的pod状态是 ImagePullBackOff 状态,但是pod是处于waiting状态,查不到
+        // 后续再调查怎么办吧
+//        try {
+//            Thread.sleep(3000L);
+//            List<Job> jobs = jobApi.getByCondition(K8sObjectRequest.builder()
+//                    .name(jobName)
+//                    .namespace(namespace)
+//                    .build());
+//            if (jobs.size() == 1){
+//                Job k8s_job = jobs.get(0);
+//                V1JobStatus status = k8s_job.getStatus();
+//                if (status != null && status.getFailed() != null && status.getFailed() > 0) {
+//                    throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.JOB_IMAGE_NOT_EXIST_ERROR);
+//                }
+//            }
+//        } catch (InterruptedException e) {
+//            e.printStackTrace();
+//            throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.JOB_CREATE_ERROR);
+//        } catch (K8sApiException e) {
+//            context.appendErrorResult(PipelineException.JOB_CREATE_ERROR, e);
+//            throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.JOB_CREATE_ERROR, e);
+//        } catch (PipelineException e) {
+//            context.appendErrorResult(PipelineException.JOB_IMAGE_NOT_EXIST_ERROR, e);
+//            throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.JOB_IMAGE_NOT_EXIST_ERROR);
+//        }
+//        context.appendSuccessResult("Job 检查通过,运行正常");
     }
 }

+ 2 - 2
web/src/main/java/cn/seecoder/web/dao/project/CommitMapper.java → web/src/main/java/cn/seecoder/web/dao/commit/CommitMapper.java

@@ -1,10 +1,10 @@
-package cn.seecoder.web.dao.project;
+package cn.seecoder.web.dao.commit;
 
 import cn.seecoder.web.model.enums.CommitRelatedEnum;
 import org.apache.ibatis.annotations.*;
 import org.springframework.stereotype.Repository;
 import cn.seecoder.web.dao.provider.GeneralInsertUpdateSqlProvider;
-import cn.seecoder.web.model.po.project.CommitPO;
+import cn.seecoder.web.model.po.commit.CommitPO;
 
 import java.util.List;
 

+ 36 - 0
web/src/main/java/cn/seecoder/web/dao/commit/CommitQualityMapper.java

@@ -0,0 +1,36 @@
+package cn.seecoder.web.dao.commit;
+
+import cn.seecoder.web.dao.provider.GeneralInsertUpdateSqlProvider;
+import cn.seecoder.web.model.po.commit.CommitQualityPO;
+import org.apache.ibatis.annotations.*;
+import org.springframework.security.core.parameters.P;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author claws
+ */
+@Repository
+public interface CommitQualityMapper {
+    @Select("select * from commit_quality where project_id = #{projectId}")
+    List<CommitQualityPO> selectByProjectId(@Param("projectId") int projectId);
+
+    // 这里的Map Key对应的是PO中的属性
+    @MapKey("commitHash")
+    @Select("select * from commit_quality where project_id = #{projectId}")
+    Map<String, CommitQualityPO> selectMapByProjectId(@Param("projectId") int projectId);
+
+    @Select("select * from commit_quality where commit_hash = #{commitHash}")
+    CommitQualityPO selectByCommitHash(@Param("commitHash") String commitHash);
+
+    @InsertProvider(type = GeneralInsertUpdateSqlProvider.class, method = "insert")
+    int insert(CommitQualityPO commitQualityPO, String... ignoredCols);
+
+    @InsertProvider(type = GeneralInsertUpdateSqlProvider.class, method = "updateById")
+    int update(CommitQualityPO commitQualityPO);
+
+    @Delete("delete from commit_quality where commit_hash = #{commitHash}")
+    int deleteByCommitHash(@Param("commitHash") String commitHash);
+}

+ 25 - 0
web/src/main/java/cn/seecoder/web/model/enums/CommitCheckResultEnum.java

@@ -0,0 +1,25 @@
+package cn.seecoder.web.model.enums;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * @author claws
+ */
+public enum CommitCheckResultEnum {
+    @JsonProperty("pass")
+    PASS("pass"),
+    @JsonProperty("fail")
+    FAIL("fail"),
+    @JsonProperty("none")
+    NONE("none");
+
+    private final String value;
+    CommitCheckResultEnum(String value) {
+        this.value = value;
+    }
+
+    @Override
+    public String toString(){
+        return value;
+    }
+}

+ 1 - 1
web/src/main/java/cn/seecoder/web/model/po/project/CommitPO.java → web/src/main/java/cn/seecoder/web/model/po/commit/CommitPO.java

@@ -1,4 +1,4 @@
-package cn.seecoder.web.model.po.project;
+package cn.seecoder.web.model.po.commit;
 
 import cn.seecoder.web.model.enums.CommitRelatedEnum;
 import lombok.AllArgsConstructor;

+ 26 - 0
web/src/main/java/cn/seecoder/web/model/po/commit/CommitQualityPO.java

@@ -0,0 +1,26 @@
+package cn.seecoder.web.model.po.commit;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+
+/**
+ * @author claws
+ * @description: 代码版本质量检查
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class CommitQualityPO {
+    private Integer id;
+    private Integer projectId;
+    private String commitHash;
+    private String sonarProjectKey;
+    private String checkResult;
+    private Date checkTime;
+}

+ 5 - 2
web/src/main/java/cn/seecoder/web/model/vo/project/CommitVO.java → web/src/main/java/cn/seecoder/web/model/vo/commit/CommitVO.java

@@ -1,7 +1,8 @@
-package cn.seecoder.web.model.vo.project;
+package cn.seecoder.web.model.vo.commit;
 
+import cn.seecoder.web.model.enums.CommitCheckResultEnum;
 import cn.seecoder.web.model.enums.CommitRelatedEnum;
-import cn.seecoder.web.model.po.project.CommitPO;
+import cn.seecoder.web.model.po.commit.CommitPO;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -35,6 +36,8 @@ public class CommitVO {
     private Integer relatedId;
     @ApiModelProperty("commit parents")
     private List<String> parents;
+    @ApiModelProperty("commit check result enum")
+    private CommitCheckResultEnum checkResult;
 
     public CommitVO(CommitPO po) {
         BeanUtils.copyProperties(po,this);

+ 8 - 6
web/src/main/java/cn/seecoder/web/model/vo/hook/SonarResultHookVO.java

@@ -25,7 +25,7 @@ public class SonarResultHookVO {
 
     @Data
     @NoArgsConstructor
-    private static class Project{
+    public static class Project{
         private String key;
         private String name;
         private String url;
@@ -33,7 +33,7 @@ public class SonarResultHookVO {
 
     @Data
     @NoArgsConstructor
-    private static class Branch{
+    public static class Branch{
         private String name;
         private String type;
         private Boolean isMain;
@@ -42,14 +42,14 @@ public class SonarResultHookVO {
 
     @Data
     @NoArgsConstructor
-    private static class QualityGate{
+    public static class QualityGate{
         private String name;
         private String status;
         private List<Condition> conditions;
 
         @Data
         @NoArgsConstructor
-        private static class Condition{
+        public static class Condition{
             private String metric;
             private String operator;
             private String value;
@@ -58,13 +58,15 @@ public class SonarResultHookVO {
         }
     }
 
-    private static class Properties{
+    @Data
+    @NoArgsConstructor
+    public static class Properties{
         @JsonProperty("sonar.analysis.detectedscm")
         private String detectedscm;
         @JsonProperty("sonar.analysis.detectedci")
         private String detectedci;
         @JsonProperty("sonar.analysis.projectId")
-        private String projectId;
+        private Integer projectId;
         @JsonProperty("sonar.analysis.imageTag")
         private String imageTag;
         @JsonProperty("sonar.analysis.imageName")

+ 2 - 2
web/src/main/java/cn/seecoder/web/model/vo/tree/TreeNodeVO.java

@@ -9,9 +9,9 @@ import lombok.NoArgsConstructor;
 import org.springframework.beans.BeanUtils;
 import cn.seecoder.web.model.enums.NodeStateEnum;
 import cn.seecoder.web.model.enums.NodeTypeEnum;
-import cn.seecoder.web.model.po.project.CommitPO;
+import cn.seecoder.web.model.po.commit.CommitPO;
 import cn.seecoder.web.model.po.tree.TreeNodePO;
-import cn.seecoder.web.model.vo.project.CommitVO;
+import cn.seecoder.web.model.vo.commit.CommitVO;
 
 import java.util.List;
 import java.util.stream.Collectors;

+ 1 - 2
web/src/main/java/cn/seecoder/web/service/impl/bug_list/BugListServiceImpl.java

@@ -4,7 +4,7 @@ import cn.seecoder.common.util.LogTrackingUtil;
 import cn.seecoder.common.util.OpType;
 import cn.seecoder.web.core.commit.model.CommitState;
 import cn.seecoder.web.dao.bug_list.BugListMapper;
-import cn.seecoder.web.dao.project.CommitMapper;
+import cn.seecoder.web.dao.commit.CommitMapper;
 import cn.seecoder.web.dao.project.ProjectRelatedMapper;
 import cn.seecoder.web.dao.user.UserMapper;
 import cn.seecoder.web.model.enums.BugListStateEnum;
@@ -15,7 +15,6 @@ import cn.seecoder.web.model.vo.bug_list.BugListCreateVO;
 import cn.seecoder.web.model.vo.bug_list.BugListUpdateBasicVO;
 import cn.seecoder.web.model.vo.bug_list.BugListVO;
 import cn.seecoder.web.service.bug_list.BugListService;
-import net.sf.json.JSON;
 import net.sf.json.JSONObject;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;

+ 55 - 44
web/src/main/java/cn/seecoder/web/service/impl/pipeline/DeploymentServiceImpl.java

@@ -35,6 +35,7 @@ import java.util.List;
 import java.util.stream.Collectors;
 
 import static cn.seecoder.web.core.pipeline.template.PipelineTemplateTable.MYSQL;
+import static cn.seecoder.web.core.pipeline.template.PipelineTemplateTable.SONAR_JAVA8;
 
 /**
  * @author PuHong Weng
@@ -70,28 +71,27 @@ public class DeploymentServiceImpl implements DeploymentService {
     public List<DeploymentInfoVO> retrieveDeploymentInfos(Integer projectId) throws AccessDeniedException {
         //projectAuthentication(projectId);
         List<PipelinePO> pipelines = pipelineMapper.selectByProjectId(projectId);
-        if (pipelines.size()==0){
+        if (pipelines.size() == 0) {
             return new ArrayList<>();
         }
         List<Integer> pipelineIds = pipelines.stream().map(PipelinePO::getId).collect(Collectors.toList());
         List<DeploymentPO> deployments = deploymentMapper.selectByPipelineIds(pipelineIds);
-        return deployments.stream().map(x->{
-            PipelineInspector inspector = PipelineInspectorFactory.init(x.getNamespace(),x.getDeployName());
+        return deployments.stream().map(x -> {
+            PipelineInspector inspector = PipelineInspectorFactory.init(x.getNamespace(), x.getDeployName());
             //获取状态
             String status = null;
             V1DeploymentStatus deploymentStatus = inspector.inspectStatus();
-            if (deploymentStatus == null){
+            if (deploymentStatus == null) {
                 status = "部署不存在,请重新部署";
-            }
-            else if(deploymentStatus.getAvailableReplicas()!=null && deploymentStatus.getAvailableReplicas()>=1){
+            } else if (deploymentStatus.getAvailableReplicas() != null && deploymentStatus.getAvailableReplicas() >= 1) {
                 status = "正常运行";
-            } else{
+            } else {
                 status = "不可用";
             }
             return DeploymentInfoVO.builder()
                     .id(x.getId())
                     .pipelineId(x.getPipelineId())
-                    .name(x.getDeployName()+"."+x.getNamespace())
+                    .name(x.getDeployName() + "." + x.getNamespace())
                     .deployedTime(x.getDeployedTime())
                     .accessUrl(x.getAccessUrl())
                     .status(status)
@@ -115,31 +115,41 @@ public class DeploymentServiceImpl implements DeploymentService {
                 .build();
         pipelineRecordMapper.insert(record);
 
+        // 有一些流水线是不产生部署产物的
+        boolean hasDeployment = true;
+        switch (pipelinePO.getTemplateName()) {
+            case SONAR_JAVA8:
+                hasDeployment = false;
+            default:
+        }
 
-        DeploymentPO deployment = deploymentMapper.selectByPipelineId(pipelineId);
-        if (deployment == null){
-            //第一次部署
-            String accessUrl;
-            //根据模板类型设置起的访问路径
-            switch (pipelinePO.getTemplateName()){
-                case MYSQL:
-                    //集群无法暴露tcp端口,只提供了集群内部访问的url
-                    accessUrl = pipelinePO.getName() + K8sConstants.SERVICE_SUFFIX+"."+projectPO.getUniqueK8sNamespace() +".svc.cluster.local";
-                    break;
-                default:
-                    accessUrl = pipelinePO.getName()+"."+projectPO.getUniqueK8sNamespace()+ properties.getK8s().getIngressHostSuffix();
-                    break;
+        // 部署产物记录
+        if (hasDeployment) {
+            DeploymentPO deployment = deploymentMapper.selectByPipelineId(pipelineId);
+            if (deployment == null) {
+                //第一次部署
+                String accessUrl;
+                //根据模板类型设置起的访问路径
+                switch (pipelinePO.getTemplateName()) {
+                    case MYSQL:
+                        //集群无法暴露tcp端口,只提供了集群内部访问的url
+                        accessUrl = pipelinePO.getName() + K8sConstants.SERVICE_SUFFIX + "." + projectPO.getUniqueK8sNamespace() + ".svc.cluster.local";
+                        break;
+                    default:
+                        accessUrl = pipelinePO.getName() + "." + projectPO.getUniqueK8sNamespace() + properties.getK8s().getIngressHostSuffix();
+                        break;
+                }
+                deploymentMapper.insert(DeploymentPO.builder()
+                        .namespace(projectPO.getUniqueK8sNamespace())
+                        .deployName(pipelinePO.getName())
+                        .accessUrl(accessUrl)
+                        .pipelineId(pipelineId)
+                        .deployedTime(record.getStartTime())
+                        .build());
+            } else {
+                deployment.setDeployedTime(record.getStartTime());
+                deploymentMapper.update(deployment);
             }
-            deploymentMapper.insert(DeploymentPO.builder()
-                    .namespace(projectPO.getUniqueK8sNamespace())
-                    .deployName(pipelinePO.getName())
-                    .accessUrl(accessUrl)
-                    .pipelineId(pipelineId)
-                    .deployedTime(record.getStartTime())
-                    .build());
-        } else {
-            deployment.setDeployedTime(record.getStartTime());
-            deploymentMapper.update(deployment);
         }
 
         Pipeline pipeline = null;
@@ -153,12 +163,12 @@ public class DeploymentServiceImpl implements DeploymentService {
             record.setResult(PipelineRecordPO.DEPLOY_FAIL);
             record.setDetails(pipeline.getContext().getResult());
             log.error("流水线配置转换发生错误");
-            throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR,"应用部署失败",e);
-        } catch (RuntimeException e){
+            throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "应用部署失败", e);
+        } catch (RuntimeException e) {
             pipeline.getContext().appendErrorResult("运行时错误: ", e);
             record.setResult(PipelineRecordPO.DEPLOY_FAIL);
             record.setDetails(pipeline.getContext().getResult());
-            throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR,"应用部署失败",e);
+            throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "应用部署失败", e);
         } finally {
             pipelineRecordMapper.update(record);
         }
@@ -166,19 +176,20 @@ public class DeploymentServiceImpl implements DeploymentService {
         List<Integer> pipelineIds = new ArrayList<>();
         pipelineIds.add(pipelineId);
         PipelineRecordPO pipelineRecordPO = pipelineRecordMapper.selectPipelinesLatestRecord(pipelineIds);
-        try{
+        try {
             JSONObject object = new JSONObject();
-            object.put("project_id",projectId);
-            object.put("record_id",pipelineRecordPO.getId());
-            object.put("pipeline_id",pipelineId);
-            object.put("user_id",userId);
-            object.put("type",record.getResult());
+            object.put("project_id", projectId);
+            object.put("record_id", pipelineRecordPO.getId());
+            object.put("pipeline_id", pipelineId);
+            object.put("user_id", userId);
+            object.put("type", record.getResult());
             object.put("result", record.getResult());
-            object.put("success",record.getResult().equals(PipelineRecordPO.DEPLOY_SUCCESS));
+            object.put("success", record.getResult().equals(PipelineRecordPO.DEPLOY_SUCCESS));
             //success?
             String data = JSONObject.toJSONString(object);
             LogTrackingUtil.log(data, OpType.DEPLOY_PIPELINE);
-        }catch (Exception e){}
+        } catch (Exception e) {
+        }
     }
 
     @Override
@@ -187,7 +198,7 @@ public class DeploymentServiceImpl implements DeploymentService {
         //projectAuthentication(projectId);
         DeploymentPO deployment = deploymentMapper.selectByPipelineId(pipelineId);
         deploymentMapper.delete(pipelineId);
-        PipelineInspector inspector = PipelineInspectorFactory.init(deployment.getNamespace(),deployment.getDeployName());
+        PipelineInspector inspector = PipelineInspectorFactory.init(deployment.getNamespace(), deployment.getDeployName());
         inspector.delete();
 
     }
@@ -195,7 +206,7 @@ public class DeploymentServiceImpl implements DeploymentService {
     @Override
     public String log(Integer projectId, Integer pipelineId) {
         DeploymentPO deployment = deploymentMapper.selectByPipelineId(pipelineId);
-        PipelineInspector inspector = PipelineInspectorFactory.init(deployment.getNamespace(),deployment.getDeployName());
+        PipelineInspector inspector = PipelineInspectorFactory.init(deployment.getNamespace(), deployment.getDeployName());
         return inspector.log();
     }
 }

+ 58 - 4
web/src/main/java/cn/seecoder/web/service/impl/project/CommitServiceImpl.java

@@ -2,22 +2,30 @@ package cn.seecoder.web.service.impl.project;
 
 import cn.seecoder.common.util.LogTrackingUtil;
 import cn.seecoder.common.util.OpType;
+import cn.seecoder.web.dao.commit.CommitQualityMapper;
 import cn.seecoder.web.dao.user.UserMapper;
+import cn.seecoder.web.model.enums.CommitCheckResultEnum;
 import cn.seecoder.web.model.enums.CommitRelatedEnum;
 import cn.seecoder.web.model.po.bug_list.BugListPO;
+import cn.seecoder.web.model.po.commit.CommitQualityPO;
 import cn.seecoder.web.model.po.tree.TreeNodePO;
-import cn.seecoder.web.model.vo.project.CommitVO;
+import cn.seecoder.web.model.vo.commit.CommitVO;
+import cn.seecoder.web.model.vo.hook.SonarResultHookVO;
 import cn.seecoder.web.service.bug_list.BugListService;
 import cn.seecoder.web.service.tree.TreeNodeService;
 import com.alibaba.fastjson.JSONObject;
 import com.nju.edu.gitlab.SeecoderGitlabApi;
 import com.nju.edu.gitlab.vo.DiffVO;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import cn.seecoder.web.dao.project.CommitMapper;
-import cn.seecoder.web.model.po.project.CommitPO;
+import cn.seecoder.web.dao.commit.CommitMapper;
+import cn.seecoder.web.model.po.commit.CommitPO;
 import cn.seecoder.web.service.project.CommitService;
 
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -27,6 +35,7 @@ import java.util.stream.Collectors;
  * @description:
  */
 @Service
+@Slf4j
 public class CommitServiceImpl implements CommitService {
 
     private final CommitMapper commitMapper;
@@ -45,6 +54,7 @@ public class CommitServiceImpl implements CommitService {
 
     @Autowired
     private UserMapper userMapper;
+    private CommitQualityMapper commitQualityMapper;
 
     @Override
     public void save(CommitPO po) {
@@ -102,12 +112,14 @@ public class CommitServiceImpl implements CommitService {
     @Override
     public List<CommitVO> getCommitsByBranchName(Integer projectId, String BranchName) {
         List<CommitVO> allCommits = new ArrayList<CommitVO>();
+        Map<String, CommitQualityPO> stringCommitQualityPOMap = commitQualityMapper.selectMapByProjectId(projectId);
 
         try{
             List<com.nju.edu.gitlab.vo.commit.CommitVO> commitsResponse = seecoderGitlabApi.getCommitsByBranch(projectId, BranchName);
             for (com.nju.edu.gitlab.vo.commit.CommitVO commit : commitsResponse){
                 CommitVO commitVO = new CommitVO(commit);
-                CommitPO commitPO = commitMapper.selectByCommitId(commitVO.getId());
+                String hash = commitVO.getId();
+                CommitPO commitPO = commitMapper.selectByCommitId(hash);
                 if (commitPO != null){
 //                System.out.println(commitPO.getId());
                     commitVO.setRelatedType(commitPO.getRelatedType());
@@ -116,6 +128,17 @@ public class CommitServiceImpl implements CommitService {
 //                System.out.println("hh");
                     commitVO.setRelatedType(CommitRelatedEnum.NONE);
                 }
+
+                // deal with check result
+                CommitQualityPO commitQualityPO = stringCommitQualityPOMap.getOrDefault(hash, null);
+                if (commitQualityPO == null) {
+                    commitVO.setCheckResult(CommitCheckResultEnum.NONE);
+                } else if (commitQualityPO.getCommitHash().equals("OK")) {
+                    commitVO.setCheckResult(CommitCheckResultEnum.PASS);
+                } else {
+                    commitVO.setCheckResult(CommitCheckResultEnum.FAIL);
+                }
+
                 allCommits.add(commitVO);
             }
 
@@ -207,4 +230,35 @@ public class CommitServiceImpl implements CommitService {
         }
         return true;
     }
+
+    @Override
+    public boolean processSonarResult(SonarResultHookVO sonarResultHookVO) {
+        try {
+            SonarResultHookVO.Properties properties = sonarResultHookVO.getProperties();
+            String commitHash = properties.getCommitHash();
+            CommitQualityPO commitQualityPO = new CommitQualityPO();
+            commitQualityPO.setProjectId(properties.getProjectId());
+            commitQualityPO.setCommitHash(commitHash);
+            commitQualityPO.setCheckResult(sonarResultHookVO.getQualityGate().getStatus());
+            DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+            simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+            Date date = simpleDateFormat.parse(sonarResultHookVO.getChangedAt());
+            commitQualityPO.setCheckTime(date);
+            commitQualityPO.setSonarProjectKey(sonarResultHookVO.getProject().getKey());
+            CommitQualityPO lastCommitQualityPO = commitQualityMapper.selectByCommitHash(commitHash);
+            if (lastCommitQualityPO != null) {
+                commitQualityPO.setId(lastCommitQualityPO.getId());
+                commitQualityMapper.update(commitQualityPO);
+            } else {
+                commitQualityMapper.insert(commitQualityPO);
+            }
+            return true;
+        } catch (NullPointerException e) {
+            log.error("传入的Sonar Result VO存在问题");
+            return false;
+        } catch (ParseException e) {
+            log.error("传入的时间格式不争取,期待格式:yyyy-MM-dd'T'HH:mm:ss");
+            return false;
+        }
+    }
 }

+ 2 - 2
web/src/main/java/cn/seecoder/web/service/impl/tree/TreeNodeServiceImpl.java

@@ -2,11 +2,11 @@ package cn.seecoder.web.service.impl.tree;
 
 import cn.seecoder.common.util.LogTrackingUtil;
 import cn.seecoder.common.util.OpType;
-import cn.seecoder.web.dao.project.CommitMapper;
+import cn.seecoder.web.dao.commit.CommitMapper;
 import cn.seecoder.web.dao.tree.TreeNodeMapper;
 import cn.seecoder.web.dao.user.UserMapper;
 import cn.seecoder.web.model.enums.*;
-import cn.seecoder.web.model.po.project.CommitPO;
+import cn.seecoder.web.model.po.commit.CommitPO;
 import cn.seecoder.web.model.po.tree.TreeNodePO;
 import cn.seecoder.web.model.po.user.UserPO;
 import cn.seecoder.web.model.vo.tree.TreeNodeCreateVO;

+ 5 - 2
web/src/main/java/cn/seecoder/web/service/project/CommitService.java

@@ -1,8 +1,9 @@
 package cn.seecoder.web.service.project;
 
 import cn.seecoder.web.model.enums.CommitRelatedEnum;
-import cn.seecoder.web.model.po.project.CommitPO;
-import cn.seecoder.web.model.vo.project.CommitVO;
+import cn.seecoder.web.model.po.commit.CommitPO;
+import cn.seecoder.web.model.vo.commit.CommitVO;
+import cn.seecoder.web.model.vo.hook.SonarResultHookVO;
 import com.nju.edu.gitlab.vo.DiffVO;
 
 import java.util.List;
@@ -47,4 +48,6 @@ public interface CommitService {
      * @return
      */
     boolean link(Integer projectId, String commitHash, CommitRelatedEnum relatedType, Integer relatedId);
+
+    boolean processSonarResult(SonarResultHookVO sonarResultHookVO);
 }

+ 17 - 0
web/src/main/resources/sql/table_init.sql

@@ -215,3 +215,20 @@ create table if not exists devcloud.pipeline_record
 )
     charset = utf8;
 
+create table if not exists devcloud.commit_quality
+(
+    id                              int             auto_increment
+        primary key,
+    project_id                      int             not null,
+    commit_hash                     varchar(127)    not null,
+    sonar_project_key               varchar(127)    not null,
+    check_result                    varchar(31)     not null,
+    check_time                      datetime default CURRENT_TIMESTAMP not null
+--     new_reliability_rating          double          null,
+--     new_security_rating             double          null,
+--     new_maintainability_rating      double          null,
+--     new_coverage                    double          null,
+--     new_duplicated_lines_density    double          null,
+--     new_security_hotspots_reviewed  double          null
+) CHARSET=utf8;
+

+ 72 - 0
web/src/test/java/cn/seecoder/web/dao/commit/CommitQualityMapperTest.java

@@ -0,0 +1,72 @@
+package cn.seecoder.web.dao.commit;
+
+import cn.seecoder.web.model.po.commit.CommitQualityPO;
+import org.junit.FixMethodOrder;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.TimeZone;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author claws
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@MapperScan(basePackages = {"cn.seecoder.web.dao"})
+@FixMethodOrder(MethodSorters.JVM)
+public class CommitQualityMapperTest {
+
+    @Autowired
+    private CommitQualityMapper commitQualityMapper;
+
+    // test insert
+    @Test
+    public void test1() throws ParseException {
+        CommitQualityPO commitQualityPO = new CommitQualityPO();
+        commitQualityPO.setCommitHash("iii");
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ssz");
+        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+        Date date = simpleDateFormat.parse("2022-04-25T08:16:28+0000");
+        commitQualityPO.setCheckTime(date);
+        commitQualityPO.setProjectId(999);
+        commitQualityPO.setSonarProjectKey("haha");
+        commitQualityPO.setCheckResult("OK");
+
+        commitQualityMapper.insert(commitQualityPO);
+        CommitQualityPO commitQualityPOResult = commitQualityMapper.selectByCommitHash("iii");
+        Assertions.assertNotNull(commitQualityPOResult);
+        Assertions.assertEquals(999, commitQualityPOResult.getProjectId());
+    }
+
+    // test select map
+    @Test
+    public void test2() {
+        Map<String, CommitQualityPO> stringCommitQualityPOMap = commitQualityMapper.selectMapByProjectId(999);
+        Assertions.assertNotNull(stringCommitQualityPOMap);
+        CommitQualityPO commitQualityPO = stringCommitQualityPOMap.getOrDefault("iii", null);
+        Assertions.assertNotNull(commitQualityPO);
+        Assertions.assertEquals(999, commitQualityPO.getProjectId());
+    }
+
+    // test delete
+    @Test
+    public void test3() {
+        commitQualityMapper.deleteByCommitHash("iii");
+        CommitQualityPO commitQualityPOResult = commitQualityMapper.selectByCommitHash("iii");
+        Assertions.assertNull(commitQualityPOResult);
+    }
+
+
+}

+ 2 - 1
web/src/test/java/cn/seecoder/web/dao/project/CommitMapperTest.java

@@ -1,5 +1,6 @@
 package cn.seecoder.web.dao.project;
 
+import cn.seecoder.web.dao.commit.CommitMapper;
 import cn.seecoder.web.model.enums.CommitRelatedEnum;
 import org.junit.jupiter.api.Test;
 import org.junit.runner.RunWith;
@@ -7,7 +8,7 @@ import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.junit4.SpringRunner;
-import cn.seecoder.web.model.po.project.CommitPO;
+import cn.seecoder.web.model.po.commit.CommitPO;
 
 /**
  * @author PuHong Weng