6

In jenkins declarative pipeline, how can I set the value of an environment variable based on custom groovy/powershell method? For instance, if I have a delcarative pipeline as follows, can I use a shared library method to set this value? Essentially I am trying to use a multibranch Declarative Pipeline jenkins job which has a deploy stage, but I need to ensure that develop branches are deployed to DEV, Release branches are deploying to STG, but using the same pipeline. My thought was to create an environment variable that is set based on a custom method (in perhaps Groovy in shared library), and that method would simply look at the current value for env.BRANCH and simply have a little logic to set the value of the target deploy environment. Here is an example of what I envision

pipeline {
environment {
    DEPLOY_ENV = mapBranchToDeployEnvironment(${BRANCH})
}

And then in my deploy stage I would use this value in two powershell invocations

bat "powershell .\\Deploy-Service -Environment ${DEPLOY_ENV}"

bat "powershell .\\Deploy-ServiceProxy -Environment ${DEPLOY_ENV}"

Otherwise, How are people current solving the problem of using the same pipeline to deploy to different environments while using the variables across many other function invocations? What is the recommended approach from Jenkins on mapping a branch name that triggered the build to an environment (if any) it should be deployed to? Based on my understanding, the Declarative Pipeline allows a pipeline to be "multibranch", which, if the job deploys as well, it needs to map to an deploy environment. How else would a pipeline deploy using multibranch to multiple environments when all the global jenkins pipeline environment variables are the same value for every job /branch execution?

In the above scenario, the pipeline variable 'DEPLOY_ENV' is derived from other environment variables that are set by the job and are available typically at the stage level, but here we are looking to set the value globally so that we can use it across stages

Update: My issue was that I didnt realize how simple it was and instead thought that I had to pass in a stage or script object into a groovy shared library function, when in fact its as simple as creating a shared library, then directly referencing the environment variables in the method. Easy. Thank you.

Judy007
  • 5,484
  • 4
  • 46
  • 68
  • Did you end up solving this? How can you change the values of variables in the `environment` block based on an arbitrary condition? – SSF May 10 '19 at 06:43

3 Answers3

11

I had exactly the same problem, and indeed it is possible to use a shared library method. But there is another solution, more simple if you do not have a shared library set-up yet, that consists in defining a groovy method before the Pipeline statement and then use it inside your pipeline like this :

def getEnvFromBranch(branch) {
  if (branch == 'master') {
    return 'production'
  } else {
    return 'staging'
 }
}

pipeline {
  agent any
  environment {
    targetedEnv = getEnvFromBranch(env.BRANCH_NAME)
  }
  stages {
    stage('Build') {
        steps {
            echo "Building in ${env.targetedEnv}"
        }
    }
 }
}
oderfou
  • 111
  • 1
  • 4
9

You can do exactly what you're suggesting. You should create a jenkins shared library with a var (a new DSL method). These can be called to assign to a pipeline-wide environment variable. You had it basically correct. Here's a Jenkinsfile fragment to assign to an environment variable:

environment {
  DEPLOY_ENV = mapBranchToDeployEnvironment()
}

You don't need to pass the branch to the mapBranchToDeployEnvironment DSL method, since you can access the branch in that method. sample contents of vars/mapBranchToDeployEnvironment.groovy in shared library look like this:

def call() {
  echo "branch is: ${env.BRANCH_NAME}"
  if (env.BRANCH_NAME == 'master') {
    return 'prod'
  } else {
    return 'staging'
  }
}

You probably shouldn't expect this to be a five minute task, but you'll get it. Good luck!

burnettk
  • 13,557
  • 4
  • 51
  • 52
  • I have tried just this, However, the DSL methods require a 'this' passed as a parameter, and that passing of a parameter would likely occur at that exact line that you mentioned above. Can you please provide an example of how the DSL method you have described above would pass the necessary arguments? "If the library needs to access global variables, such as env, those should be explicitly passed into the library classes, or methods" https://jenkins.io/doc/book/pipeline/shared-libraries/ – Judy007 Jul 22 '17 at 21:42
  • If jenkins is telling the truth, that means that the parameter would need to be passed in the snippet you provide above, correct? – Judy007 Jul 22 '17 at 21:43
  • if you're using just a var (https://jenkins.io/doc/book/pipeline/shared-libraries/#defining-global-variables), you don't need to pass `this`. i have found that vars have access to everything that is available in the Jenkinsfile. if you want your var to call into classes or methods you have defined in `src/com/blah/blah.groovy`, then you would need to pass `this` from the var to the class. but don't do that unless you have something more complex; just use a var. :) – burnettk Jul 22 '17 at 21:54
  • Ok, can you provide a very simple example of a var that references env in its logic? There is literally nothing online – Judy007 Jul 22 '17 at 23:30
  • Thank you so much. My mistake: thinking that I HAD to pass in some object from which the method would then find and use its properties. Instead, its literally as simple as creating the method, and using the env variables right from inside the method body, similar to how we woudl use in jenkisnfile. Thank you again. – Judy007 Jul 23 '17 at 01:00
0
stage('Prepare env variables') {
    steps {
        script {
            if (env.BRANCH_NAME == 'master') {
                echo 'Copying project-stg.env file...';
                sh 'cp /opt/project-stg.env .env';
            } else {
                echo 'Copying project-dev.env file...';
                sh 'cp /opt/project-dev.env .env';
            }
        }
    }
}

michal-michalak
  • 827
  • 10
  • 6