Shaybc
Shaybc

Reputation: 3187

Jenkins groovy (SharedLibrary) class can't access WorkflowScript members

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]),

  1. does anyone have a solution / idea / direction ?
  2. does anyone have info on the CPS Transform process (specifically to Jenkins, not the CPS theory), or how can i see the end product WorkflowScript after the transformation ?

Upvotes: 0

Views: 2178

Answers (1)

Shaybc
Shaybc

Reputation: 3187

based on daggett solution in the remarks:

  1. jenkins pipeline scripted job is written in groovy
  2. it is then compiled and CPS transformed (during runrime) into a WorkflowScript groovy class with a single method that is executed

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

Related Questions