Jenkins教程(八)实现 GitLab 触发 Jenkins 自动按模块发布前端
楔子
上篇文章解決了提交/合并請(qǐng)求自動(dòng)觸發(fā)的需求,但所有前端模塊都在同一個(gè)代碼倉庫里,如何獲取變更文件路徑確定要發(fā)布哪個(gè)模塊呢?本文將帶你解決這個(gè)問題。
思路
分別解決 3 個(gè)問題:
過程
GitLab 事件觸發(fā) Jenkins 構(gòu)建只是一個(gè)啟動(dòng)信號(hào),獲取變更文件列表需要知曉上一次構(gòu)建時(shí)某個(gè)倉庫的版本號(hào),這里 Jenkins 的插件 git-plugin 已經(jīng)幫我們實(shí)現(xiàn)了這部分工作。所以只需要通過 git-plugin 檢出代碼即可。
檢出代碼
checkout([$class: 'GitSCM',branches: [[name: "*/$branchName"]],doGenerateSubmoduleConfigurations: false,extensions: [[$class: 'RelativeTargetDirectory',relativeTargetDir: "$relativeTarget"]],submoduleCfg: [],userRemoteConfigs: [[credentialsId: "$credentialsId", url: "$gitUrl"]]])請(qǐng)自行替換 $branchName 為分支名,$relativeTarget 為檢出相對(duì)路徑,$credentialsId 為用戶憑據(jù), $gitUrl 即 GIT倉庫地址。
獲取變更文件列表
//獲取變更文件列表,返回HashSet,注意添加的影響文件路徑不含倉庫目錄名 @NonCPS def getChangeFilePathSet() {def changedFiles = new HashSet<String>();echo "開始獲取變更的文件列表"for (int i = 0; i < currentBuild.changeSets.size(); i++) {def entries = currentBuild.changeSets[i].itemsfor (int j = 0; j < entries.length; j++) {def entry = entries[j]changedFiles.addAll(entry.getAffectedPaths());}}println '輸出修改文件列表:' + changedFilesreturn changedFiles; }這個(gè)方法可以放到 pipeline 塊外,直接在 script 塊中引用。實(shí)現(xiàn)思路是訪問 currentBuild.changeSets 獲取所有本次構(gòu)建相比上次構(gòu)建的變更列表,返回的是 HashSet 是為了方便,用其他容器也是可以的。
注意:變更文件列表的各個(gè)文件是相對(duì)于它所在倉庫的路徑!
變更文件列表截字符串,獲取模塊列表并去重
//獲取合并報(bào)表前端自動(dòng)發(fā)布模塊set集合。 //pathPrefix為模塊路徑前綴,如develop/@gc @NonCPS def getAutoPublishModuleSet(pathPrefix) {//使用Set容器去重,保證待發(fā)布模塊只有一份def modulePaths = new HashSet<String>();for(def filePath in getChangeFilePathSet()){//忽略非前端模塊的文件,比如 Jenkinsfile 等if(filePath.startsWith(pathPrefix)){//從超過模塊前綴長度的下標(biāo)開始,獲取下一個(gè)/的位置。即分串位置int index = filePath.indexOf('/', pathPrefix.length()+1)//分串得到模塊路徑,比如 develop/@gc/testdef modulePath = filePath.substring(0, index)println 'add module path: ' + modulePathmodulePaths.add(modulePath)}}println '輸出待發(fā)布模塊列表:' + modulePathsreturn modulePaths; }寫個(gè)構(gòu)建發(fā)布 Shell 腳本
publish-web-module.sh
#!/bin/bash #此腳本用于構(gòu)建發(fā)布前端模塊,@author: Hellxz #$1:發(fā)布版本/$2:模塊目錄 set -euecho "------------開始發(fā)布$2模塊------------>" cd $2 echo "清理dist node_modules package-lock.json ……" rm -rf dist node_modules package-lock.json echo "正在安裝依賴 ……" npm i echo "開始構(gòu)建 ……" npm run build:dev echo "開始發(fā)布 ……" npm --no-git-tag-version version $1 npm publish echo "<------------發(fā)布$2模塊完成------------"cd ${WORKSPACE}/web; #回到前端源碼目錄 exit 0;循環(huán)調(diào)用構(gòu)建發(fā)布腳本
for(def modulePath in modulePaths){sh label: "構(gòu)建發(fā)布前端模塊 ${publishVersion} ${modulePath}", script: "bash ${SHELL_PATH}/publish-web-module.sh ${publishVersion} ${modulePath}" }流水線示例
需將下列 Jenkinsfile 與 publish-web-module.sh 提交到同一倉庫中
Jenkinsfile
pipeline{agent any;environment{gitUrl="http://xxxxxxxx/xxxx/web.git"branchName=devrelativeTarget="web"credentialsId=credentials('git-user')pathPrefix="develop/@gc"publishVersion="v1.0"npmRepo="http://xxxxxx/nexus/repository/npm-public/"npmToken=credentials('npm-token')shellPath="${WORKSPACE}/jenkins" //腳本與Jenkinsfile在同級(jí)目錄中}stages{stage("檢出代碼"){steps{script {cleanWs()checkoutRepo("master", "jenkins", "${credentialsId}", "http://xxxxxxxx/xxxx/jenkins.git")checkoutRepo("${branchName}", "${relativeTarget}", "${credentialsId}", "${gitUrl}")}}}stage("構(gòu)建發(fā)布"){steps{script{sh label: "設(shè)置npm倉庫", script: "npm set registry ${npmRepo}"sh label: "登錄npm倉庫", script: "npm config set //xxxxxx/nexus/repository/npm-public/:_authToken ${npmToken}"def modulePaths = getAutoPublishModuleSet(env.pathPrefix)for(def modulePath in modulePaths){sh label: "構(gòu)建發(fā)布前端模塊 ${publishVersion} ${modulePath}", script: "bash ${shellPath}/publish-web-module.sh ${publishVersion} ${modulePath}"}}}post{always{script{cleanWs()}}}}} }//抽取檢出代碼方法 @NonCPS def checkoutRepo(branchName, relativeTarget, credentialsId, gitUrl){checkout([$class: 'GitSCM',branches: [[name: "*/$branchName"]],doGenerateSubmoduleConfigurations: false,extensions: [[$class: 'RelativeTargetDirectory',relativeTargetDir: "$relativeTarget"]],submoduleCfg: [],userRemoteConfigs: [[credentialsId: "$credentialsId", url: "$gitUrl"]]]) }//獲取變更文件列表,返回HashSet,注意添加的影響文件路徑不含倉庫目錄名 @NonCPS def getChangeFilePathSet() {def changedFiles = new HashSet<String>();echo "開始獲取變更的文件列表"for (int i = 0; i < currentBuild.changeSets.size(); i++) {def entries = currentBuild.changeSets[i].itemsfor (int j = 0; j < entries.length; j++) {def entry = entries[j]changedFiles.addAll(entry.getAffectedPaths());}}println '輸出修改文件列表:' + changedFilesreturn changedFiles; }//獲取合并報(bào)表前端自動(dòng)發(fā)布模塊set集合。 @NonCPS def getAutoPublishModuleSet(pathPrefix) {//使用Set容器去重,保證待發(fā)布模塊只有一份def modulePaths = new HashSet<String>();for(def filePath in getChangeFilePathSet()){//忽略非前端模塊的文件,比如 Jenkinsfile 等if(filePath.startsWith(pathPrefix)){//從超過模塊前綴長度的下標(biāo)開始,獲取下一個(gè)/的位置。即分串位置int index = filePath.indexOf('/', pathPrefix.length()+1)//分串得到模塊路徑,比如 develop/@gc/testdef modulePath = filePath.substring(0, index)println 'add module path: ' + modulePathmodulePaths.add(modulePath)}}println '輸出待發(fā)布模塊列表:' + modulePathsreturn modulePaths; }僅供拋磚引玉,抽取出來的方法本人將它們放到共享庫中,寫腳本就更清晰簡(jiǎn)短了。
還有什么問題
- 首次構(gòu)建會(huì)識(shí)別不到提交記錄,可能會(huì)漏發(fā)一次
- 切到未構(gòu)建過的分支,也會(huì)漏發(fā)一次
- 限于文章篇幅,未添加手動(dòng)傳參指定模塊發(fā)布的功能
對(duì)于多分支首次檢出漏發(fā)的問題,這是因?yàn)闆]有上一個(gè)可供參考的相同分支提交ID作參考,本身不是技術(shù)問題,預(yù)先將所有前端發(fā)版分支提交點(diǎn)內(nèi)容,只要構(gòu)建觸發(fā)了,后續(xù)就不會(huì)再漏發(fā)了。
最后
希望對(duì)您能有所啟發(fā),如果您有更優(yōu)雅的實(shí)現(xiàn)方式 或者 文中有錯(cuò)誤,希望您能不吝賜教評(píng)論指出,感謝。
本文同步發(fā)布于博客園(東北小狐貍 https://www.cnblogs.com/hellxz/)與CSDN(東北小狐貍-Hellxz https://blog.csdn.net/u012586326)禁止轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的Jenkins教程(八)实现 GitLab 触发 Jenkins 自动按模块发布前端的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: file相对路径java_浅谈java
- 下一篇: kaggle数据集下载-搜狐浏览器