Jenkins:从全局函数设置环境变量

时间:2018-02-07 15:23:29

标签: jenkins jenkins-pipeline

我有一个多分支管道项目,在SCM中有一个脚本化的Jenkins文件。我想从共享的全局函数中设置管道中的环境变量。我的共享全局函数如下所示:

#!/usr/bin/groovy

def call(String envName = 'staging') {

  def json = libraryResource 'env-config.yaml'
  def config = readYaml text: json
  def envObj = config.environments.find{it.name == envName}
  environment {
    PROJECT = ${envObj.project}
    ARTIFACTS_REPOSITORY = ${envObj.artifacts_repository}
    DOCKER_REGISTRY_PREFIX = ${envObj.docker_registry_prefix}
  }
  println "${envObj}"
}

但在我的Jenkins文件中,我没有看到这些设置:

timestamps {
  withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'xxx', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']]) {
    node('klm') {
      try {
        def revisionTag
        loadEnvConfig('staging')
        println "project=${env.PROJECT}, repo=${env.ARTIFACTS_REPOSITORY}"
        ...

env.PROJECTenv.ARTIFACTS_REPOSITORY均为空。如果我从函数返回envObj并打印管道中的属性,我可以看到它们。是否可以从我的函数中设置环境变量?

编辑:我刚刚意识到我无法在多分支管道中的Jenkins文件中设置任何环境变量。例如。这两种模式都不起作用

timestamps {
  withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'xxx', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']]) {
    node('klm') {
      try {
        environment {
          FOO = "bar"
        }
        println "project=${env.FOO}"
        ...

timestamps {
  withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'xxx', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']]) {
    node('klm') {
      try {
        withEnv(["FOO=BAR"]) {
        println "project=${env.FOO}"
        ...

1 个答案:

答案 0 :(得分:3)

我不完全确定environment是什么以及为什么它没有让你失败。 PROJECT = ${envObj.project}无效Groovy,因此不会执行块。看起来您正在尝试使用environment directive for declarative pipelines,但是,您使用的是脚本化管道。由于共享库和声明性管道的限制,以下选项仅对脚本管道有效。

在当前代码中,您不会修改任何全局脚本变量或返回要在其他步骤中使用的值,因此它们不会产生任何影响。根据您要向消费者提供的API,您有几种不同的方法。

第一个选项是修改env全局变量:

env.PROJECT = envObj.project
env.ARTIFACTS_REPOSITORY = envObj.artifacts_repository
env.DOCKER_REGISTRY_PREFIX = envObj.docker_registry_prefix

这些将修改脚本中其他位置可用的全局env状态(除非它们被覆盖或删除)。

另一个选择是使用现有的withEnv step编写方法,并允许消费者提供Closure正文。这是我将函数从loadEnvConfig重命名为withEnvConfig的示例:

def call(String envName = 'staging', Closure body) {
  // Previous code... 
  withEnv([
      "PROJECT=${envObj.project}",
      "ARTIFACTS_REPOSITORY=${envObj.artifacts_repository}",
      "DOCKER_REGISTRY_PREFIX=${envObj.docker_registry_prefix}",
  ]) {
    body()
  }
}

Jenkinsfile

withEnvConfig('staging') {
  println "In block project=${env.PROJECT}, repo=${env.ARTIFACTS_REPOSITORY}"
}
println "Out of block project=${env.PROJECT}, repo=${env.ARTIFACTS_REPOSITORY}"

在身体内部,它们被设置为withEnv的值。在街区外,他们被重置。

我更喜欢这种模式来修改全局状态。