Search code examples
jenkinsgroovy

Jenkins - how to use property defined in a groovy file loaded by Jenkinsfile


Because we have several pipelines that have similar logic and need some common properties, we created a groovy file and put some common methods properties in it. But we found the properties defined in the groovy file can't be accessed.

Here is our groovy file: common.groovy:

def MyProp="value"

def myMethod() {
  //Fail here
  println MyProp
}

return this

JenkinsFile:

node('test') {
  checkout scm

  def jenkinsCommon = load "common.groovy"

  jenkinsCommon.myMethod()
  // Below also fail
  println jenkinsCommon.MyProp
}

We got the following exception when running jobs with this Jenkinsfile:

groovy.lang.MissingPropertyException: No such property: MyProp for class: groovy.lang.Binding
    at groovy.lang.Binding.getVariable(Binding.java:63)
    at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:242)
    at org.kohsuke.groovy.sandbox.impl.Checker$6.call(Checker.java:288)
    at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:292)
    at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.getProperty(SandboxInvoker.java:29)
    at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:20)
    at Script1.myMethod(Script1.groovy:4)
    at WorkflowScript.run(WorkflowScript:33)
    at ___cps.transform___(Native Method)
    at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.get(PropertyishBlock.java:74)
    at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30)
    at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.fixName(PropertyishBlock.java:66)
    at sun.reflect.GeneratedMethodAccessor286.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

How to define and use the property in a groovy file loaded by pipeline?


Solution

  • If you want to use a variable defined outside the method then you have to annotate it with @Field annotation, e.g.

    import groovy.transform.Field
    
    @Field
    def myProp="value"
    
    def myMethod() {
      println myProp
    }
    

    Every Groovy script gets compiled to a class that extends groovy.lang.Script class and each method defined in a script is compiled as a class level method, while the rest of script body is executed inside Script.run() method.

    It means that when your myMethod tries to access myProp it fails, because myProp is compiled as a local variable available inside Script.run() method. This @Field annotation promotes given variable to a class level variable, so it can be accessed from any method defined in the script.