想法的來源
某大佬讓我實現gitlab的webhook,監聽到其它分支合併到mater分支後給DY發郵件。我做過用 push 到 github觸發jenkins實現自動部署,但是那個時候就是自己玩,不用考慮分支和其它。其實一旦扯到分支上,其實我個人感覺就難了。但是,還是要乾的。
思路
(1)自信滿滿
一開始我想簡單啊,在項目裏的URL添加自己阿里雲的一個sout接口,選擇Merge requet events,點擊Add webhook。如下圖所示,這不就OK了嗎?
因爲我自己沒事整 本地push到github然後觸發jenkins自動構建項目也是這麼簡單啊。
(2)備受挫折
1)創建merge請求
2)修改merge請求
3)撤銷merge請求
4)重新打開merge請求
5)同意merge請求
都觸發我的請求,我哪知道哪種是哪種,而且我想要合併到master的請求,現在dev1合併到dev2也給觸發,很亂。
(3)受人指點
但是我就發現其實有很多操作是會調用這個上面鉤子程序的URL的,然後就在這個時候,一位叫勝哥的給我指了條明路,看文檔,就是上圖中的箭頭,從此就解決了很多疑惑。
然後在文檔中找到如下圖所示的內容,這不就是我想要的東西嗎?
(3)獲取請求體裏的內容
百度了一段代碼,獲取了上圖中的請求體(要親自試,你纔會明白裏面參數的含義)
@RequestMapping("/email")
@ResponseBody
public String sendEmail(HttpServletRequest request) {
InputStream is = null;
try {
is = request.getInputStream();
StringBuilder sb = new StringBuilder();
byte[] b = new byte[4096];
for (int n; (n = is.read(b)) != -1; ) {
sb.append(new String(b, 0, n));
}
System.out.println("----------------------->");
System.out.println(sb);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != is) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 發送郵件
//emailService.sendSimpleMail();
return "success";
(4)分析請求體
我有五份請求體,正如步驟(3)中的5種情況。分析他們的不同,其實就是看他們有什麼區別
這裏用到了超級好用 json 格式化網站 https://tool.lu/json/
因爲我的需求是我要合併請求並且合併到master分支的才進行業務邏輯,所以就在網站裏分析。
打開兩個格式化json的網頁,當你在這兩個頁面之間來回切換你就能發現他們的不同(除了時間)
(5)分析出不同的參數,寫代碼
import io.swagger.annotations.Api;
import lombok.Data;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
/**
* @author chaird
* @create 2020-06-18 23:22
*/
@Api("分支合併到master鉤子接口")
@RestController
@RequestMapping("/admin/webhook")
public class WebHookController {
/** merge請求狀態 */
private final String MERGE_STATUS = "can_be_merged";
/** merge操作狀態 */
private final String STATUS = "merged";
/** 目標分支,即要合併到的分支 */
private final String TARGET_BRANCH = "master";
@RequestMapping(value = "/invokeMergeHook", method = RequestMethod.POST)
public Object invokeMergeHook(@RequestBody GLWHRootInfo glwhRootInfo) {
String result;
try {
// 獲取項目名稱
String projectName = glwhRootInfo.getProject().getName();
// 獲取gitlab觸發此次請求的操作類型,比如提交、同意、撤銷合併分支請求
String merge_status = glwhRootInfo.getObject_attributes().getMerge_status();
String state = glwhRootInfo.getObject_attributes().getState();
// 獲取source分支和獲取target分支
String target_branch = glwhRootInfo.getObject_attributes().getTarget_branch();
String source_branch = glwhRootInfo.getObject_attributes().getSource_branch();
// 獲取操作用戶郵箱
String user_email =
glwhRootInfo.getObject_attributes().getLast_commit().getAuthor().getEmail();
// 如果merge_status爲D0_MERGE 並且目標分支是master分支
if (MERGE_STATUS.equals(merge_status)
&& STATUS.equals(state)
&& TARGET_BRANCH.equals(target_branch)) {
System.out.println("--------------->發郵件");
String msg =
"此郵件爲測試郵件:"
+ "此郵件爲測試郵件"
+ "\n"
+ "projectName:"
+ projectName
+ "\n"
+ "target_branch:"
+ target_branch
+ "\n"
+ "source_branch:"
+ source_branch
+ "\n"
+ "user_email:"
+ user_email;
// 發送郵箱
System.out.println("-------------------------------------------------------");
result = "分支合併成功並且符合發送郵箱要求";
} else {
result = "不符合發送郵箱要求";
}
} catch (Exception e) {
return "非gitlab發送的請求";
}
return result;
}
}
/** Gitlab觸發webhook中的RequestBody對應的實體類 */
@Data
class GLWHRootInfo {
private String object_kind;
private User user;
private Project project;
private Object_attributes object_attributes;
List<String> labels = new ArrayList<>();
private Changes changes;
private Repository repository;
}
@Data
class State {
private String previous;
private String current;
}
@Data
class Author {
private String name;
private String email;
}
@Data
class Changes {
private State state;
private Updated_at updated_at;
private Total_time_spent total_time_spent;
}
@Data
class Last_commit {
private String id;
private String message;
private String timestamp;
private String url;
private Author author;
}
@Data
class Merge_params {
private String force_remove_source_branch;
}
@Data
class Object_attributes {
private String assignee_id;
private int author_id;
private String created_at;
private String description;
private String head_pipeline_id;
private int id;
private int iid;
private String last_edited_at;
private String last_edited_by_id;
private String merge_commit_sha;
private String merge_error;
private Merge_params merge_params;
private String merge_status;
private String merge_user_id;
private boolean merge_when_pipeline_succeeds;
private String milestone_id;
private String source_branch;
private Integer source_project_id;
private String state;
private String target_branch;
private Integer target_project_id;
private Integer time_estimate;
private String title;
private String updated_at;
private String updated_by_id;
private String url;
private Source source;
private Target target;
private Last_commit last_commit;
private boolean work_in_progress;
private Integer total_time_spent;
private String human_total_time_spent;
private String human_time_estimate;
private String action;
}
@Data
class Project {
private int id;
private String name;
private String description;
private String web_url;
private String avatar_url;
private String git_ssh_url;
private String git_http_url;
private String namespace;
private int visibility_level;
private String path_with_namespace;
private String default_branch;
private String ci_config_path;
private String homepage;
private String url;
private String ssh_url;
private String http_url;
}
@Data
class Repository {
private String name;
private String url;
private String description;
private String homepage;
}
@Data
class Source {
private int id;
private String name;
private String description;
private String web_url;
private String avatar_url;
private String git_ssh_url;
private String git_http_url;
private String namespace;
private Integer visibility_level;
private String path_with_namespace;
private String default_branch;
private String ci_config_path;
private String homepage;
private String url;
private String ssh_url;
private String http_url;
}
@Data
class Target {
private int id;
private String name;
private String description;
private String web_url;
private String avatar_url;
private String git_ssh_url;
private String git_http_url;
private String namespace;
private int visibility_level;
private String path_with_namespace;
private String default_branch;
private String ci_config_path;
private String homepage;
private String url;
private String ssh_url;
private String http_url;
}
@Data
class Total_time_spent {
private String previous;
private Integer current;
}
@Data
class Updated_at {
private String previous;
private String current;
}
@Data
class User {
private String name;
private String username;
private String avatar_url;
}
(6)驀然回首
文檔上都說了啥時候觸發請求,我沒用看到,我自己試出來的,然後有什麼用呢,不看文檔的人會喫虧的。
總結
1)看文檔,看官方文檔(雖然我還沒有做到),這是技術人員的必經之路。
2)其實我我沒有感覺做出來多少厲害,我只是感覺從解決問題的過程中學到解決問題的思路以及看請求體的重要性。
3)有人指導,這確實是一看運氣
參考
https://git.lug.ustc.edu.cn/help/user/project/integrations/webhooks
https://blog.csdn.net/qq_37171353/article/details/106470391