0

I'm trying to define custom DSL refer https://www.jenkins.io/doc/book/pipeline/shared-libraries/#defining-custom-steps it seems work if just define simple command in {} but failed when use complicated command

(root)
+- vars
|      +- shareL.groovy
|      +- xxx.groovy
|      +- monitorStep.groovy

shareL.groovy

def install(){
   print "test install"
}

def checkout(){
   print "test checkout"

}

monitorStep.groovy

def call(body) {
    def config = [:]
    body.resolveStrategy = Closure.DELEGATE_FIRST
    body.delegate = config
    // This is where the magic happens - put your pipeline snippets in here, get variables from config.
    script {
        def status
        def failed_cause=''
        try{
            body()
        } catch(e){
            status = 'fail'
            failed_cause = "${e}"
            throw e
        }finally {
            def myDataMap = [:]
            myDataMap['stage'] = STAGE_NAME
            myDataMap['status'] = status
            myDataMap['failed_cause'] = failed_cause
            influxDbPublisher selectedTarget: 'myTest', measurementName: 'myTestTable',customData: myDataMap
        }
    }
}

Jenkinsfile

#!groovy
@Library('myShareLibray@') _

pipeline {
   stages{
       stage('Checkout') {
            steps {
                script {
                    monitorStep{
                        shareL.checkout()
                    }
                }
            }
        }

        stage('Install') {
            steps {
                script {
                    monitorStep{
                        docker.image("node").inside(){
                            shareL.install()
                        }
                    }
                }
            }
        }
   }

}

first stage failed with

java.lang.NullPointerException: Cannot invoke method checkout() on null object 

second stage failed with

java.lang.NullPointerException: Cannot invoke method image() on null object

1 Answers1

0

The problem is that the closure cannot find the name shareL which should be accessible in the closure's delegate, which is in our case the map config. You need to redeclare the map to expose the name shareL and additionally a second name install which must be invokable. The solution is to rewrite the map like this:

def config = [ shareL : [install: { println "Inside the map" }] ]
body.resolveStrategy = Closure.DELEGATE_FIRST
body.delegate = config
body()

Then when you call body() it will find shareL.install() but this will not point to the call() method in the shareL.groovy but to the property in the map.

Catalin
  • 366
  • 2
  • 8
  • thanks, @Catalin I also need use other share library method, so I fixed this problem by passing a reference https://stackoverflow.com/a/52052626 – Grace He Mar 03 '21 at 02:15