本篇介绍实际工作中一个很重要的技巧,那就是多个pipeline项目中如何使用jenkins 共享库中的方法。什么是jenkins共享库,说白了就是一个共享库项目,也就是一个git仓库中的代码。我们知道,公司中jenkins环境,测试环境可能部署一个,生产环境也部署一个。每个jenkins环境中,公司多个部门都在上面创建不同的jenkins job,那么问题就来了。 多个jenkins job, 特别是pipeline job中有很多共性的方法。如果没有一个共享的调用,那么每个不同pipeline代码都需要些这些共性的方法,是不是感觉代码重复呢?

举例一个发送邮件的方法,不管什么pipeline job,一般来说,构建完成,不管成功还是失败,都需要给相关人员发送邮件通知。这个发送邮件通知就是一个公共的方法。我们需要把这个公共方法提取出来,放到一个Jenkins 共享库中去。这样只需要在一台jenkins实例机器上配置了共享库,那么这台jenkins服务器上所有的job 都可以调用发送邮件的代码,这个就很方便,特别公共方法越多,就更好提取到jenkins share lib项目中来。

1.jenkins share lib的官网介绍

https://jenkins.io/doc/book/pipeline/shared-libraries/

如果想认真完整了解如何实现不同类型的share lib的创建方式,那么请认真阅读官网的内容。如果看不懂,那么接下来跟着我做,你也会学会其中一种方法,会用就好。

2.创建一个share lib 的git项目

这里我创建好了这个项目,在我github上,大家可以模仿我创建自己实际项目所需要的share lib项目。

项目地址 https://github.com/Anthonyliu86/anthony-jenkins-sharelib-demo

一般来说share lib项目文件结构如下图

如果你是小白,不用管resources 和src这两个文件夹和子文件夹内容,我这个项目也没有在里面写什么代码。重点在vars这个文件夹,我们习惯把一些功能方法都放这个文件夹下,例如SendEmail.groovy, 一个groovy文件就是一个公共方法。为了简单,我直接写了一个两个整数相加求和的方法来举例这个过程。

这个加法方法很简单,这里需要提一下,不管什么公共方法,这个方法都是def call()开头。如果这个方法很复杂,为了代码阅读效果,你可以在下面定义其他的方法,但是call方法里面,肯定要写调用外层的方法,这里的call就相当于这个公共方法的main方法。记住一个原则,一个公共方法,写一个groovy类文件,这个groovy文件的名称就是这个公共方法的函数名称,在其他pipeline项目中调用这个方法就是直接一行写这个groovy类名称,具体使用看下面内容。

3.Jenkins上配置(管理员操作)

在使用share lib方法之前,我们需要在jenkins服务器上配置share lib。

jenkins管理员登录,点击系统管理-> 系统设置,找到下面图片位置。

点击Add按钮,配置如下,这些配置,其实在上面官网文章都有介绍和截图。

这个名称,需要记下来,待会pipeline代码中引用需要使用这个名称,第二个默认版本,这里填的是master,其实如果你创建jenkins share lib默认肯定有mater分支,如果你们项目还有其他分支,你可以写其他分支,建议默认是master分支。下面就是填写你jenkins share lib git项目信息,然后点击Save.

4.pipeline代码如何引用share lib

在导入包语句下 和pipeline关键字之上 写引用share lib的代码

这里模仿写一个stage 用来调用测试3 加5是不是等于8

完整代码

import hudson.model.*;

@Library('share-lib') _

pipeline{ 
	
	agent any
	stages{
		stage("Hello Pipeline") {
			steps {
			    script {
					println "Hello Pipeline!"
					println env.JOB_NAME
					println env.BUILD_NUMBER
				}
			}
		}
		
		stage("Init paramters in json") {
			steps {
			    script {
					println "read josn input file"
					json_file = INPUT_JSON? INPUT_JSON.trim() : ""
					prop = readJSON file : json_file
					name = prop.NAME? prop.NAME.trim() : ""
					println "Name:" + name
					age = prop.AGE? prop.AGE.trim() : ""
					println "Age:" + age
					phone = prop.PHONE_NUMBER? prop.PHONE_NUMBER.trim() : ""
					println "Phone:" + phone
					address = prop.ADDRESS? prop.ADDRESS.trim() : ""
					println "Address:" + address
					email = prop.EMAIL? prop.EMAIL.trim() : ""
					println "Email:" + email
					gender = prop.GENDER? prop.GENDER.trim() : ""
					println "Gender:" + gender
					is_marry = prop.IS_MARRY? prop.IS_MARRY : false
					println "is_marry:" + is_marry
					is_smoke = prop.SMOKE? prop.SMOKE : false
					println "is_smoke:" + is_smoke
					full_test = prop.FULL_TEST? prop.FULL_TEST : false
				}
			}
		}
		stage("call a method") {
			steps {
			    script {
					println "send the parameter as map type"
					model_call = load env.WORKSPACE + "/groovy/projectA-model.groovy"
					model_call.getUserInfo(name:name, age:age, phone:phone, address:address, email:email, gender:gender, is_marry:is_marry)
				}
			}
		}
		stage("check serive up") {
		    when {
		        expression {
		            return (is_smoke == true || full_test == true)
		        }
		    }
		    steps {
			    script {
					println "SMOKE TEST: check service startup"
				}
			}
		}
        stage("check UI login") {
	        when {
			    expression {
			        return (is_smoke == true || full_test == true)
			    }
			}
		    steps {
			    script {
					println "SMOKE TEST: check UI login success"
				}
			}
		}
		
		stage("Integrate-ModelA") {
	        when {
			    expression {
			        return (is_smoke == false || full_test == true)
			    }
			}
		    steps {
			    script {
					println "Integrate-ModelA"
				}
			}
		}
		
		stage("Integrate-ModelB") {
	        when {
			    expression {
			        return (is_smoke == false || full_test == true)
			    }
			}
		    steps {
			    script {
					println "Integrate-ModelB"
				}
			}
		}
		stage("Test share lib") {
		    steps {
			    script {
					println "Here test jenkins share lib method"
				    result = TwoNumberAdd 3,5
				    println result
				}
			}
		}
	}
	
	post {
	    always {
	        script {
	            println "Do some actins when always need."
	        }
	    }
	    failure {
	        script {
	            println "Do some actins when build failed."
	        }
	    }
        success {
	        script {
	            println "Here we kickoff run job B"
	        }
	    }
	}


}

5.测试运行

根据知识,参数提供一个json文件,然后提交job,看看日志,有没有打印出来8.

 

通过两个数求和的例子,我把pipeline中如何调用share lib项目的公共方法给介绍完了,你把这个求和方法替换成发邮件,或者其他公共方法,这个技巧是很有必要掌握的,可以减少很多pipeline项目的公共方法代码的重复。

关于pipeline的教程 系列,我暂时更新到这里。基本上把入门到实际项目使用的知识和相关技巧都给介绍过了。如果以后没有发现新的技巧更新,这个系列就介绍了。这里顺便说一下pipeline和自动化测试和CI平台的关系。我个人是这么理解的,先有自动化,例如接口自动化,UI自动化,然后我们学习pipeline知识,把原来项目自动化转换成pipeline job自动化,有了pipeline job,加上一个web应用服务,其实我们就可以考虑开发一个CI平台。我简单描述下这个CI平台,这个CI平台有前端页面,让用户输入参数的值,前端提交就给服务器生成一个json文件,然后触发对应jenkins上pipeline job去跑起来。这个CI平台,可以集成UI pipeline的项目,也集成接口pipeline的项目,也集成单元测试pipeline项目,甚至性能pipeline项目。有了这么多集成项目,这个平台就需要开发一些其他的辅助功能,各种报告,和job详情页等。CI平台就需要我们学习web开发技能,才有可能做得起来的。所以,学习pipeline是为了CI平台开发服务的。web服务开发又上升到了一个新的高度,真的是开发工具和开发平台的技能,要求很高。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐