Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

println in "call" method of "vars/foo.groovy" works, but not in method in class

I'm iterating through building a Jenkins pipeline shared library, so my Jenkinsfile is a little cleaner.

I'm using the following page for guidance: https://jenkins.io/doc/book/pipeline/shared-libraries/ .

I first defined several methods in individual files, like "vars/methodName.groovy", with a "call()" method in the code. This works ok, and I particularly note that "println" calls in these methods are seen in the Jenkins console output.

I then decided I wanted to save some state between method calls, so I added a new file in "vars" named "uslutils.groovy" that begins like this (minus some required imports):

class uslutils implements Serializable {

I defined some "with<property>" methods that set a property and return this.

I then wrote a "public String toString()" method in "uslutils" that looks something like this:

public String toString() {
    println "Inside uslutils.toString()."
    return "[currentBuild[${currentBuild}] mechIdCredentials[${mechIdCredentials}] " +
           "baseStashURL[${baseStashURL}] jobName[${jobName}] codeBranch[${codeBranch}] " +
           "buildURL[${buildURL}] pullRequestURL[${pullRequestURL}] qBotUserID[${qBotUserID}] " +
           "qBotPassword[${qBotPassword}]]"
}

Then, inside my Jenkinsfile, after setting the uslutils properties, I added a line like this:

println "uslutils[${uslutils}]"

Then, I ran my job, and the curious thing that happened is that I didn't see the "uslutils" line, or the Inside uslutils.toString(). line. However, I did modify the one functional method I've added so far to "uslutils" (besides the "with" methods), which returns a string value, and I just added an "x" to the value. My Jenkinsfile was printing the result from that, and it did show the additional "x".

Note that no errors occurred here, it just seemed to omit the println output from within the shared library class, and even stranger, omitted the output from the println call in the Jenkinsfile that was implicitly calling the uslutils.toString() method. Note that the println calls in the original call() methods WERE seen in the console output.

Any ideas what might be happening here?

Update:

I now have the following lines in my Jenkinsfile (among others):

println "uslutils.qBotPassword[${uslutils.qBotPassword}]"
println "uslutils[${uslutils}]"
println "uslutils.toString()[${uslutils.toString()}]"

And to repeat, here is the "uslutils.toString()" method:

public String toString() {
    println "Inside uslutils.toString()."
    return "[currentBuild[${currentBuild}] mechIdCredentials[${mechIdCredentials}] " +
           "baseStashURL[${baseStashURL}] jobName[${jobName}] codeBranch[${codeBranch}] " +
           "codeURL[${codeURL}] buildURL[${buildURL}] pullRequestURL[${pullRequestURL}] qBotUserID[${qBotUserID}] " +
           "qBotPassword[${qBotPassword}]]"
}

Here are corresponding lines of output from the build:

[Pipeline] echo
uslutils.qBotPassword[...]
[Pipeline] echo
uslutils.toString()[[currentBuild[org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper@41fb2c94] mechIdCredentials[121447d5-0fe4-470d-b785-6ce88225ef01] baseStashURL[https://...] jobName[unified-service-layer-build-pipeline] codeBranch[master] codeURL[ssh://git@...] buildURL[http://...] pullRequestURL[] qBotUserID[...] qBotPassword[...]]

As you can see, the line attempting to print "uslutils[${uslutils}]" was simply ignored. The line attempting to print "uslutils.toString()[${uslutils.toString()}]" did render, but also note that the Inside uslutils.toString(). did not render.

I'm still looking for an explanation for this behavior, but perhaps this summarizes it more succinctly.

like image 572
David M. Karr Avatar asked Feb 10 '17 00:02

David M. Karr


1 Answers

I did some digging and found this issue, https://issues.jenkins-ci.org/browse/JENKINS-41953, basically in normal pipeline script println is aliased to echo step. But when you're in a class, e.g. outside of the pipeline CPS, then the echo step isn't available and the println is ignored (since, as I understand it, there is no logger available).

What you can do is to propagate the script environment into your class methods using a variable and call echo through the variable (found solution in this thread). Like this:

class A {
    Script script;
    public void a() {
        script.echo("Hello")
    }
}
def a = new A(script:this)
echo "Calling A.a()"
a.a()

outputs:

Started by user jon
[Pipeline] echo
Calling A.a()
[Pipeline] echo
Hello
[Pipeline] End of Pipeline
Finished: SUCCESS

Which is what we want. For comparison, here is without propagation:

class A {
    public void a() {
        println "Hello"
    }
}
def a = new A()
echo "Calling A.a()"
a.a()

Gives:

Started by user jon
[Pipeline] echo
Calling A.a()
[Pipeline] End of Pipeline
Finished: SUCCESS
like image 131
Jon S Avatar answered Nov 05 '22 07:11

Jon S