1

I'm constructing a Jenkins pipeline to verify the shared-libs (from Gerrit) automatically, by reuse whatever pipelines we have right now.

the original thoughts should be very simple, which :

@Library( 'shared-libs@master' ) _
//                       |
//                       |
//         variable instead of hard code
//                       |
//                       v
@Library( "shared-libs@${refs_params}" ) _

the libraries structure :

(root)
+- src                                # Groovy source files
|   +- org
|       +- jenkins
|           +- FooDefinition.groovy   # for org.jenkins.FooDefinition
|           +- BarDefinition.groovy   # for org.jenkins.BarDefinition
|           +- ...                    # for org.jenkins....
|       +- virtualization
|           +- PodDefinition.groovy   # for org.virtualization.PodDefinition
|           +- ...                    # for org.virtualization....
+- vars
|   +- foo.groovy                     # for global 'foo' variable
|   +- logger.groovy                  # for global 'logger' variable

For regular pipeline, I'm using the groovy shared library (pre-setup in Manage Jenkins -> Configure System -> Global Pipeline Libraries) by:

@Library( 'shared-libs@master' ) _
import org.virtualization.PodDefinition

// generate pod
PodDefinition.runWith( ... ) {
  // pipeline content
}

make sure the refs/changes/x works in Specify ref specs : +refs/changes/*:refs/remotes/@{remote}/changes/*:

// works by using hard code `refs/changes/x/x/123`
@Library( 'shared-libs@refs/changes/x/x/123' ) _
import org.virtualization.PodDefinition

However, when I using GERRIT_REFSPEC, it dosen't work due to WorkflowScript: @Library value ‘shared-libs@$GERRIT_REFSPEC’ was not a constant either way as below:

  • @Library( 'shared-libs@${GERRIT_REFSPEC}' ) _
  • @Library( 'shared-libs@${env.GERRIT_REFSPEC}' ) _
  • @Library( 'shared-libs@${params.GERRIT_REFSPEC}' ) _

So, I've modified the library usage according from the official document Extending with Shared Libraries to library( "shared-libs@${GERRIT_REFSPEC}" ), the libs clone works, but import org.virtualization.PodDefinition failed :

library( "shared-libs@${GERRIT_REFSPEC}" )
// or
this._ = library( "shared-libs@${GERRIT_REFSPEC}" )
// or
this = library( "shared-libs@${GERRIT_REFSPEC}" )
// or
library( "shared-libs@${GERRIT_REFSPEC}" ) _

import org.virtualization.PodDefinition 


// WorkflowScript: 5: unable to resolve class org.virtualization.PodDefinition
//  @ line 3, column 1.
//   import org.virtualization.PodDefinition
//   ^
//
// 1 error

So, I've tried:

  • load path/to/x.grovy
    library( "shared-libs@${GERRIT_REFSPEC}" )
    node( 'built-in' ) {
      load "../${env.JOB_BASE_NAME}@libs/<reivsion>/src/org/jenkins/FooDefinition.groovy"
      load "../${env.JOB_BASE_NAME}@libs/<reivsion>/src/org/jenkins/BarDefinition.groovy"
      load "../${env.JOB_BASE_NAME}@libs/<reivsion>/src/org/virtualization/PodDefinition.groovy"
    }
    
    // --- shows thrid party libs import failure ---
    // org.jenkinsci.plugins.workflow.cps.CpsCompilationErrorsException: startup failed:
    // Script7.groovy: 3: unable to resolve class com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterDefinition
    //  @ line 3, column 1.
    //    import com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterDefinition
    //    ^
    //
    // 1 error
    
  • def x = library() org.x.x ( get hints from Importing class from git - unable to resolve class ) : it will not exact reuse current pipeline any more, and also dozens of groovy file make difficult of naming
    def a = library( "shared-libs@${GERRIT_REFSPEC}" ) org.jenkins.FooDefinition.groovy
    def b = library( "shared-libs@${GERRIT_REFSPEC}" ) org.jenkins.BarDefinition.groovy
    def c = library( "shared-libs@${GERRIT_REFSPEC}" ) org.jenkins.xxx.groovy
    def d = library( "shared-libs@${GERRIT_REFSPEC}" ) org.virtualization.PodDefinition.groovy
    def e = library( "shared-libs@${GERRIT_REFSPEC}" ) org.virtualization.xxx.groovy
    
  • @Grab :
    library( "shared-libs@${GERRIT_REFSPEC}" )
    
    @Grab( 'org.virtualization.PodDefinition' )
    @Grab( group='org.virtualization', module='PodDefinition' ) 
    // WorkflowScript: 3: The missing attribute "version" is required in @Grab annotations
    //  @ line 3, column 1.
    //    @Grab( group='org.virtualization', module='PodType' )
    //    ^
    //
    // 1 error
    
    
    @Grab( group='org.virtualization', module='PodDefinition', version='latset' )
    // org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
    // General error during conversion: Error grabbing Grapes -- [unresolved dependency: org.virtualization#PodDefinition;latest: not found]
    
    
    
    @Grab( group='org.virtualization', module='PodDefinition', version='default' )
    // org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
    // General error during conversion: Error grabbing Grapes -- [unresolved dependency: org.virtualization#PodDefinition;default: not found]
    

So, I don't know what I should do next, either "change" "shared-libs@${GERRIT_REFSPEC}" to constant to use @Library(...) _, or using library(...) to import all libs under src/**

BTW, here the way I've tried to "convert" variable to constant:

Object.metaclass.SHARED_LIBS = "shared-libs@${GERRIT_REFSPEC}"
@Library( SHARED_LIBS ) _

// or
class SHARED_LIBS {
  final String REFSPEC = "shared-libs@${GERRIT_REFSPEC}"
}
@Library( SHARED_LIBS.REFSPEC ) _

// or
import groovy.transform.Field
@Field final String SHARED_LIBS = "shared-libs@${GERRIT_REFSPEC}"
@Library( SHARED_LIBS ) _

// or
def bindings = new Binding()
bindings.setVariable("SHARED_LIBS", "shared-libs@${GERRIT_REFSPEC}")
@Library( SHARED_LIBS ) _


// or
withEnv([ 'SHARED_LIBS=shared-libs@${GERRIT_REFSPEC}' ]) {
  @Library( SHARED_LIBS ) _
}
Marslo
  • 2,994
  • 4
  • 26
  • 35
  • I applaud your effort, but the error message is completely accurate: you must specify a constant for the git retrieval of a shared library. – Matthew Schuchard Aug 31 '22 at 14:39
  • is there any way to "create" a constant in Jenkinsfile ? – Marslo Aug 31 '22 at 14:59
  • Yes you can declare with the `const` keyword within a Groovy scope. You would not be able to use for the shared library retrieval though. – Matthew Schuchard Aug 31 '22 at 16:22
  • To clarify: the `@Library` is used during compilation (Groovy -> CPS -> Java -> bytecode) so it can be used with import keyword, statically checked classes/types, etc. There is a separate `library` DSL step - see https://www.jenkins.io/doc/book/pipeline/shared-libraries/#loading-libraries-dynamically - which has certain limitations and inconveniences, but for some cases works... or so they say (I'm trying to convert some pipelines to that now and it is very puzzling how some things work and others, seemingly same, do not). – Jim Klimov Sep 27 '22 at 16:05
  • See also this explanation : https://stackoverflow.com/a/67784728/4715872 – Jim Klimov Sep 27 '22 at 16:10

1 Answers1

1

You can dynamically load the library at any point of your groovy file and use the full class name to use the function. Maybe this is something that could help you.

def myLib = dsl.library 'my-shared-lib@<SHA>'
myLib.net.vy.a.v1.Sonarqube.call(dsl, parameters)

Here net.vy.a.v1.Sonarqube is the actual package. dsl is an object of Script

Ram
  • 1,154
  • 6
  • 22