有没有一种方法可以在声明性Jenkinsfile中基于分支设置环境变量?

时间:2019-04-24 20:38:18

标签: jenkins groovy jenkins-pipeline jenkins-groovy

我希望找到一种方法,通过基于分支加载环境变量来删除声明性Jenkins文件中的重复阶段。

目前我有类似的东西

@Library("MySharedLibrary@v1") _

String tagBaseDev = "repo.org/myspace/image:dev"
String tagBaseTest = "repo.org/myspace/image:test"
String tagBaseProd = "repo.org/myspace/image:prod"

pipeline {
  agent none
  stages {
    // Always Run This
    stage ('Maven Build and Unit Tests') {
      agent {label 'docker-slave'}
      steps {
        sharedLibraryBuild mavenGoals:'clean package', additionalProps:['ci.env':'']
        stash 'artifacts'
      }
    }
    // Dev Only
    stage ('Build Dev Docker Image and Push') {
      when {
        branch 'dev'
      }
      agent {label 'docker-slave'}
      steps {
        unstash 'artifacts'
        sharedLibraryDockerImageBuildPush tag:"$tagBaseDev"
      }
    }
    // Test Only
    stage ('Build Test Docker Image and Push') {
      when {
        branch 'test'
      }
      agent {label 'docker-slave'}
      steps {
        unstash 'artifacts'
        sharedLibraryDockerImageBuildPush tag:"$tagBaseTest"
      }
    }
    // Prod Only
    stage ('Build Prod Docker Image and Push') {
      when {
        branch 'prod'
      }
      agent {label 'docker-slave'}
      steps {
        unstash 'artifacts'
        sharedLibraryDockerImageBuildPush tag:"$tagBaseProd"
      }
    }
  }
}

我希望能够将其简化为一个阶段,并基于分支动态加载所需的$tagBaseXXX。这只是一个示例,但我计划有四个或五个变量,每个变量的环境值都不同。

我的想法是创建具有相应值的EnvDevEnvTestEnvProd映射,然后创建EnvMap,这是将分支名称与Environment相关联的Map地图。例如:

def EnvDev = [
  url: "dev.com",
  tag: "dev",
  var: "Dev Var"
]

def EnvProd = [
  url: "prod.com",
  tag: "prod",
  var: "prod Var"
]

def EnvMap = [
  dev: EnvDev,
  prod: EnvProd
]

然后我尝试创建一个类似于以下内容的共享库调用:

def call(String branch, Map envMapping) {
    Map use_me = envMapping.get("${branch}")
    String url = use_me.get("URL")
    echo ("${url}")
}

我们的想法是传递地图,并根据分支拉出相应的环境地图,然后根据需要使用变量。

所以我有这样的东西:

@Library("MySharedLibrary@v1") _

def EnvDev = [
  url: "dev.com",
  tag: "dev",
  var: "Dev Var"
]

def EnvProd = [
  url: "prod.com",
  tag: "prod",
  var: "prod Var"
]

def EnvMap = [
  dev: EnvDev,
  prod: EnvProd
]

pipeline {
  agent {label 'docker-slave'}
  stages {
    stage ('Test Env Vars') {
      steps {
        echo "$env.GIT_BRANCH"
        sharedLibrarySetupEnv branch: "$env.GIT_BRANCH", evnMapping: EnvMap
      }
    }
  }
}

但是出现以下错误:

  

hudson.remoting.ProxyException:groovy.lang.MissingMethodException:方法的无签名:setupEnv.call()适用于参数类型:(java.util.LinkedHashMap)值:[[branch:dev,env_mapping:[dev :[url:dev.com,tag:dev,var:Dev Var],...]]]

     

可能的解决方案:调用(java.lang.String,java.util.Map),wait(),any(),wait(long),main([Ljava.lang.String;),each(groovy.lang) 。闭幕)

是否有更简单的方法来完成我想做的事情?

这是我第一次尝试编写Shared Library函数,所以我猜测这可能只是一些我不熟悉的Groovy语法/概念。

谢谢!

3 个答案:

答案 0 :(得分:2)

您的函数签名为No tests were executed! (Set -DfailIfNoTests=false to ignore this error.) ,但您的调用为def call(String branch, Map envMapping)

更改为branch: xxx, env_mapping:xxx

答案 1 :(得分:0)

您可以使用变量BRANCH_NAME并将其置于如下所示的状态:-

if (env.BRANCH_NAME == master)
{
    //set all the environment variable you need
} else {
    //variable required if the condition doesn't match
}

您可以在条件中使用 REGEX

答案 2 :(得分:0)

问题在于我如何尝试调用共享库功能。我以为我能够引用导致Jenkinsfile /管道将LinkedHashMap传递到共享库的变量名,而不是两个单独的变量。

有两种解决方法:

  1. 让共享库调用方法接受Map<String, Object> parms,并在调用中使用parms.varname引用变量。

共享库:

def call(Map<String, Object> parms) {
    echo "${parms.branch}"
    Map use_this_map = parms.envMapping.get(branch)
}

Jenkinsfile:

setupEnv branch: "$env.GIT_BRANCH", envMapping: EnvMap
  1. 不要在Jenkinsfile中传递变量名,而让Shared Library调用方法接受相应的变量。

共享库:

def call(String branch, Map<String, Map> envMapping) {
    echo "${branch}"
    Map use_this_map = envMapping.get(branch)
}

Jenkinsfile:

setupEnv $env.GIT_BRANCH, EnvMap