当有大量的pipeline项目构建任务,有很多代码是重复的,这时需要提取和复用共同的逻辑。 其实pipeline本质就是一个Groovy脚本,所以可以在pipeline中自定义函数,并使用Groovy语言自带的特性。 比如下面的Jenkinsfile,我们自定义了一个 createVersion 函数,并使用了内置的Date类。
pipeline { agent any stages { stage ('build') { steps { // 输出 201907-4 echo "${createVersion(BUILD_NUMBER)}" } } } } def createVersion(String BUILD_NUMBER) { return new Date().format('yyyyMM') + "-${BUILD_NUMBER}" } 复制代码
还有一种更优雅的写法,将变量定义在environment内
pipeline { agent any environment { _version = createVersion() } stages { stage ('build') { steps { echo "${_version}" } } } } def createVersion() { return new Date().format('yyyyMM') + "-${env.BUILD_NUMBER}" } 复制代码
大致流程:
这里已经建好 jenkins-shared-library ,文件结构如下:
vars 目录下的全局变量可以直接在pipeline中使用,即当写 sayHello('world')
,实际调用的是 sayHello.groovy
中的call函数
src 目录是标准的Java源码结构,目录中的类被称为类库(Library class),而 @Library('global-shared-library@master')
就是一次性静态加载src目录下所有代码到classpath中。
src目录中的类,可以使用Groovy中的@Grab注解,自动下载第三方依赖包
@Library('global-shared-library@master') _ pipeline { agent any environment { _version = createVersion() } stages { stage ('build') { steps { script { def util = new com.mafeifan.Utils() def version = util.createVersion("${BUILD_NUMBER}") echo "${version}" sayHello 'yes' echo "${_version}" } } } } } def createVersion() { return new Date().format('yyyyMM') + "-${env.BUILD_NUMBER}" } 复制代码
查看构建日志,发现Jenkins首先拉取共享库代码,执行成功。
// vars/generatePipeline.groovy
def call(String lang) { if (lang == 'go') { pipeline { agent any stages { stage ('set go path') { steps { echo "GO path is ready" } } } } } else if (lang == 'java') { pipeline { agent any stages { stage ('clean install') { steps { sh "mvn clean install" } } } } } // 其他语言 } 复制代码
使用时,Jenkinsfile 只有两行
@Library['global-shared-library'] _ generatePipeline('go') 复制代码
如果大多数项目都是标准化的,可以利用共享库的pipeline模块技术来降低维护成本。
这里只是抛砖引玉,想写出更强大的共享库需要多了解Groovy。
优先考虑使用自定义函数,如果此函数出现在了至少三个项目中,考虑移到共享库里,当发现项目的pipeline非常相似,考虑使用pipeline模块。