Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructor not called in Jenkins Shared Libraries

I am trying to develop shared libraries and has the following directory structure

  • src/com/mycomapny
    • MyTest.groovy
  • vars
    • test.groovy
  • Jenkinsfile

my Jenkinsfile calls only method available in the test.groovy with required input. which imports MyTest and creates object and calls constructor and followed by the actual method that executes the functionality available in the MyTest.groovy file

Here the constructor class never called from global vars/test.groovy

I tried calling class and method from groovy it is working fine but when i am calling it from jenkinsfile it is not working. I don't know why i am not able to call constructor and what i am missing.

I have placed @NonCPS on above test.groovy method but still it is not working.

//MyTest.groovy
package com.mycompany

class MyTest implements Serializable {
    public _notification

    MyTest(Closure content) {
        notification = [:]
        content.resolveStrategy = Closure.DELEGATE_FIRST
        content.delegate = notification
        content()
        println("Entered Constructor")
        this._notification = notification
    }

}

//test.groovy
import com.mycopany.MyTest
def notify(Closure content) {
    println("This is line i am getting in the output but nothing after that")
    MyTest tester = new MyTest(content)
    println(tester._notification.colorcode)
} 

//Jenkinsfile
@library("MysharedLibrary@master") _
pipeline{
    stages {
         stage {
             steps {
                 test.notify {
                      buildno = 12
                      jobname = "Mytest"
                      colorcode = "Blue"
                 }
             }
         }
    }
}

here i just want to call constructor from jenkins file and print the value of input value in my vars/test.groovy.

EDIT1: When I use @NonCPS above the method "def nofity" my build is getting successful but i am getting nothing except print statement in the first line in the notify method.

If I don't use @NonCPS I am getting following Exception

Error when executing always post condition:
com.cloudbees.groovy.cps.impl.CpsCallableInvocation

hudson.remoting.ProxyException:com.cloudbees.groovy.cps.impl.CpsCallableInvocation
Finished: FAILURE
like image 246
yashwanth ssc Avatar asked Oct 15 '22 13:10

yashwanth ssc


1 Answers

You see this error because you are calling closure inside the constructor. Instead, you should extract it to a separate method. The constructor should be used to initialize the object with values passed during initialization. For instance, the common practice is to pass the reference to the WorkflowScript object, so you can use pipeline steps like echo.

Consider the following changes to your shared library code:

src/com/mycompany/MyTest.groovy

package com.mycompany

class MyTest {
  final Map notification = [:]
  final Script script

  MyTest(Script script) {
    this.script = script
  }

  def notify(Closure content) {
    processContent(content)
    script.echo "Notification processed = ${notification}"
  }

  def processContent(Closure content) {
    content.resolveStrategy = Closure.DELEGATE_FIRST
    content.delegate = notification
    content()
  }
}

vars/test.groovy

import com.mycompany.MyTest
import groovy.transform.Field

@Field
final MyTest tester = new MyTest(this)

def notify(Closure content) {
    println("This is line i am getting in the output but nothing after that")
    tester.notify(content)
    println(tester.notification.colorcode)
}

Jenkinsfile

pipeline {
    agent any

    stages {
         stage("Test") {
             steps {
                 script {
                     test.notify {
                          buildno = 12
                          jobname = "Mytest"
                          colorcode = "Blue"
                     }
                 }
             }
         }
    }
}

The output:

[Pipeline] Start of Pipeline
[Pipeline] node
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Test)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
This is line i am getting in the output but nothing after that
[Pipeline] echo
Notification processed = [buildno:12, jobname:Mytest, colorcode:Blue]
[Pipeline] echo
Blue
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline

Keep in mind that this is just a one way of how you can refactor your shared pipeline library code. Your main goal should be to move the closure call from inside the class constructor. It's up to you where to put it so it works for you best.

like image 133
Szymon Stepniak Avatar answered Oct 19 '22 01:10

Szymon Stepniak