zoukankan      html  css  js  c++  java
  • 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 = "
    构建成功!"
    				// deploy.AnsibleDeploy("${deployHosts}","-m ping")
    			}
    		}
    		failure {
    			script{
    				println("failure:只有构建失败才会执行")
    				currentBuild.description = "
    构建失败!"
    			}
    		}
    		aborted {
    			script{
    				println("aborted:只有取消构建才会执行")
    				currentBuild.description = "
    构建取消!"
    			}
    		}
    	}
    }
    

    其中修改的地方是:

    // 获取分支
    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 += "
    构建成功!"
    				// deploy.AnsibleDeploy("${deployHosts}","-m ping")
    			}
    		}
    		failure {
    			script{
    				println("failure:只有构建失败才会执行")
    				currentBuild.description += "
    构建失败!"
    			}
    		}
    		aborted {
    			script{
    				println("aborted:只有取消构建才会执行")
    				currentBuild.description += "
    构建取消!"
    			}
    		}
    	}
    }
    
    

    然后我们提交以下代码,测试效果如下:
    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 += "
    构建成功!"
    				// deploy.AnsibleDeploy("${deployHosts}","-m ping")
    				sendEmail.SendEmail("构建成功",toEmailUser)
    			}
    		}
    		failure {
    			script{
    				println("failure:只有构建失败才会执行")
    				currentBuild.description += "
    构建失败!"
    				sendEmail.SendEmail("构建失败",toEmailUser)
    			}
    		}
    		aborted {
    			script{
    				println("aborted:只有取消构建才会执行")
    				currentBuild.description += "
    构建取消!"
    				sendEmail.SendEmail("取消构建",toEmailUser)
    			}
    		}
    	}
    }
    
    

    7.5、修改Jenkins项目

    我们要在Jenkins项目中添加一个变量来获取构建者的邮箱。
    image.png

    7.6、执行测试

    上面步骤都完成以后,修改项目并提交进行测试,看邮件是否能够成功发出。如果是下面就表示邮件发送是OK了。
    image.png

  • 相关阅读:
    (转)【web前端培训之前后端的配合(中)】继续昨日的故事
    ural(Timus) 1136. Parliament
    scau Josephus Problem
    ACMICPC Live Archive 6204 Poker End Games
    uva 10391 Compound Words
    ACMICPC Live Archive 3222 Joke with Turtles
    uva 10132 File Fragmentation
    uva 270 Lining Up
    【转】各种字符串哈希函数比较
    uva 10905 Children's Game
  • 原文地址:https://www.cnblogs.com/coolops/p/12793385.html
Copyright © 2011-2022 走看看