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("\r\n"," ");
            String latestCommitUser = latestCommit.getJSONObject("author").getString("name");
            commitInfo = "\n>Tag描述:"+newTagMsg
                    +"\n>最近一次提交信息:"+latestCommitMsg
                    +"\n>最近一次提交人:"+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!"
                +"\n>Tag名稱:"+tag
                +commitInfo
                +"\n>[查看詳情]("+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("\n","");
        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!"
                +"\n>標題:"+title
                +"\n>描述:"+description
                +"\n>Source Branch:"+source
                +"\n>Target Branch:"+target
                +"\n>最近一次提交信息:"+lastCommitMsg
                +"\n>最近一次提交人:"+lastCommitUser
                +"\n>[查看詳情]("+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,感受它帶來的擴展和便捷。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM