Add Jenkins Shared Libraries with classes reference in a Jenkinsfile dynamically

Hi,

I have constructed a Shared Library in which I want to have class definitions, below is an example of shared lib code.

package apicode
class ApiCode implements Serializable {

    private final Map data
    private final DSL steps

    ApiCode(Map data, DSL steps) {
        this.data = data
        this.steps = steps
    }
}

I have placed this class definition in a shared library git repo, with the path apiCode/src/apicode/apiCode.groovy. I am importing the shared library using the following step at the top of my Jenkins file, outside any node or pipeline directive:

library identifier: 'apiCode@master', retriever: modernSCM(
    scm: [
       $class: 'GitSCMSource', 
        credentialsId: '<my-credentials-id>',
        remote: '<my-git-remote>',
        traits: [gitBranchDiscovery()]
    ],
    libraryPath: 'apiCode/'
)
import apicode.*

When I use the above class from the shared library it’s throwing an exception saying that the class is not found.

Below is my simple Jenkins pipeline file to call the class.

library identifier: 'apiCode@master', retriever: modernSCM(
   scm: [
       $class: 'GitSCMSource', 
        credentialsId: '<My GIT Credentials>',
        remote: '<my shared lib gitbranch>',
        traits: [gitBranchDiscovery()]
    ],
    libraryPath: 'apiCode/'
)
import apicode.*



pipeline {
    agent any
    stages {
        stage("test1") {
            steps {
               script {
                    def data = [:]
                    ApiCode foo = new ApiCode(data, steps)
                }
            }
        }
    }
}

It’s throwing the below error.

WorkflowScript: 18: unable to resolve class ApiCode
 @ line 18, column 29.
               ApiCode foo = new ApiCode(env.data, steps)
                               ^


    at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:309)
    at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:981)
    at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:626)
    at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:575)
    at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:323)
    at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:293)
    at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox$Scope.parse(GroovySandbox.java:163)
    at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.doParse(CpsGroovyShell.java:142)
    at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:127)
    at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:562)
    at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:514)
    at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:336)
    at hudson.model.ResourceController.execute(ResourceController.java:107)
    at hudson.model.Executor.run(Executor.java:449)
Finished: FAILURE

So can anyone please help me how to get this class loaded in my Jenkins job dynamically?

I would suggest starting by following the naming conventions for naming your class, ie it should be Api. I’m not sure of all the conversions made by Groovy behind the scenes but it’s entirely possible that might be the cause for this error.

Thank you for the message @PierreBtz

I actually changed the original name from my actual code to api for reference here and I am sure the naming convention is not the problem here.

I think Jenkins is not able to load the classes from dynamically loaded shared libraries. because of that, I am unable to use the class from the dynamically loaded shared library.

I actually tested the same by adding the global library path under Jenkins configuration and used the below simple code to load the class into my Jenkins and it worked perfectly fine. and the issue is coming only when I am loading it dynamically.

@Library('apiCode')_
import apicode.ApiCode

I just changed my example pretty much similar to my actual code (Just names changed)

For dynamic libraries, please refer to this document, specifically:

However you may use library classes dynamically (without type checking), accessing them by fully-qualified name from the return value of the library step. static methods can be invoked using a Java-like syntax:

library('my-shared-library').com.mycorp.pipeline.Utils.someStaticMethod()

You can also access static fields, and call constructors as if they were static methods named new:

def useSomeLib(helper) { // dynamic: cannot declare as Helper
    helper.prepare()
    return helper.count()
}

def lib = library('my-shared-library').com.mycorp.pipeline // preselect the package

echo useSomeLib(lib.Helper.new(lib.Constants.SOME_TEXT))

Thank you @PierreBtz

I have read the document you have provided and do not understand it properly on how I can integrate it with my example.

Would you mind helping me with an example that I have provided above .?

@PierreBtz

I have used a multi-branch pipeline and used the Pipeline Libraries plugin to achieve this. After configuring this I am able to import the class simply with the import command. :slight_smile:

What did you end up doing?

I have used the below plugin, which will give me an option to implicitly configure the libraries for individual multibranch pipelines. after configuring it I can simply import the class from the shared library with the import command.

Library name: Pipeline: Groovy Libraries
Option Name in the multibranch pipeline to configure implicitly shared libs: Pipeline Libraries (check the Load implicit option) and provide the shared libraries git details.