devops流程中,对接gerrit的设计与实现(二)

一、说在前面的话

接着前文,本文将介绍gerrit的消息通知机制与对接详细。
你需要确保gerrit安装了webhook插件,截止目前的最新版本已默认安装了该插件,如果你的没有,则需要升级gerrit。
其次,在webhooks.config文件中,配置事件及回调地址。
最后,在devops服务中,接收回调报文,并发送im消息给对应的人。

二、gerrit的webhook配置

插件-plugins_webhooks的源码地址:https://github.com/GerritCodeReview/plugins_webhooks。

详细文档,参考https://github.com/GerritCodeReview/plugins_webhooks/blob/master/src/main/resources/Documentation/config.md

[remote "devops"]
  url = http://192.168.5.17/api/v1/gerrit/notify
  event = project-created
  event = patchset-created
  event = reviewer-added
  event = reviewer-deleted
  event = comment-added

另外,你如果想要让所有的事件都触发一个回调地址,如下:

[remote "devops"]
  url = http://192.168.5.17/api/v1/gerrit/notify

三、实现

在这里插入图片描述

3.1、controller层定义api接口,接收gerrit的webhook回调

    @Autowired
    private GerritMessageService gerritMessageService;

    @ApiOperation(value = "gerrit回调")
    @PostMapping(value = "/api//v1/gerrit/notify")
    public ResponseEntity<?> gerritNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String requestJson = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
        if (log.isInfoEnabled()) {
            log.info("gerrit回调的完整信息是{}", requestJson);
        }

        JSONObject jsonObject = JSON.parseObject(requestJson);

        String eventType = jsonObject.getString("type");

        if (StringUtils.isNotEmpty(eventType)) {
            gerritMessageService.notice(eventType, requestJson);
        }

        return ResponseEntity.ok("SUCCESS");
    }

3.2、GerritMessageService.java

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.xxx.gerrit.event.CommentAddedEvent;
import com.xxx.gerrit.event.PatchsetCreatedEvent;
import com.xxx.gerrit.event.ProjectCreatedEvent;
import com.xxx.gerrit.event.ReviewerAddedEvent;
import com.xxx.oa.ProjectInfoService;
import com.xxx.util.MessageFormatUtil;
import com.xxx.wechat.WechatService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

import static com.xxx.util.WxchatRobotUtil.*;

/**
 * @author xxx
 */
@Slf4j
@Service
public class GerritMessageService {

    @Autowired
    private WechatService wechatService;

    public void notice(String eventType, String content) {
        Map<String, String> paramMap = Maps.newHashMap();

        if (GerritEventEnum.PATCHSET_CREATED.getCode().equalsIgnoreCase(eventType)) {
            // 提交后,等待jenkins的Verified+1,再提醒需要code review
//            this.noticeReview(content, paramMap);
        } else if (GerritEventEnum.REVIEWER_ADDED.getCode().equalsIgnoreCase(eventType)) {
            // 新增reviewer
            this.addReviewer(content, paramMap);
        } else if (GerritEventEnum.COMMENT_ADDED.getCode().equalsIgnoreCase(eventType)) {
            this.noticeReviewResult(content, paramMap);
        } else if (GerritEventEnum.PROJECT_CREATED.getCode().equalsIgnoreCase(eventType)) {
            this.noticeCreateProject(content, paramMap);
        }
    }

    private void noticeCreateProject(String content, Map<String, String> paramMap) {
        log.info("创建gerrit工程成功,收到回调通知,发送IM消息给相关人员, content={}", content);

        ProjectCreatedEvent projectCreatedEvent = JSON.parseObject(content, ProjectCreatedEvent.class);
        String projectName = projectCreatedEvent.getProject().getName();
        String realProjectName = projectName.substring(projectName.lastIndexOf("/") + 1);

        // 根据projectName查询工程所在的业务组
        String group = ProjectInfoService.getTag(realProjectName, ProjectInfoService.GERRIT);

        paramMap.put("projectName", realProjectName);

        wechatService.sendByTagName(group, MessageFormatUtil.parseTemplate(GERRIT_PROJECT_CREATE_NOTICE, paramMap));
    }

    private void noticeReview(String content, Map<String, String> paramMap) {
        log.info("gerrit代码需要评审,[content={}]", content);
        // 提醒
        PatchsetCreatedEvent patchsetCreatedEvent = JSON.parseObject(content, PatchsetCreatedEvent.class);
        String project = patchsetCreatedEvent.getChange().getProject();
        String projectName = project.substring(project.lastIndexOf("/") + 1);
        paramMap.put("projectName", projectName);
        paramMap.put("branch", patchsetCreatedEvent.getChange().getBranch());
        // 秒转日期
        paramMap.put("createdOn", DateUtil.formatDateTime(DateUtil.date(
                1000 * patchsetCreatedEvent.getChange().getCreatedOn())));
        paramMap.put("commitMessage", patchsetCreatedEvent.getChange().getCommitMessage());
        paramMap.put("url", patchsetCreatedEvent.getChange().getUrl());

        paramMap.put("name", patchsetCreatedEvent.getUploader().getName());
        paramMap.put("username", patchsetCreatedEvent.getUploader().getUsername());

        // 根据projectName查询工程所在的业务组
        String group = ProjectInfoService.getTag(projectName, ProjectInfoService.GERRIT);

        wechatService.sendByTagName(group, MessageFormatUtil.parseTemplate(GERRIT_REVIEW_NOTICE, paramMap));
    }

    private void addReviewer(String content, Map<String, String> paramMap) {
        log.info("gerrit代码需要评审,[content={}]", content);
        // 提醒
        ReviewerAddedEvent reviewerAddedEvent = JSON.parseObject(content, ReviewerAddedEvent.class);
        String project = reviewerAddedEvent.getChange().getProject();
        String projectName = project.substring(project.lastIndexOf("/") + 1);
        paramMap.put("projectName", projectName);
        paramMap.put("branch", reviewerAddedEvent.getChange().getBranch());
        // 秒转日期
        paramMap.put("createdOn", DateUtil.formatDateTime(DateUtil.date(
                1000 * reviewerAddedEvent.getChange().getCreatedOn())));
        paramMap.put("commitMessage", reviewerAddedEvent.getChange().getCommitMessage());
        paramMap.put("url", reviewerAddedEvent.getChange().getUrl());

        paramMap.put("name", reviewerAddedEvent.getPatchSet().getUploader().getName());
        paramMap.put("username", reviewerAddedEvent.getPatchSet().getUploader().getUsername());
        paramMap.put("adder", reviewerAddedEvent.getAdder().getName());

        // 审核人员
        String phone = reviewerAddedEvent.getReviewer().getUsername();

        wechatService.sendByAccount(phone, MessageFormatUtil.parseTemplate(GERRIT_REVIEW_NOTICE, paramMap));
    }

    private void noticeReviewResult(String content, Map<String, String> paramMap) {
        log.info("gerrit代码评审结果通知,[content={}]", content);
        // 审核结果
        CommentAddedEvent commentAddedEvent = JSON.parseObject(content, CommentAddedEvent.class);

        // 判断
        int unPassedItems = 0;
        int ignoredItems = 0;
        List<CommentAddedEvent.Approval> approvals = commentAddedEvent.getApprovals();

        StringBuilder resultBuilder = new StringBuilder();
        for (CommentAddedEvent.Approval approval : approvals) {
            if ("Code-Review".equals(approval.getType())) {
                resultBuilder.append("Code-Review : ").append(approval.getValue()).append(",\t");
                if ("0".equals(approval.getValue())) {
                    ignoredItems++;
                }
            } else if ("Verified".equals(approval.getType())) {
                resultBuilder.append("Verified : ").append(approval.getValue()).append(",\t");
                if ("0".equals(approval.getValue())) {
                    ignoredItems++;
                }
            }

            if ("-1".equals(approval.getValue()) || "-2".equals(approval.getValue())) {
                unPassedItems++;
            }
        }

        if (ignoredItems == 2) {
            return;
        }

        paramMap.put("reviewResult", resultBuilder.toString());

        String project = commentAddedEvent.getChange().getProject();
        String projectName = project.substring(project.lastIndexOf("/") + 1);
        paramMap.put("projectName", projectName);
        paramMap.put("branch", commentAddedEvent.getChange().getBranch());
        // 秒转日期
        paramMap.put("createdOn", DateUtil.formatDateTime(DateUtil.date(
                1000 * commentAddedEvent.getChange().getCreatedOn())));
        paramMap.put("commitMessage", commentAddedEvent.getChange().getCommitMessage());
        paramMap.put("url", commentAddedEvent.getChange().getUrl());

        paramMap.put("comment", commentAddedEvent.getComment());
        paramMap.put("eventCreatedOn", DateUtil.formatDateTime(DateUtil.date(
                1000 * commentAddedEvent.getEventCreatedOn())));

        paramMap.put("adder", commentAddedEvent.getPatchSet().getUploader().getName());

        // jenkins构建通过, 提醒同组的开发同事去评审
        if (unPassedItems == 0 && "jenkins".equalsIgnoreCase(commentAddedEvent.getAuthor().getUsername())) {
            log.info("gerrit代码需要评审(jenkins验证已通过!),[content={}]", content);

            paramMap.put("name", StringUtils.isEmpty(commentAddedEvent.getPatchSet().getUploader().getName()) ?
                    commentAddedEvent.getPatchSet().getUploader().getUsername() :
                    commentAddedEvent.getPatchSet().getUploader().getName());
            paramMap.put("username", commentAddedEvent.getPatchSet().getUploader().getUsername());

            // 根据projectName查询工程所在的业务组
            String group = ProjectInfoService.getTag(projectName, ProjectInfoService.GERRIT);

            wechatService.sendByTagName(group, MessageFormatUtil.parseTemplate(GERRIT_REVIEW_NOTICE,
                    paramMap));
        } else {
            paramMap.put("name", StringUtils.isEmpty(commentAddedEvent.getAuthor().getName()) ?
                    commentAddedEvent.getAuthor().getUsername() : commentAddedEvent.getAuthor().getName());
            paramMap.put("username", commentAddedEvent.getAuthor().getUsername());

            String phone = commentAddedEvent.getPatchSet().getUploader().getUsername();

            wechatService.sendByAccount(phone, MessageFormatUtil.parseTemplate(
                    unPassedItems == 0 ? GERRIT_REVIEW_PASS : GERRIT_REVIEW_UNPASS,
                    paramMap));
        }
    }
}

四、回调报文示例

  • change-merged事件
{
    "submitter":{
        "name":"xxx",
        "email":"xxx@xx.cn",
        "username":"158xxxx9229"
    },
    "newRev":"b9b071813e739e7d63bfa6efaed9ad4057834578",
    "patchSet":{
        "number":1,
        "revision":"b9b071813e739e7d63bfa6efaed9ad4057834578",
        "parents":[
            "7babe2f1ec9f87c32f5910f87fc7c43e6cd4448c"
        ],
        "ref":"refs/changes/70/40770/1",
        "uploader":{
            "name":"xxx",
            "email":"xxx@xx.cn",
            "username":"158xxxx9229"
        },
        "createdOn":1684137095,
        "author":{
            "name":"xxx",
            "email":"xxx@xx.com",
            "username":""
        },
        "kind":"REWORK",
        "sizeInsertions":51,
        "sizeDeletions":30
    },
    "change":{
        "project":"service/user-service",
        "branch":"master",
        "id":"I56c4ec9321aef6e198a626d305bd78dc78788379",
        "number":40770,
        "subject":"# 2.54.3 - 获取所有区域列表增加省市区筛选",
        "owner":{
            "name":"xxx",
            "email":"xxx@xx.cn",
            "username":"158xxxx9229"
        },
        "url":"http://review.xxx.net/c/service/user-service/+/40770",
        "commitMessage":"# 2.54.3\n- 获取所有区域列表增加省市区筛选\n\nChange-Id: I56c4ec9321aef6e198a626d305bd78dc78788379\n",
        "createdOn":1684137095,
        "status":"MERGED"
    },
    "project":{
        "name":"service/user-service"
    },
    "refName":"refs/heads/master",
    "changeKey":{
        "key":"I56c4ec9321aef6e198a626d305bd78dc78788379"
    },
    "type":"change-merged",
    "eventCreatedOn":1684198055
}
  • comment-added事件(代码评审人员)
{
    "author":{
        "name":"xxx",
        "email":"xxx@xx.cn",
        "username":"158xxxx9229"
    },
    "approvals":[
        {
            "type":"Verified",
            "description":"Verified",
            "value":"0"
        },
        {
            "type":"Code-Review",
            "description":"Code-Review",
            "value":"2",
            "oldValue":"0"
        }
    ],
    "comment":"Patch Set 1: Code-Review+2",
    "patchSet":{
        "number":1,
        "revision":"b9b071813e739e7d63bfa6efaed9ad4057834578",
        "parents":[
            "7babe2f1ec9f87c32f5910f87fc7c43e6cd4448c"
        ],
        "ref":"refs/changes/70/40770/1",
        "uploader":{
            "name":"xxx",
            "email":"xxx@xx.cn",
            "username":"158xxxx9229"
        },
        "createdOn":1684137095,
        "author":{
            "name":"xxx",
            "email":"xxx@xx.com",
            "username":""
        },
        "kind":"REWORK",
        "sizeInsertions":51,
        "sizeDeletions":30
    },
    "change":{
        "project":"service/user-service",
        "branch":"master",
        "id":"I56c4ec9321aef6e198a626d305bd78dc78788379",
        "number":40770,
        "subject":"# 2.54.3 - 获取所有区域列表增加省市区筛选",
        "owner":{
            "name":"xxx",
            "email":"xxx@xx.cn",
            "username":"158xxxx9229"
        },
        "url":"http://review.xx.net/c/service/user-service/+/40770",
        "commitMessage":"# 2.54.3\n- 获取所有区域列表增加省市区筛选\n\nChange-Id: I56c4ec9321aef6e198a626d305bd78dc78788379\n",
        "createdOn":1684137095,
        "status":"NEW"
    },
    "project":{
        "name":"service/user-service"
    },
    "refName":"refs/heads/master",
    "changeKey":{
        "key":"I56c4ec9321aef6e198a626d305bd78dc78788379"
    },
    "type":"comment-added",
    "eventCreatedOn":1684198053
}
  • comment-added事件(jenkins工具,Verified+1)
{
    "author":{
        "username":"jenkins"
    },
    "approvals":[
        {
            "type":"Verified",
            "description":"Verified",
            "value":"1",
            "oldValue":"0"
        },
        {
            "type":"Code-Review",
            "description":"Code-Review",
            "value":"0"
        }
    ],
    "comment":"Patch Set 1: Verified+1\n\nBuild Successful \n\nhttp://cd.xxx.net/job/V_resource_java_user-service/167/ : SUCCESS",
    "patchSet":{
        "number":1,
        "revision":"e660287f84476680bad5636d4a6ed8d9d654297b",
        "parents":[
            "5bc9463d90172a9e7b650d46a198f0513c446acc"
        ],
        "ref":"refs/changes/76/40776/1",
        "uploader":{
            "name":"xxx",
            "email":"xxx@xx.cn",
            "username":"134xxxx0708"
        },
        "createdOn":1684222769,
        "author":{
            "name":"xxx",
            "email":"xxx@xx.com",
            "username":""
        },
        "kind":"REWORK",
        "sizeInsertions":76,
        "sizeDeletions":5
    },
    "change":{
        "project":"resource/user-service",
        "branch":"master",
        "id":"I850b63f3b03d3df7905ad6b027482ec9a385df48",
        "number":40776,
        "subject":"字符统计增加详解字符统计",
        "owner":{
            "name":"xxx",
            "email":"xxx@xx.cn",
            "username":"134xxxx0708"
        },
        "url":"http://review.xxx.net/c/resource/user-service/+/40776",
        "commitMessage":"字符统计增加详解字符统计\n\nChange-Id: I850b63f3b03d3df7905ad6b027482ec9a385df48\n",
        "createdOn":1684222769,
        "status":"NEW"
    },
    "project":{
        "name":"resource/user-service"
    },
    "refName":"refs/heads/master",
    "changeKey":{
        "key":"I850b63f3b03d3df7905ad6b027482ec9a385df48"
    },
    "type":"comment-added",
    "eventCreatedOn":1684222949
}
  • patchset-created事件
{
    "uploader":{
        "name":"xxx",
        "email":"xxx@xx.cn",
        "username":"182xxxx0316"
    },
    "patchSet":{
        "number":1,
        "revision":"78de0ddced5c4a29265773a9c3df234ed81e991f",
        "parents":[
            "3da50a3658865f3ff930a2bca0581a202e14a807"
        ],
        "ref":"refs/changes/77/40777/1",
        "uploader":{
            "name":"xxx",
            "email":"xxx@xx.cn",
            "username":"182xxxx0316"
        },
        "createdOn":1684223816,
        "author":{
            "name":"182xxxx0316",
            "email":"xxx@xx.com",
            "username":""
        },
        "kind":"REWORK",
        "sizeInsertions":41,
        "sizeDeletions":43
    },
    "change":{
        "project":"root/user-service",
        "branch":"master",
        "id":"I11baec7db30d8bbb71f5155e55e51bd4d6cc5ef9",
        "number":40777,
        "subject":"1.修改开关相关字段命名",
        "owner":{
            "name":"xxx",
            "email":"xxx@xx.cn",
            "username":"182xxxx0316"
        },
        "url":"http://review.xxx.net/c/root/user-service/+/40777",
        "commitMessage":"1.修改开关相关字段命名\n\nChange-Id: I11baec7db30d8bbb71f5155e55e51bd4d6cc5ef9\n",
        "createdOn":1684223816,
        "status":"NEW"
    },
    "project":{
        "name":"root/user-service"
    },
    "refName":"refs/heads/master",
    "changeKey":{
        "key":"I11baec7db30d8bbb71f5155e55e51bd4d6cc5ef9"
    },
    "type":"patchset-created",
    "eventCreatedOn":1684223817
}
  • reviewer-added事件(略)
  • project_created事件(略)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天草二十六_简村人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值