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

  • 相关阅读:
    英黑客侵入Zynga系统窃得价值1200万美元筹码 狼人:
    瑞星发布2010企业安全报告 九成国内企业曾被入侵 狼人:
    赛门铁克大中国区总裁吴锡源:云安全是一项系统工程 狼人:
    频遭攻击 索尼无奈关闭多国网站 狼人:
    Pwn2Own黑客大赛首日:Safari、IE8被攻破 狼人:
    疯子的研究:瘫痪整个互联网绝非天方夜谭 狼人:
    Google收购安全分析软件厂商Zynamics 狼人:
    RSA大会:黑客正在觊觎个人用户而非网络 狼人:
    从索尼泄密看云计算安全 狼人:
    RSA公布被攻击内幕:钓鱼邮件惹祸 狼人:
  • 原文地址:https://www.cnblogs.com/coolops/p/12793385.html
Copyright © 2011-2022 走看看