创建可重复使用的jenkins管道脚本

时间:2016-08-01 09:23:44

标签: jenkins jenkins-workflow jenkins-pipeline

我正在考虑最近使用Jenkins管道脚本,一个问题是我没有想出一个聪明的方法来创建内部可重用的utils代码,想象一下,我有一个共同的函数helloworld将被使用通过大量的管道工作,所以我希望创建一个utils.jar可以将它注入到作业类路径中。

我注意到Jenkins与global library有类似的概念,但我对这个插件的关注:

由于它是一个插件,所以我们需要通过jenkins插件管理器安装/升级它,然后它可能需要重新启动来应用更改,这不是我想看到的,因为utils可能会改变,总是添加,我们希望它可以立即使用。

其次,它是官方jenkins共享lib,我不想(或者他们不会申请我们)将私人代码放入jenkins repo。

有什么好主意吗?

4 个答案:

答案 0 :(得分:30)

Shared Librariesdocs)允许您使您的代码可供所有管道脚本访问。您不必为此构建插件,也不必重新启动Jenkins。

E.g。这是调用此常用函数的my librarythis a Jenkinsfile

编辑(2017年2月): 可以通过Jenkins的内部Git服务器访问库,也可以通过其他方式(例如通过Chef)部署到 jenkins 用户主目录中的workflow-lib/目录。(仍然可能,但非常不方便)。

可以通过以下方式配置全局库:

  • @Library('github.com/...')中的Jenkinsfile注释,指向共享库存储库的网址。
  • 在Jenkins作业的文件夹级别配置。
  • 在Jenkins配置中配置为全局库,其优点是代码可信,即不受脚本安全限制。

第一个和最后一个方法的混合将是未显式加载的共享库,然后仅使用Jenkinsfile中的名称@Library('mysharedlib')来请求。

答案 1 :(得分:9)

根据您计划重用代码的频率,您还可以加载一个函数(或一组函数)作为另一个管道的一部分。

{
  // ...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的基础知识。

在Groovy脚本中,您load,请确保在最后添加return this。这将允许您稍后拨打电话。否则,当您设置pipeline = load global-functions.groovy时,该变量将设置为null

答案 2 :(得分:2)

以下是我们目前正在使用的解决方案,以便重用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'

}

我可能有点难看,但它可以实现,除此之外,它还允许我们在共享代码之前或之后插入一些特定于存储库的代码。

答案 3 :(得分:0)

我更喜欢创建一个从存储库调用的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上写了一篇关于此的博客文章: https://www.jenkins.io/blog/2020/10/21/a-sustainable-pattern-with-shared-library/