3

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?

Scrambler
  • 33
  • 1
  • 4
  • I'm confused...where is the "env" defined? I see "environment" but not "env"? – AndrewG Aug 27 '18 at 16:27
  • 2
    In Jenkins the environment variables can be accessed using. Env. or directly the name, in this case does not modify the result – Scrambler Aug 27 '18 at 16:30

3 Answers3

5

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.

Szymon Stepniak
  • 40,216
  • 10
  • 104
  • 131
1

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
Andrew Gray
  • 3,593
  • 3
  • 35
  • 62
1

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
}
Quirino Gervacio
  • 1,240
  • 9
  • 9