Reputation: 3187
I have a simple pipeline script that access a groovy class (which resides in a shared library), the pipeline script pass a reference (to itself) to the class, the class then calls a function or a closure found in the script, that function access a member in that same script,
the result is a groovy.lang.MissingPropertyException exception.
so here is the actual (runnable) code:
Jenkins pipeline script:
@Library("testLib") _
import my.domain.Tester;
public Tester tester = new Tester(this);
def closure()
{
echo "tester: " + tester;
}
node("master")
{
tester.test();
}
com.domain.Tester.groovy class:
package my.domain
class Tester
{
Script scriptRef = null;
public Tester(Script scriptRef)
{
this.scriptRef = scriptRef;
}
public void test()
{
this.scriptRef.closure();
}
}
the exception received:
groovy.lang.MissingPropertyException: No such property: tester for class: WorkflowScript
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:53)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:458)
at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.getProperty(DefaultInvoker.java:39)
at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:20)
at WorkflowScript.closure(WorkflowScript:9)
at my.domain.Tester.test(Tester.groovy:8)
at WorkflowScript.run(WorkflowScript:23)
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.GeneratedMethodAccessor538.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
at com.cloudbees.groovy.cps.Next.step(Next.java:83)
at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174)
at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:129)
at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:268)
at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:186)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:370)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$200(CpsThreadGroup.java:93)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:282)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:270)
at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:67)
at java.util.concurrent.FutureTask.run(Unknown Source)
at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:131)
at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59)
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Finished: FAILURE
so obviously it is something happening due to the cps transform procedure the pipeline script goes through, and the script member is not there anymore (not by name and not at scope [probably]),
Upvotes: 0
Views: 2178
Reputation: 3187
based on daggett solution in the remarks:
and since it is just a groovy class then the groovy scoping rules should apply, in groovy if you declare a var / 'def' you can do it without the 'def' prefix and that would declare it globally available everywhere in the script,
so change the declaration in the pipeline script to this:
tester = new Tester(this)
and that's it!
Jenkins pipeline script:
@Library("testLib") _
import my.domain.Tester;
// note the definition without the 'def' or Tester or public
tester = new Tester(this);
def closure()
{
echo "tester: " + tester;
}
node("master")
{
tester.test();
}
OR:
since Groovy version 1.8 and up, we can add the @Field annotation and keep the declaration as it is,
how-do-i-create-and-access-the-global-variables-in-groovy
so we can also change the pipeline to look like this:
Jenkins pipeline script:
@Library("testLib") _
import my.domain.Tester;
// note the definition without the 'def' or Tester or public
@Field Tester tester = new Tester(this);
def closure()
{
echo "tester: " + tester;
}
node("master")
{
tester.test();
}
Upvotes: 0