Search code examples
jenkinsgroovyjenkins-pipelineshared-libraries

Jenkins helper class not printing to console


I have a Jenkins shared-library
under src/org/helpers I have a groovy file ErrorHolder.groovy

package org.helpers

class ErrorHolder {
    private String message = ""

    def echo_error(String msg) {
        println "[\033[91;1mError\033[0m] ${msg}"
    }

    def emit_error(String msg) {
        echo_error(msg)
        message = msg
        error(msg)
    }

    def getMessage() {
        return message
    }
}

in the pipeline, the class is initialized and the function emit_error is called

import org.helpers.*

void call () {
    currentBuild.result = 'SUCCESS'
    ErrorHolder errorHolder = new ErrorHolder()

    pipeline {
        agent any
        options { ansiColor('xterm') }

        stages {
            stage ('Clean Workspace') {
                steps {
                    script {
                        println "Debug: $errorHolder"
                        errorHolder.emit_error("Test Error")
                    }
                }
            }
        }
    }
}

However,
I do see the first debug print,println "Debug: $errorHolder"
I don't see on the output of the print statement from the function echo_error in the console,
and I get an error: hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: org.helpers.ErrorHolder.error() is applicable for argument types

I have two questions:

  1. how to call the error built-in function from the class?
  2. how to make the print statement work?

Solution

  • Functions that are available within the Jenkins Pipeline context are not automatically available withing the custom classes that your are building. This includes functions like sh,bat, error, echo and all others functions that are available in the pipeline from different plugins or the Jenkins core library.

    To use these functions in your class you will need to pass the relevant Script context that contains those function to your class constructor, then call the function threw the context. For example:

    package org.helpers
    
    class ErrorHolder {
        /**
        * Jenkins Pipeline Script context.
        */
        final Script script
    
        private String message = ""
    
        public ErrorHolder (Script script) {
            this.script = script // initiate script context in constructor
        }
    
        def echo_error(String msg) {
            // Access println function  threw the script context
            script.println "[\033[91;1mError\033[0m] ${msg}"
        }
    
        def emit_error(String msg) {
            echo_error(msg)
            message = msg
            // Access error function threw the script context
            script.error(msg)
        }
    
        def getMessage() {
            return message
        }
    }
    

    You can now call any pipeline available function threw the script variable.
    Now when you initialize your class in the pipeline pass the context as follows:

    ErrorHolder errorHolder = new ErrorHolder(this)
    

    If you want to make it a bit easier to use, you can use a library script as a connector. For that you can create an adapter file called ErrorHolder.groovy located in the shared library vars folder:

    import org.helpers.*
    
    def call() {
       return new ErrorHolder(this)
    }
    

    Then in your pipeline you don't need the import statement and usage is as follows:

    def errorHolder = ErrorHolder()