【问题标题】:println in "call" method of "vars/foo.groovy" works, but not in method in class“vars/foo.groovy”的“调用”方法中的 println 有效,但在类中的方法中无效
【发布时间】:2017-02-10 00:46:53
【问题描述】:

我正在迭代构建一个 Jenkins 管道共享库,所以我的 Jenkinsfile 更干净一些。

我正在使用以下页面作为指导:https://jenkins.io/doc/book/pipeline/shared-libraries/

我首先在单个文件中定义了几个方法,例如“vars/methodName.groovy”,在代码中使用了“call()”方法。这可以正常工作,我特别注意到这些方法中的“println”调用可以在 Jenkins 控制台输出中看到。

然后我决定我想在方法调用之间保存一些状态,所以我在“vars”中添加了一个名为“uslutils.groovy”的新文件,它以这样的开头(减去一些必需的导入):

class uslutils implements Serializable {

我定义了一些“with<property>”方法来设置一个属性并返回这个。

然后我在“uslutils”中编写了一个“public String toString()”方法,看起来像这样:

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}]]"
}

然后,在我的 Jenkinsfile 中,设置 uslutils 属性后,我添加了如下一行:

println "uslutils[${uslutils}]"

然后,我开始了我的工作,奇怪的是我没有看到“uslutils”行或Inside uslutils.toString()。线。但是,我确实修改了迄今为止添加到“uslutils”(除了“with”方法之外)的一个函数方法,它返回一个字符串值,我只是在该值中添加了一个“x”。我的 Jenkinsfile 正在打印结果,它确实显示了额外的“x”。

请注意,这里没有发生错误,它似乎只是省略了共享库类中的 println 输出,甚至更奇怪的是,省略了 Jenkinsfile 中隐式调用 @987654336 的 println 调用的输出@ 方法。请注意,在控制台输出中可以看到原始 call() 方法中的 println 调用。

你有什么想法吗?

更新

我的 Jenkinsfile(以及其他)中现在有以下几行:

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

重复一遍,这里是“uslutils.toString()”方法:

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}]]"
}

以下是构建的相应输出行:

[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[...]]

如您所见,尝试print "uslutils[${uslutils}]" 的行被简单地忽略了。尝试print "uslutils.toString()[${uslutils.toString()}]" 的行确实渲染了,但还要注意Inside uslutils.toString()。没有渲染。

我仍在寻找这种行为的解释,但也许这可以更简洁地总结它。

【问题讨论】:

    标签: jenkins groovy jenkins-pipeline


    【解决方案1】:

    我做了一些挖掘,发现了这个问题,https://issues.jenkins-ci.org/browse/JENKINS-41953,基本上在正常的管道脚本中,println 别名为echo 步骤。但是当你在课堂上时,例如在管道 CPS 之外,则 echo 步骤不可用并且 println 被忽略(因为据我了解,没有可用的记录器)。

    您可以做的是使用变量将脚本环境传播到您的类方法中,并通过变量 (found solution in this thread) 调用 echo。像这样:

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

    输出:

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

    这是我们想要的。为了比较,这里没有传播:

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

    给予:

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

    【讨论】:

    • 您是否曾尝试在主/从环境中运行此解决方案?尝试序列化脚本属性时似乎失败
    • 是的,你可能需要用 @NonNCP 注释方法 A.a(),类需要实现 Serializable 接口来防止然后将脚本作为参数传递给方法......
    • 我不太了解通过在从节点的上下文中运行对管道施加的限制,但workflow-cps-plugin 的自述文件说,You may not call regular (CPS-transformed) methods, or Pipeline steps, from a @NonCPS method, so they are best used for performing some calculations before passing a summary back to the main script.github.com/jenkinsci/workflow-cps-plugin/#technical-design
    • @eelghEEz 是的,所以如果你用@NonCPS注释一个方法,那么你不能从全局范围调用任何步骤,也不能使用上面的技巧,你会得到一个错误当您尝试引用上面脚本变量中的内容。这与您所处的主/从环境无关。但是请注意,print ant println 是 groovy 中内置的函数,因此不包括在内,但如上所示,消息并不总是打印在控制台输出中。
    猜你喜欢
    • 1970-01-01
    • 2014-06-19
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多