Jenkins聯動碼雲自動匹配分支進行構建流水線


一、安裝Generic Webhook Trigger插件

image.png

二、創建項目

創建項目之前先准備自己的項目,如果沒有可以我fork的一個項目。地址是:https://gitee.com/jokerbai/simple-java-maven-app.git


由於我這里是使用了Jenkins的share library,可以參考我的配置。地址是:https://gitee.com/jokerbai/jenkins-shareLibrary.git


然后開始正式創建項目。
(1)、創建一個java-maven-test的項目
(2)、定義幾個參數,如下:
image.png
image.png
image.png
image.png
(3)、配置觸發器
選擇我們剛才安裝的觸發器
image.png


配置觸發器,指定一個運行模式。通過這個參數來判斷流水線是手動觸發還是遠程觸發。
image.png


配置TOKEN,這里就將TOKEN指定為項目名
image.png


把日志打印打開,后面會有用
image.png
然后把上面的URL保存下:http://JENKINS_URL/generic-webhook-trigger/invoke


(4)、配置流水線,我這里配置的是share library地址
image.png


(5)、保存退出

三、配置Jenkins和碼雲聯動

1、配置Jenkins用戶和security

在“系統管理–管理用戶–用戶列表–admin處點擊進去–左邊側邊欄–設置”設置用戶API Token
image.png


然后在“系統設置->Configure Global Security”,去掉防止跨站點請求偽造的勾,這樣我們就可以在瀏覽器和碼雲的webhook訪問到api的地址了,不然我們把用戶名和密碼放到url 中,還是不能訪問。


2、配置碼雲webhook

找到webhook管理界面
image.png
添加webhooks
image.png


然后我們點擊測試,看Jenkins是否自動觸發。
image.png


然后我們在Jenkins上可以看到可以自動觸發了,而且可以看到日志如下:
image.png


然后可以隨便修改一下項目內容,提交后看Jenkins運行情況(略)。

四、配置多分支自動匹配構建

(1)、創建一個分支用於測試
image.png
(2)、我們可以分析一下自動觸發構建都傳過來什么參數,把起json格式化一下。
image.png
從上面可以看到我們要的分支是key是"ref"。


(3)、我們重新配置流水線項目,解析我們需要的ref
image.png
其中:branch是自定義名字,$.ref表示解析子串中的ref,其中$表示整個子串。


然后我們隨意修改一下test分支下的代碼,提交以下抓取jenkins的日志。
image.png
可以看到成功獲取到了我們的分支名。


接下來我們就需要修改我們的Jenkinsfile了。
如下:

//String workspace "/opt/jenkins/workspace"
// 配置共享庫
@Library('myLib')

// 引用共享庫中的方法
def tools = new org.devops.tools()
def build = new org.devops.build()
def deploy = new org.devops.deploy()

// 定義變量
String buildType = env.buildType
String buildShell = env.buildShell
String deployHosts = env.deployHosts

String branchName = "${env.branchName}"
String srcUrl = "${env.srcUrl}"

// 獲取分支

if ("${runOpts}" == "GiteePush"){
	branchName = branch - "refs/heads/"
}

// Pipeline
pipeline {
	// 指定在哪個節點上執行pipeline
	agent any
	

	// 獲取自動安裝或者手動安裝的環境變量
	//tools {
	//	maven "M2"
	//}


	// 指定運行的選項(可選)
	options {
		timestamps()	// 日志會有時間
		skipDefaultCheckout()	// 刪除隱式checkout scm語句
		disableConcurrentBuilds()	//禁止並行
		timeout(time:1,unit:'HOURS') //設置流水線超時時間
	}

	// 構建階段
	stages {
		// 下載代碼
		stage("GetCode"){
			// 步驟
			steps{
				// 設置步驟超時時間
				timeout(time:5,unit:'MINUTES'){
					script{

						tools.PrintMes(branchName, "blue")

						// println("獲取代碼")
						tools.PrintMes("獲取代碼",'red')
            checkout([$class: 'GitSCM', branches: [[name: "${branchName}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitee', url: "${srcUrl}"]]])
					}
				}
			}
		}
		stage("Build"){
			steps{
				timeout(time:20,unit:'MINUTES'){
					script{
						// println("代碼打包")
						tools.PrintMes("代碼打包",'blue')
						build.Build(buildType,buildShell)
					}
				}
			}
		}
		stage("CodeScanner"){
			steps{
				timeout(time:30,unit:'MINUTES'){
					script{
						// println("代碼掃描")
						tools.PrintMes("代碼掃描",'green')
					}
				}
			}
		}
	}

	// 構建后的操作
	post {
		always {
			script{
				println("always:不論構建成功與否都會執行")
			}
		}
		success {
			script{
				println("success:只有構建成功才會執行")
				currentBuild.description = "\n構建成功!"
				// deploy.AnsibleDeploy("${deployHosts}","-m ping")
			}
		}
		failure {
			script{
				println("failure:只有構建失敗才會執行")
				currentBuild.description = "\n構建失敗!"
			}
		}
		aborted {
			script{
				println("aborted:只有取消構建才會執行")
				currentBuild.description = "\n構建取消!"
			}
		}
	}
}

其中修改的地方是:

// 獲取分支
tools.PrintMes("獲取分支名","green")
if ("${runOpts}" == "GiteePush"){
    branchName = branch - "refs/heads/"
}

tools.PrintMes(branchName, "blue")

在拉取代碼之前進行判斷,對分支進行重新定義。


然后修改test分支下的代碼,重新提交查看jenkins的日志。
image.png
能夠成功得到分支名,並且拉取的代碼也是test分支代碼了。


這時候我們就可以把最開始定義的分支去掉了,因為它並不會起什么作用了。
image.png

五、增加構建描述信息

這個描述信息都可以通過[currentBuild](http://jenkins.coolops.cn/job/java-maven-test/pipeline-syntax/globals#currentBuild).description獲取。
更多信息可以在流水線中的全局變量中獲取。
image.png


那么對於自動觸發流水線我們需要一些什么信息呢?我這里只列舉幾個

  • 提交者
  • 分支名


提交者我們依然可以從日志中獲取,如下:
image.png


然后我們修改流水線配置,增加解析username步驟,如下
image.png
然后修改Jenkinsfile,如下:

//String workspace "/opt/jenkins/workspace"
// 配置共享庫
@Library('myLib')

// 引用共享庫中的方法
def tools = new org.devops.tools()
def build = new org.devops.build()
def deploy = new org.devops.deploy()

// 定義變量
String buildType = env.buildType
String buildShell = env.buildShell
String deployHosts = env.deployHosts

String branchName = "${env.branchName}"
String srcUrl = "${env.srcUrl}"

// 獲取分支

if ("${runOpts}" == "GiteePush"){
	branchName = branch - "refs/heads/"
	currentBuild.description = "構建者${userName} 分支${branchName}"
}

// Pipeline
pipeline {
	// 指定在哪個節點上執行pipeline
	agent any
	

	// 獲取自動安裝或者手動安裝的環境變量
	//tools {
	//	maven "M2"
	//}


	// 指定運行的選項(可選)
	options {
		timestamps()	// 日志會有時間
		skipDefaultCheckout()	// 刪除隱式checkout scm語句
		disableConcurrentBuilds()	//禁止並行
		timeout(time:1,unit:'HOURS') //設置流水線超時時間
	}

	// 構建階段
	stages {
		// 下載代碼
		stage("GetCode"){
			// 步驟
			steps{
				// 設置步驟超時時間
				timeout(time:5,unit:'MINUTES'){
					script{

						tools.PrintMes(branchName, "blue")

						// println("獲取代碼")
						tools.PrintMes("獲取代碼",'red')
            checkout([$class: 'GitSCM', branches: [[name: "${branchName}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitee', url: "${srcUrl}"]]])
					}
				}
			}
		}
		stage("Build"){
			steps{
				timeout(time:20,unit:'MINUTES'){
					script{
						// println("代碼打包")
						tools.PrintMes("代碼打包",'blue')
						build.Build(buildType,buildShell)
					}
				}
			}
		}
		stage("CodeScanner"){
			steps{
				timeout(time:30,unit:'MINUTES'){
					script{
						// println("代碼掃描")
						tools.PrintMes("代碼掃描",'green')
					}
				}
			}
		}
	}

	// 構建后的操作
	post {
		always {
			script{
				println("always:不論構建成功與否都會執行")
			}
		}
		success {
			script{
				println("success:只有構建成功才會執行")
				currentBuild.description += "\n構建成功!"
				// deploy.AnsibleDeploy("${deployHosts}","-m ping")
			}
		}
		failure {
			script{
				println("failure:只有構建失敗才會執行")
				currentBuild.description += "\n構建失敗!"
			}
		}
		aborted {
			script{
				println("aborted:只有取消構建才會執行")
				currentBuild.description += "\n構建取消!"
			}
		}
	}
}

然后我們提交以下代碼,測試效果如下:
image.png

六、優化push操作

到目前為止,基本的流水線功能已經跑起來了,但是還有一些問題,比如我們在碼雲上創建新的一條流水線,依然會觸發Jenkins,因為我們創建流水線是一個push操作,觸發器就默認的認為我們已經做了操作,就需要執行流水線了。但是很多情況我們並不需要其去執行流水線,所以我們要對其做一些過濾。


我們可以先新建一個分支,然后到Jenkins上去看看輸出情況(注意觀察before和after字段)。
(1)、新建分支
image.png
(2)、刪除分支
image.png
(3)、普通提交(為了更好的做對比)
image.png
有沒有發現很有意思的一點?當我們新建分支的時候before是"00000000",當我們刪除分支的時候也是"00000000",這樣我們就只要過濾掉before或after都是0的push請求即可。


其實在Generic Webhook的示例代碼中也有說明,不過是用的gitlab示例。可以去研究研究,我這里也是仿照其寫法來的。


首先我們定義幾個變量,如下圖所示:
image.png
image.png
image.png
然后定義正則表達式
image.png


然后我們測試新建分支,刪除分支就不會觸發jenkins了,正常commit可以正常觸發。

七、配置郵件通知

Jenkins在做構建的時候有時候會成功,有時候會失敗。但是對於操作者來說,我不想每次都登錄Jenkins去查看結果,或者說操作者根本就沒權限登錄Jenkins查看結果,這時候我們要通知操作構建結果怎么辦呢?我們可以配置郵件、釘釘等通知,只需要將構建結構發給操作者即可。下面我們以郵件通知來實驗。

7.1、添加插件

這次用的插件是Email Extension Template
image.png
選擇插件安裝即可。

7.2、配置郵件服務器

系統管理--->系統設置
(1)、設置管理員郵箱地址
image.png
(2)、設置發件人信息

前提:到自己的郵箱服務器去申請授權碼

image.png

7.3、添加shareLibrary

package org.devops

//定義郵件內容
def SendEmail(status,emailUser){
    emailext body: """
            <!DOCTYPE html> 
            <html> 
            <head> 
            <meta charset="UTF-8"> 
            </head> 
            <body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0"> 
                <table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">   
                <tr>
		            本郵件由系統自動發出,無需回復!<br/>
		            各位同事,大家好,以下為${JOB_NAME}項目構建信息</br>
		            <td><font color="#CC0000">構建結果 - ${status}</font></td>
		        </tr>

                    <tr> 
                        <td><br /> 
                            <b><font color="#0B610B">構建信息</font></b> 
                        </td> 
                    </tr> 
                    <tr> 
                        <td> 
                            <ul> 
                                <li>項目名稱:${JOB_NAME}</li>         
                                <li>構建編號:${BUILD_ID}</li> 
                                <li>構建狀態: ${status} </li>                         
                                <li>項目地址:<a href="${BUILD_URL}">${BUILD_URL}</a></li>    
                                <li>構建日志:<a href="${BUILD_URL}console">${BUILD_URL}console</a></li>   
                            </ul> 
                        </td> 
                    </tr> 
                    <tr>  
                </table> 
            </body> 
            </html>  """,
            subject: "Jenkins-${JOB_NAME}項目構建信息 ",
            to: emailUser       
}

7.4、修改Jenkinsfile

修改后如下:

//String workspace "/opt/jenkins/workspace"
// 配置共享庫
@Library('myLib')

// 引用共享庫中的方法
def tools = new org.devops.tools()
def build = new org.devops.build()
def deploy = new org.devops.deploy()
def sendEmail = new org.devops.sendEmail()
def runOpts

// 定義變量
String buildType = env.buildType
String buildShell = env.buildShell
String deployHosts = env.deployHosts

String branchName = "${env.branchName}"
String srcUrl = "${env.srcUrl}"


// 獲取分支

if ("${runOpts}" == "GiteePush"){
	branchName = branch - "refs/heads/"
	currentBuild.description = "構建者${userName} 分支${branchName}"
}else{
	currentBuild.description = "構建者${env.BUILD_USER_ID} 分支${branchName}"
}


// Pipeline
pipeline {
	// 指定在哪個節點上執行pipeline
	agent any
	

	// 獲取自動安裝或者手動安裝的環境變量
	//tools {
	//	maven "M2"
	//}


	// 指定運行的選項(可選)
	options {
		timestamps()	// 日志會有時間
		skipDefaultCheckout()	// 刪除隱式checkout scm語句
		disableConcurrentBuilds()	//禁止並行
		timeout(time:1,unit:'HOURS') //設置流水線超時時間
	}

	// 構建階段
	stages {
		// 下載代碼
		stage("GetCode"){
			// 步驟
			steps{
				// 設置步驟超時時間
				timeout(time:5,unit:'MINUTES'){
					script{

						tools.PrintMes(branchName, "blue")

						// println("獲取代碼")
						tools.PrintMes("獲取代碼",'red')
            checkout([$class: 'GitSCM', branches: [[name: "${branchName}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitee', url: "${srcUrl}"]]])
					}
				}
			}
		}
		stage("Build"){
			steps{
				timeout(time:20,unit:'MINUTES'){
					script{
						// println("代碼打包")
						tools.PrintMes("代碼打包",'blue')
						build.Build(buildType,buildShell)
					}
				}
			}
		}
		stage("CodeScanner"){
			steps{
				timeout(time:30,unit:'MINUTES'){
					script{
						// println("代碼掃描")
						tools.PrintMes("代碼掃描",'green')
					}
				}
			}
		}
	}

	// 構建后的操作
	post {
		always {
			script{
				println("always:不論構建成功與否都會執行")
			}
		}
		success {
			script{
				println("success:只有構建成功才會執行")
				currentBuild.description += "\n構建成功!"
				// deploy.AnsibleDeploy("${deployHosts}","-m ping")
				sendEmail.SendEmail("構建成功",toEmailUser)
			}
		}
		failure {
			script{
				println("failure:只有構建失敗才會執行")
				currentBuild.description += "\n構建失敗!"
				sendEmail.SendEmail("構建失敗",toEmailUser)
			}
		}
		aborted {
			script{
				println("aborted:只有取消構建才會執行")
				currentBuild.description += "\n構建取消!"
				sendEmail.SendEmail("取消構建",toEmailUser)
			}
		}
	}
}

7.5、修改Jenkins項目

我們要在Jenkins項目中添加一個變量來獲取構建者的郵箱。
image.png

7.6、執行測試

上面步驟都完成以后,修改項目並提交進行測試,看郵件是否能夠成功發出。如果是下面就表示郵件發送是OK了。
image.png


免責聲明!

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



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