创建可重用的詹金斯管道脚本
Create resusable jenkins pipeline script
我最近正在考虑使用 Jenkins 管道脚本,一个问题是我没有想出一个聪明的方法来创建内部可重用的 utils 代码,想象一下,我有一个通用函数 helloworld
被很多管道作业使用,所以我希望创建一个 utils.jar
可以将它注入到作业类路径中。
我注意到 Jenkins 与 global library 有相似的概念,但我对这个插件的担忧:
因为它是一个插件,所以我们需要通过 jenkins 插件管理器 install/upgrade 它,然后它可能需要重新启动才能应用更改,这不是我想看到的,因为 utils 可能会更改,添加总是,我们希望它能立即可用。
其次,它是jenkins官方共享库,我不想(或者他们不会申请我们)将私有代码放入jenkins repo。
有什么好主意吗?
Shared Libraries (docs) 允许您使您的 代码可供所有管道脚本访问。您不必为此构建插件,也不必重新启动 Jenkins。
例如这是 my library and this a Jenkinsfile 调用了这个公共函数。
编辑(2017 年 2 月):
库可以通过 Jenkins 的内部 Git 服务器访问,或者通过其他方式(例如通过 Chef)部署到 jenkins[=36 中的 workflow-lib/
目录=] 用户的主目录。(仍然可以,但非常不方便)。
全局库可以通过以下方式配置:
Jenkinsfile
中的 @Library('github.com/...')
注释指向共享库存储库的 URL。
- 在 Jenkins 作业的文件夹级别配置。
- 在 Jenkins 配置中配置为全局库,优点是代码 受信任,即不受脚本安全性约束。
第一个和最后一个方法的混合将是一个未显式加载的共享库,然后仅使用其在 Jenkinsfile
中的名称进行请求:@Library('mysharedlib')
.
这是我们目前使用的解决方案,以便重新使用 Jenkinsfile 代码:
node {
curl_cmd = "curl -H 'Accept: application/vnd.github.v3.raw' -H 'Authorization: token ${env.GITHUB_TOKEN}' https://raw.githubusercontent.com/example/foobar/master/shared/Jenkinsfile > Jenkinsfile.t
sh "${curl_cmd}"
load 'Jenkinsfile.tmp'
}
我可能有点丑,但它确实可以工作,除此之外,它还允许我们在共享代码之前或之后插入一些特定于存储库的代码。
根据您计划重用代码的频率,您还可以加载一个函数(或一组函数)作为另一个管道的一部分。
{
// ...your pipeline code...
git 'http://urlToYourGit/projectContainingYourScript'
pipeline = load 'global-functions.groovy'
pipeline.helloworld() // Call one of your defined function
// ...some other pipeline code...
}
与 StephenKing 的解决方案相比,这个解决方案可能看起来有点麻烦,但我喜欢这个解决方案的原因是我的全局函数都致力于 Git,任何人都可以在(几乎)不知情的情况下轻松修改它们Jenkins,只是 Groovy.
的基础知识
在您正在 load
ing 的 Groovy 脚本中,确保在最后添加 return this
。这将允许您稍后拨打电话。否则当你设置 pipeline = load global-functions.groovy
时,变量将被设置为 null
.
我更喜欢创建一个从存储库调用的 buildRepo()
方法。它的签名是def call(givenConfig = [:])
,所以它也可以带参数调用,比如:
buildRepo([
"npm": [
"cypress": false
]
])
我将参数保持在绝对最低限度,并尽量依赖约定而不是配置。
我提供了一个默认配置,这也是我放置文档的地方:
def defaultConfig = [
/**
* The Jenkins node, or label, that will be allocated for this build.
*/
"jenkinsNode": "BUILD",
/**
* All config specific to NPM repo type.
*/
"npm": [
/**
* Whether or not to run Cypress tests, if there are any.
*/
"cypress": true
]
]
def effectiveConfig merge(defaultConfig, givenConfig)
println "Configuration is documented here: https://whereverYouHos/getConfig.groovy"
println "Default config: " + defaultConfig
println "Given config: " + givenConfig
println "Effective config: " + effectiveConfig
使用有效的配置和存储库的内容,我创建了一个构建计划。
...
derivedBuildPlan.npm.cypress = effectiveConfig.npm.cypress && packageJSON.devDependencies.cypress
...
构建计划是一些构建方法的输入:
node(buildPlan.jenkinsNode) {
stage("Install") {
sh "npm install"
}
stage("Build") {
sh "npm run build"
}
if (buildPlan.npm.tslint) {
stage("TSlint") {
sh "npm run tslint"
}
}
if (buildPlan.npm.eslint) {
stage("ESlint") {
sh "npm run eslint"
}
}
if (buildPlan.npm.cypress) {
stage("Cypress") {
sh "npm run e2e:cypress"
}
}
}
我在 Jenkins.io 上写了一篇关于此的博客 post:
https://www.jenkins.io/blog/2020/10/21/a-sustainable-pattern-with-shared-library/
我最近正在考虑使用 Jenkins 管道脚本,一个问题是我没有想出一个聪明的方法来创建内部可重用的 utils 代码,想象一下,我有一个通用函数 helloworld
被很多管道作业使用,所以我希望创建一个 utils.jar
可以将它注入到作业类路径中。
我注意到 Jenkins 与 global library 有相似的概念,但我对这个插件的担忧:
因为它是一个插件,所以我们需要通过 jenkins 插件管理器 install/upgrade 它,然后它可能需要重新启动才能应用更改,这不是我想看到的,因为 utils 可能会更改,添加总是,我们希望它能立即可用。
其次,它是jenkins官方共享库,我不想(或者他们不会申请我们)将私有代码放入jenkins repo。
有什么好主意吗?
Shared Libraries (docs) 允许您使您的 代码可供所有管道脚本访问。您不必为此构建插件,也不必重新启动 Jenkins。
例如这是 my library and this a Jenkinsfile 调用了这个公共函数。
编辑(2017 年 2 月):
库可以通过 Jenkins 的内部 Git 服务器访问,或者通过其他方式(例如通过 Chef)部署到 jenkins[=36 中的 (仍然可以,但非常不方便)。workflow-lib/
目录=] 用户的主目录。
全局库可以通过以下方式配置:
Jenkinsfile
中的@Library('github.com/...')
注释指向共享库存储库的 URL。- 在 Jenkins 作业的文件夹级别配置。
- 在 Jenkins 配置中配置为全局库,优点是代码 受信任,即不受脚本安全性约束。
第一个和最后一个方法的混合将是一个未显式加载的共享库,然后仅使用其在 Jenkinsfile
中的名称进行请求:@Library('mysharedlib')
.
这是我们目前使用的解决方案,以便重新使用 Jenkinsfile 代码:
node {
curl_cmd = "curl -H 'Accept: application/vnd.github.v3.raw' -H 'Authorization: token ${env.GITHUB_TOKEN}' https://raw.githubusercontent.com/example/foobar/master/shared/Jenkinsfile > Jenkinsfile.t
sh "${curl_cmd}"
load 'Jenkinsfile.tmp'
}
我可能有点丑,但它确实可以工作,除此之外,它还允许我们在共享代码之前或之后插入一些特定于存储库的代码。
根据您计划重用代码的频率,您还可以加载一个函数(或一组函数)作为另一个管道的一部分。
{
// ...your pipeline code...
git 'http://urlToYourGit/projectContainingYourScript'
pipeline = load 'global-functions.groovy'
pipeline.helloworld() // Call one of your defined function
// ...some other pipeline code...
}
与 StephenKing 的解决方案相比,这个解决方案可能看起来有点麻烦,但我喜欢这个解决方案的原因是我的全局函数都致力于 Git,任何人都可以在(几乎)不知情的情况下轻松修改它们Jenkins,只是 Groovy.
的基础知识在您正在 load
ing 的 Groovy 脚本中,确保在最后添加 return this
。这将允许您稍后拨打电话。否则当你设置 pipeline = load global-functions.groovy
时,变量将被设置为 null
.
我更喜欢创建一个从存储库调用的 buildRepo()
方法。它的签名是def call(givenConfig = [:])
,所以它也可以带参数调用,比如:
buildRepo([
"npm": [
"cypress": false
]
])
我将参数保持在绝对最低限度,并尽量依赖约定而不是配置。
我提供了一个默认配置,这也是我放置文档的地方:
def defaultConfig = [
/**
* The Jenkins node, or label, that will be allocated for this build.
*/
"jenkinsNode": "BUILD",
/**
* All config specific to NPM repo type.
*/
"npm": [
/**
* Whether or not to run Cypress tests, if there are any.
*/
"cypress": true
]
]
def effectiveConfig merge(defaultConfig, givenConfig)
println "Configuration is documented here: https://whereverYouHos/getConfig.groovy"
println "Default config: " + defaultConfig
println "Given config: " + givenConfig
println "Effective config: " + effectiveConfig
使用有效的配置和存储库的内容,我创建了一个构建计划。
...
derivedBuildPlan.npm.cypress = effectiveConfig.npm.cypress && packageJSON.devDependencies.cypress
...
构建计划是一些构建方法的输入:
node(buildPlan.jenkinsNode) {
stage("Install") {
sh "npm install"
}
stage("Build") {
sh "npm run build"
}
if (buildPlan.npm.tslint) {
stage("TSlint") {
sh "npm run tslint"
}
}
if (buildPlan.npm.eslint) {
stage("ESlint") {
sh "npm run eslint"
}
}
if (buildPlan.npm.cypress) {
stage("Cypress") {
sh "npm run e2e:cypress"
}
}
}
我在 Jenkins.io 上写了一篇关于此的博客 post: https://www.jenkins.io/blog/2020/10/21/a-sustainable-pattern-with-shared-library/