Jenkins: get environment variables in the body of a global function

て烟熏妆下的殇ゞ 提交于 2021-01-21 05:33:46

问题


I have a shared global function on PublishGitHub.groovy looks like this:

#!/usr/bin/env groovy
def call(body)
{
    def config = [:]
    body.resolveStrategy = Closure.DELEGATE_FIRST
    body.delegate = config

    echo "\u001B[32mINFO: Publishing...\u001B[m"
    body()
    echo "\u001B[32mINFO: End Publish...\u001B[m"      
}

And a code on my JenkinsFile:

environment {
    VERSION = "v1.3.${env.BUILD_NUMBER}"
}
stages {
    stage ('Publish WebAPI'){
        steps{
            echo "\u001B[32mINFO: Start Publish...\u001B[m"

            PublishGitHub{
                echo "This is a body with version: ${env.VERSION}"
            }               
        }
    }
}

And this is my output:

[Pipeline] echo
INFO: Start Publish...
[Pipeline] echo
INFO: Publishing...
[Pipeline] }

And follow next error:

java.lang.NullPointerException: Cannot get property 'VERSION' on null object

Because inside the body I do not have access to the environment variables?


回答1:


Your shared library code runs outside of the workflow CPS context, that is why closure you pass to the vars script does not recognize env property. You can fix this problem by passing a reference to the workflow script. If you call your function like this

PublishGitHub(this) {
    echo "This is a body with version: ${env.VERSION}"
}

and you apply a small modification to vars/PublishGitHub.groovy script like:

#!/usr/bin/env groovy

def call(config, body) {
    body.resolveStrategy = Closure.DELEGATE_FIRST
    body.delegate = config

    echo "\u001B[32mINFO: Publishing...\u001B[m"
    body()
    echo "\u001B[32mINFO: End Publish...\u001B[m"
}

then you will run your pipeline successfully:

[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Publish WebAPI)
[Pipeline] echo
[32mINFO: Start Publish...[m
[Pipeline] echo
[32mINFO: Publishing...[m
[Pipeline] echo
This is a body with version: v1.3.537
[Pipeline] echo
[32mINFO: End Publish...[m
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

If you want to limit the scope for the shared library, you can always simply pass env instead of this and change vars/PublishGitHub.groovy to something like this:

#!/usr/bin/env groovy

def call(env, body) {
    def config = [
            env: env
    ]
    body.resolveStrategy = Closure.DELEGATE_FIRST
    body.delegate = config

    echo "\u001B[32mINFO: Publishing...\u001B[m"
    body()
    echo "\u001B[32mINFO: End Publish...\u001B[m"
}

In this scenario you give your shared library an access to environment variables only.




回答2:


In order to make the environment variables that you have defined in your Jenkinsfile available in your shared library code you have to pass a this parameter on the call to your shared library method.

For example (below is a partial extract only of a full pipeline file):

// JENKINS-42730
@Library('pipeline-shared-library')_
import org.blah.MySharedLibraryClass
// END JENKINS_42730

pipeline {
     agent { any }

     environment {
         FOO = (new MySharedLibraryClass(config, this)).myMethod("StringVar1", "StringVar2")

     }
}

My Shared Library:

package org.blah

import groovy.text.SimpleTemplateEngine

public class MySharedLibraryClass implements Serializable {
    def engine = new SimpleTemplateEngine()
    def config
    def steps

    def ArtifactoryHelper(config, steps) {
        this.config = config
        this.steps = steps
    }

    def log(msg){
        //Allows me to print to Jenkins console
        steps.println(msg)
    }

    def myMethod(var1, var2) {
        ....
    }

The this parameter I referred to above maps to steps in the shared library code. You should then be able to resolve "VERSION=${steps.env.VERSION}" in your shared library code.

Also see this post.

Notes:

  1. pipeline-shared-library is the ID I gave the library in Manage Jenkins > Configure System



回答3:


Szymon's answer works. I added "p.env = env"

def toParam(final Closure body) {
  final def p = [:]
  p.env = env
  body.resolveStrategy = Closure.DELEGATE_FIRST
  body.delegate = p
  body()
  return p
}


来源:https://stackoverflow.com/questions/52043397/jenkins-get-environment-variables-in-the-body-of-a-global-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!