Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I define a global variable or constant using jenkins pipeline shared library?

While I was able to define methods, defining variables using Jenkins Shared library seems to an unresolved quest so far.

I added /vars/True.groovy with this body

def call() {
    return true
}

And now inside Jenkinsfile, I tried to test if it works as expected:

println "evaluation ${ true == True }"

But surprise, this fails as it considers true != class True. My impression is that true == True() may work but that's not the point, I need a real variable because that whole purpose was to avoid some errors caused by people using wrong case.

So what is the magic trick?

like image 752
sorin Avatar asked Nov 09 '17 15:11

sorin


People also ask

How do you set global variables in Jenkins?

We can set global properties by navigating to “Manage Jenkins -> Configure System -> Global properties option”.

How do you declare a variable in Jenkins pipeline?

Jenkins pipeline environment variables: You can define your environment variables in both — global and per-stage — simultaneously. Globally defined variables can be used in all stages but stage defined variables can only be used within that stage. Environment variables can be defined using NAME = VALUE syntax.

How do I set environment variable in Jenkins pipeline stage?

Setting Stage Level Environment Variable It is by using the env variable directly in the script block. We can define, let us say, USER_GROUP and display it. You will see that the underlying shell also has access to this environment variable. You can also set an environment variable using withEnv block.


3 Answers

It looks like Global Variables defined in the vars directory must be lower/camel/maybe some other special casing. This isn't stated anywhere in on the Defining global variables section, but there is this note at the top:

The vars directory hosts scripts that define global variables accessible from Pipeline. The basename of each *.groovy file should be a Groovy (~ Java) identifier, conventionally camelCased. The matching *.txt, if present, can contain documentation, processed through the system’s configured markup formatter (so may really be HTML, Markdown, etc., though the txt extension is required).

Here is what I tried:

  • vars/MyTrue.groovy

    class MyTrue implements Serializable {
    }
    
  • vars/myTrue.groovy

    class myTrue implements Serializable {
    }
    
  • vars/mytrue.groovy

    class mytrue implements Serializable {
    }
    
  • vars/doesCasingMatter.groovy

    class DoesCasingMatter implements Serializable {
    }
    

And in my pipeline script to test if they are instances or Class types (no script security enabled here):

echo("MyTrue: ${Class.isInstance(MyTrue)}")
echo("myTrue: ${Class.isInstance(myTrue)}")
echo("mytrue: ${Class.isInstance(mytrue)}")
echo("What bindings are there?: ${binding.variables}")

This prints out:

[Pipeline] echo
MyTrue: true
[Pipeline] echo
myTrue: false
[Pipeline] echo
mytrue: false
[Pipeline] echo
What bindings are there?: [steps:org.jenkinsci.plugins.workflow.cps.DSL@e96256, myTrue:myTrue@8a1ddc5, mytrue:mytrue@392ff649]

Which seems to indicate that something about the class name determines how it gets compiled and created. The first example, which is similar to your vars/True.groovy, is only imported as a class and not instantiated. The other two are compiled and instantiated and are bound to the script with their defined class names. I think you will have to define your classes differently if you want them to be global variables.

like image 85
mkobit Avatar answered Oct 12 '22 03:10

mkobit


I've found a way to achieve this, but with a slight caveat: the variables must be defined/wrapped within a class. However, this does have the upside of providing better organization, in order not to pollute the global space too much.

For example, we often reuse four standard "magic strings" for build statuses, which I wanted to save as global constants to facilitate interoperability. So I created a global status class, defined in vars/status.groovy:

class status {
  final String STARTED = "STARTED"
  final String SUCCESS = "SUCCESS"
  final String FAILURE = "FAILURE"
  final String ABORTED = "ABORTED"
}

The constants can then be used by referring to their parent class:

echo status.STARTED
echo status.SUCCESS
echo status.FAILURE
echo status.ABORTED

Specials thanks to @mkobit for pointing me in the right direction!

like image 26
Marco Roy Avatar answered Oct 12 '22 01:10

Marco Roy


Variable True is definitely a variable but it holds a reference to object of type True(that you defined in /vars/True.groovy). You have two options
The good one: Use it this way

println "evaluation ${ true == True() }"

The strange one: You can override equals() method in /vars/True.groovy

public boolean equals(obj) {
    return obj == true;
}

Then this should work

println "evaluation ${ true == True }"

But it would be really strange and can lead to misunderstandings.

like image 1
Vitalii Vitrenko Avatar answered Oct 12 '22 01:10

Vitalii Vitrenko



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!