Search code examples
jenkinsgroovyjenkins-workflowjenkins-pipeline

Jenkins Build Pipeline fileLoad in library files not working


I'm using the Workflow Remote Loader plugin's fileLoad function to load dependencies for my build script. In my main file, I have the following:

build-app.groovy

def java
def util

node {
    stage "Setup"
    fileLoader.withGit('git@github.com:myorg/build-scripts.git', 'master', '234720asdf8ed1a2', '') {

        java = fileLoader.load('lib/java.groovy');
        util = fileLoader.load('lib/util.groovy');
    }

    util.checkIfFileExists('myFile.txt')
    def version = java.getJarVersion("api")
}

util.checkIfFileExists() works perfectly, but a problem occurs when java.getJarVersion is called. In getJarVersion there is also a dependency on util. My java lib is as follows:

java.groovy

def util = fileLoader.load('lib/util.groovy')

def getJarVersion() {
    ...
    util.checkIfFileExists('myFile.txt')
    ...
}

This gives the following error when I run in Jenkins:

groovy.lang.MissingPropertyException: No such property: util for class: groovy.lang.Binding
    at groovy.lang.Binding.getVariable(Binding.java:62)
    at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:224)
    at org.kohsuke.groovy.sandbox.impl.Checker$4.call(Checker.java:241)
    at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:238)
    at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.getProperty(SandboxInvoker.java:23)
    at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:17)
    at Script4.checkIfFileExists(Script4.groovy:39)
    at Script4.getJarVersion(Script4.groovy:23)
    at WorkflowScript.run(WorkflowScript:18)
    at ___cps.transform___(Native Method)
    at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.get(PropertyishBlock.java:62)
    at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30)
    at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.fixName(PropertyishBlock.java:54)
    at sun.reflect.GeneratedMethodAccessor254.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    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:58)
    at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:154)
    at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:18)
    at org.jenkinsci.plugins.workflow.cps.SandboxContinuable$1.call(SandboxContinuable.java:32)
    at org.jenkinsci.plugins.workflow.cps.SandboxContinuable$1.call(SandboxContinuable.java:29)
    at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:108)
    at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:29)
    at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:164)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:276)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$000(CpsThreadGroup.java:78)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:185)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:183)
    at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:47)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:112)
    at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

The plugin's doc says:

Use static initializers within the Groovy file of the loaded file to load more context from neighbor files.

I've tried static def util = fileLoader.load('lib/util.groovy'), but this produced the same error. I've also tried a variety of other combinations to no avail. Maybe this is some lack of understanding of the groovy language? Not really sure.

Thanks in advance!


Solution

  • OK, after much trial and error, I figured out the issue.

    java.groovy before:

    def util = fileLoader.load('lib/util.groovy')
    
    def getJarVersion() {
        ...
        util.checkIfFileExists('myFile.txt')
        ...
    }
    
    return this;
    

    java.groovy after:

    def getJarVersion() {
        ...
        util.checkIfFileExists('myFile.txt')
        ...
    }
    
    this.util = fileLoader.load('lib/util.groovy')
    return this;
    

    The return this; line was omitted from the original post because it was in the documentation of the remote file loader plugin, but it's key. When java.groovy is loaded from build.groovy it is using the returned this as the scope the calls made to java.groovy. This scope did not include util when it was defined as def util = fileLoader.load('lib/util.groovy'). Adding it to this before returning it put util in scope for all function calls in the file.