3

I have a Jenkins shared lib in a repo, usual folder structure:

vars
  utils.groovy

In utils.groovy I have some functions:

void funcA() {}
void funcB() {}

Now I want to define a constant that all functions in that module can use, but when I try this:

String common='hi'
void funcA() {println "A ${common}"}
void funcB() {println "B ${common}"}

I get an exception that common is not a symbol that exists:

groovy.lang.MissingPropertyException: No such property: common for class: utils

For now I'm getting around the issue by doing this hack:

String _getCommon() {
    return 'hi'
}
void funcA() {String common=_getCommon(); println "A ${common}"}
void funcB() {String common=_getCommon(); println "B ${common}"}
Oliver
  • 27,510
  • 9
  • 72
  • 103

2 Answers2

9

Module level variables can be defined via the @Field:

import groovy.transform.Field
@Field var =...
void func() {println var}

Other modules in the same library can reference it too, the usual way. Ex assuming the above was defined in utils.groovy the other.groovy could have:

void func() {println utils.var}

See http://docs.groovy-lang.org/latest/html/gapi/groovy/transform/Field.html.

Oliver
  • 27,510
  • 9
  • 72
  • 103
  • Nice. Access even works from within the Jenkinsfile itself (using `utils.var`). – Ingo Karkat Mar 08 '19 at 14:59
  • Actually with this solution you can't override `utils.var` from within your pipeline. If you want to do that (e.g. for configuration) the solution from Joerg S works – Marcus Held Nov 15 '19 at 10:35
  • @MarcusHeld just define a setter function in the lib. With my solution, you don't need that innerclass that Joerg defines, and the code is a lot simpler. – Oliver Nov 16 '19 at 12:48
  • 1
    I gave it a try but setting the variable from another script didn't work. It ended up to be null, for some reason. – Marcus Held Nov 18 '19 at 13:23
  • OK I'll have another at my code, I'm pretty sure I've done that but maybe not. – Oliver Nov 18 '19 at 13:28
3

Looks like the CPS class loader does not support simple properties. However turns out that you can use something like:

class InnerClass {
    static String myProperty = 'Hi'
}

String setCommon(String value) {
    InnerClass.myProperty = value
}

String getCommon() {
    return InnerClass.myProperty
}

void funcA() {println "A ${common}"}
void funcB() {println "B ${common}"}

Having this you may also access the property from within your Jenkinsfile like:

@Library('cpsLibFoo') _

utils.funcA()
utils.common = 'baz'
utils.funcB()

Output will be:

[Pipeline] echo
A Hi
[Pipeline] echo
B baz
[Pipeline] End of Pipeline
Joerg S
  • 4,730
  • 3
  • 24
  • 43
  • Thanks for posting, I would not have thought of that. But I found a much simpler approach, I have posted. – Oliver Sep 15 '18 at 01:20
  • 1
    CPS doesn't seem to serialize static fields. That means after Jenkins restart if there was any state saved in to that variable - that state will be lost. – Dee Jul 31 '21 at 00:30