在上一篇博客:CICD:Jenkins入門和使用中,我們學習了Jenkins
的搭建和插件+流水線的基本使用方法,Jenkins
極大地提升了部署效率。
最近想學習一下如何集成GitLab webhook
,實現進一步解放雙手,目標:
- 推送(
git push
)觸發構建 - 推送到指定分支觸發構建
- 根據
commit
的文件,結合mvn -pl
指令,實現部分增量構建,並記錄commit
信息
推送事件也可以換成Tag push events
、Merge request events
等其他觸發條件,根據需要自由選擇。
基礎實現
使用Gitlab Hook Plugin
,並在Jenkins和GitLab中分別配置。
下載並配置插件
在Jenkins 插件管理中搜索並安裝插件:
在Jenkins Job中配置:
在GitLab
中配置
在GitLab中配置:
規避鑒權可以直接在Jenkins中配置允許訪問,將圖示勾選方框里的勾去掉即可:
配置完成后,可以在GitLab中測試
接口返回200,出現如圖所示提醒,配置成功!
到Jenkins里查看,可以看到該Job已經開始構建了。
至此,目標中的前兩條,推送構建和推送到指定分支構建實現!
進階實現
從上述過程,我們也可以看出,WebHook
的本質就是從GitLab
發了一條請求,Jenkins
配置了一個終端地址(endpoint
)來接收,從而實現了兩個步驟的串聯。
這個請求實質上就是一條HTTP POST
請求。
相信接觸過服務互相調用的小伙伴們都不陌生。有了請求體,我們自然可以拿到自己想要的東西,進行進一步的處理了。
請求體內容:
Jenkins插件:Generic WebHook Trigger Pugin
下載並配置Generic WebHook Trigger Pugin
從插件簡介來看,支持接收任何一個HTTP
請求,當然也包括接收GitLab
發送的請求。
在Jenkins Job
中配置接收地址
構建觸發器配置
配置鑒權token
在Jenkins用戶管理中配置鑒權token
我直接使用admin
帳號創建,在發送請求時需要攜帶此token。
GitLab配置
在Gitlab中的配置與上文相同,格式為:
http://admin:${token}@${JENKINS_IP}:${PORT}/generic-webhook-trigger/invoke
填上剛剛配置生成的token
和自己的Jenkins
地址和端口即可。
同樣可以使用自帶的測試來測試連接,返回200成功。
- 如果返回
404
,看配置的地址是否有誤 - 返回
403
,查看權限配置是否有誤
至此,連接建立成功!
編寫流水線腳本
關於如何使用聲明式流水線,上一次的博客已有所介紹。這里主要說明如何加入觸發器語法。
流水線觸發器語法
從JSONPath中獲取參數:
要從請求體中拿到所需要的參數,可以通過配置獲取JSONPath參數實現。
在流水線中加入下列語句,即可當作變量在流水線腳本中使用。
triggers {
GenericTrigger(
genericVariables: [
[key: 'branch', value: '$.ref'],
[key:'commitText', value:'$.commits']
],
causeString: 'Triggered on $branch' ,
printContributedVariables: false,
printPostContent: false
)
}
- 序列化JSON
要想在pipeline腳本中將字符串反序列化成JSON對象,可以引入Pipeline Utility Step
插件,該插件提供了一些工具方法。
下載並安裝Pipeline Utility Step插件:
def commits = readJSON text: commitText
流水線腳本使用
Groovy
語言,該語言基於Java
編寫,也集成了一些有趣的特性。在IDEA中編寫只需要配置Groovy Library
即可。
核心方法
- 根據commits,定義patternMap,匹配到指定正則文件格式,構建指定組件。
def modifiedFile = [];
for (commit in commits) {
modifiedFile.addAll(commit.getAt("added").findAll())
modifiedFile.addAll(commit.getAt("modified").findAll())
modifiedFile.addAll(commit.getAt("removed").findAll())
}
def buildComponents = new HashSet();
def patternMap = ['mark-engine-manager/.*': 'manager', 'mark-tools/.*': 'web','mark-engine-dm/.*':'dm','mark-engine-web/.*':'web',
'mark-engine-uc/.*':'uc','mark-engine-gateway/.*':'gateway'];
//遍歷所有修改了的文件
for (file in modifiedFile) {
for(entry in patternMap.entrySet()){
if (file ==~ entry.key) {
buildComponents << entry.value;
}
}
}
- 根據需要構建的組件,拼接
maven
構建指令。
String mvnCmd = 'mvn clean install -Dmaven.test.skip=true'
for(component in buildComponents){
mvnCmd = mvnCmd + ' -pl mark-engine-'+component+',';
}
經過調試和測試push,三個目標全部完成。
總結
一切都是代碼,CICD當然也可以使用代碼實現。經過實踐我們可以探索出Jenkins更多有趣的玩法。