• GitLab的Webhook配置和开发


    本文主要介绍如何使用gitlab的webhook来打通企业微信消息提醒。

    前提准备

    企业微信消息发送接口

    根据企业微信开发者文档得到一个消息发送的接口url,参照:企业微信群机器人配置说明

    gitlab(账号,用户组,项目)

    • 生成gitlab账号token
      在这里插入图片描述
      在这里插入图片描述

    • 获取项目的project_id
      参考gitlab如何查询项目ID

    • 获取用户组的group_id
      方法类似于上面project_id的获取

    gitlab开放API文档

    开放API文档
    在这里插入图片描述

    webhook配置和开发

    配置webhook

    在这里插入图片描述

    Secret TokenEnable SSL verification配置项可以先不配置。

    在这里配置wenhook,我这里先配置两个触发事件,Tag push events(tag新增/删除事件)和Merge request events(MR新增/删除事件)。

    gitlab的webhook原理

    上面的配置中有一个URL配置项还没有配置。
    想知道这里应该配什么,首先应该了解gitlab的webhook工作原理。

    这里还是以发送通知到企业微信为例。

    在这里插入图片描述

    1. 项目代码变动往gitlab上推送相应的事件,例如代码push,新建tag,创建merge request等等;
    2. gitlab收到相应事件,触发对应的webhook,设置HTTP请求的header以及request body,然后发送HTTP请求到配置的webhook的URL;
    3. HTTP请求到达对应的处理服务器以后,对request body和header进行解析,包装通知内容;
    4. 将通知的内容通过企业微信的消息发送接口发送到企业微信;
      具体参考webhook使用指南
      在这里插入图片描述
      接下来所有的重点就是这个URL是什么?他应该是一个接口,用来处理gitlab的事件。

    项目实战

    前提准备做好之后,就可以开发处理事件的服务端了(基于SpringBoot项目)。
    以下是一些核心代码。
    GitLabApiUtils.java

    /**
         * 获取所以项目master成员
         * @param projectId
         * @return
         */
        public static List<String> getAllProjectMembers(Integer projectId) {
            getProjectMembersUrl = getProjectMembersUrl.replace("$",""+projectId);
            getGroupMembersUrl = getGroupMembersUrl.replace("$","800");
            List<String> projectMasterMembers = getGitLabMasterMembers(getProjectMembersUrl);
            List<String> groupMasterMembers = getGitLabMasterMembers(getGroupMembersUrl);
            return Stream.of(projectMasterMembers,groupMasterMembers).flatMap(Collection::stream).distinct().collect(Collectors.toList());
        }
    
    /**
         * 获取master成员
         * @param url
         * @return
         */
        private static List<String> getGitLabMasterMembers(String url) {
            List<String> result = new ArrayList<>();
            OkHttpClient okHttpClient = new OkHttpClient();
            Request request = new Request.Builder().url(url).header("PRIVATE-TOKEN",token).build();
            Response response = null;
            try {
                response = okHttpClient.newCall(request).execute();
                String body = response.body().string();
                JSONArray jsonArray = JSONArray.parseArray(body);
                for (int i = 0;i < jsonArray.size();i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    if (jsonObject.getInteger("access_level") == 40) {
                        result.add(jsonObject.getString("name"));
                    }
                }
            } catch (IOException e) {
                log.error("调用GitLab API失败!",e);
            } finally {
                if (response != null) {
                    response.close();
                }
            }
            return result;
        }
    

    这个例子中只做了Tag Push Event和Merge Request Event的处理,主要是根据不同的事件构建不同的企业微信消息内容。其他的可以自己扩展。
    MessageStrategy.java

    /**
     * 构建消息内容
     */
    public interface MessageStrategy {
        String produceMsg(JSONObject jsonObject);
    }
    

    TagMessageStrategy.java

    @Override
        public String produceMsg(JSONObject jsonObject) {
            String operateType = OPERATE_TYPE_ADD;
            if ("0000000000000000000000000000000000000000".equals(jsonObject.getString("after"))) {
                operateType = OPERATE_TYPE_DELETE;
            }
            Integer projectId = jsonObject.getInteger("project_id");
            JSONObject prObject = jsonObject.getJSONObject("project");
            String repo = prObject.getString("name");
            String operator = jsonObject.getString("user_name");
            String tag = jsonObject.getString("ref");
            String[] tagArr = tag.split("/");
            tag = tagArr[tagArr.length-1];
            String detailUrl = prObject.getString("web_url")+"/tags/"+tag;
            String commitInfo = "";
            if (OPERATE_TYPE_ADD.equals(operateType)) {
                String newTagMsg = jsonObject.getString("message");
                JSONObject latestCommit = jsonObject.getJSONArray("commits").getJSONObject(0);
                String latestCommitMsg = latestCommit.getString("message").replaceAll("
    "," ");
                String latestCommitUser = latestCommit.getJSONObject("author").getString("name");
                commitInfo = "
    >Tag描述:"+newTagMsg
                        +"
    >最近一次提交信息:"+latestCommitMsg
                        +"
    >最近一次提交人:"+latestCommitUser;
            }
            List<String> members = GitLabApiUtils.getAllProjectMembers(projectId);
            String alertUsers = members.stream().map(s -> "@"+s+" ").collect(Collectors.joining());
            String alertContent = alertUsers+"<font color=\"info\">【"+repo+"】</font>"+operator+"<font color=\"info\">"+operateType+"</font>了一个Tag!"
                    +"
    >Tag名称:"+tag
                    +commitInfo
                    +"
    >[查看详情]("+detailUrl+")";
            return alertContent;
        }
    

    MRMessageStrategy.java

    @Override
        public String produceMsg(JSONObject jsonObject) {
            String operator = jsonObject.getJSONObject("user").getString("name");
            JSONObject objectAttributes = jsonObject.getJSONObject("object_attributes");
            String operateType = "变更";
            String state = objectAttributes.getString("state");
            if ("closed".equals(state)) {
                operateType = "关闭";
            } else if ("opened".equals(state)) {
                operateType = "新增";
            } else if ("merged".equals(state)) {
                operateType = "审核通过";
            }
            String source = objectAttributes.getString("source_branch");
            String target = objectAttributes.getString("target_branch");
            Integer projectId = objectAttributes.getInteger("target_project_id");
            String title = objectAttributes.getString("title");
            String description = objectAttributes.getString("description");
            JSONObject lastCommit = objectAttributes.getJSONObject("last_commit");
            String lastCommitMsg = lastCommit.getString("message").replaceAll("
    ","");
            String lastCommitUser = lastCommit.getJSONObject("author").getString("name");
            String repo = objectAttributes.getJSONObject("target").getString("name");
            String url = objectAttributes.getString("url");
            List<String> members = GitLabApiUtils.getAllProjectMembers(projectId);
            String alertUsers = members.stream().map(s -> "@"+s+" ").collect(Collectors.joining());
            String alertContent = alertUsers+"<font color=\"info\">【"+repo+"】</font>"+operator+"<font color=\"info\">"+operateType+"</font>了一个Merge Request!"
                    +"
    >标题:"+title
                    +"
    >描述:"+description
                    +"
    >Source Branch:"+source
                    +"
    >Target Branch:"+target
                    +"
    >最近一次提交信息:"+lastCommitMsg
                    +"
    >最近一次提交人:"+lastCommitUser
                    +"
    >[查看详情]("+url+")";
            return alertContent;
        }
    

    AlertController.java

    @PostMapping("/alert")
        public String alert(@RequestBody JSONObject jsonObject, HttpServletRequest request) {
            String bodyContext = "发送成功";
            String objectKind = jsonObject.getString("object_kind");
            MessageStrategy messageStrategy = null;
            if("tag_push".equals(objectKind)) {
                messageStrategy = new TagMessageStrategy();
            } else if("merge_request".equals(objectKind)) {
                messageStrategy = new MRMessageStrategy();
            }
            MessageStrategyContext messageStrategyContext = new MessageStrategyContext(messageStrategy);
            String alertContent = messageStrategyContext.buildMessage(jsonObject);
            log.info("消息内容:"+alertContent);
            String[] cmds={"curl",weChatSendUrl,"-H"
                    ,"Content-Type: application/json","-d","{"msgtype": "markdown","markdown": {"content": ""+alertContent+""}}"};
            ProcessBuilder process = new ProcessBuilder(cmds);
            try {
                process.start();
            } catch (Exception e) {
                bodyContext = "发送失败";
            }
            return bodyContext;
        }
    

    完整代码请查看gitlab-to-企业微信


    经过开发之后webhook配置项里的URL自然也就有了,那就是http://{服务ip}:{服务端口}/alert

    总结

    其实hook这种设计在很多地方都有,且不说一些开源中间件,JDK本身就提供了ShutdownHook,最重要的还是了解hook的工作原理,才能更好的使用hook,感受它带来的扩展和便捷。

  • 相关阅读:
    设计模式之解释器模式
    设计模式之中介者模式
    设计模式之职责链模式
    设计模式之命令模式
    设计模式之迭代器模式
    设计模式之备忘录模式
    设计模式之状态模式
    【转】CSS中position属性( absolute | relative | static | fixed )详解
    【转】fiddler-http协议调试代理工具
    TCP/IP、Http、Socket的区别
  • 原文地址:https://www.cnblogs.com/xuxiaojian/p/14408859.html
Copyright © 2020-2023  润新知