詹金斯管道中的 XmlSlurper()。如何避免 java.io.NotSerializableException: groovy.util.slurpersupport.NodeChild

red*_*888 6 groovy jenkins jenkins-pipeline

我正在尝试从我的 pom.xml 文件中读取属性。我尝试了以下方法并且有效:

steps {
    script {
        def xmlfile = readFile "pom.xml"
        def xml = new XmlSlurper().parseText(xmlfile)
        def version = "${xml.version}"
        echo version
    }
}
Run Code Online (Sandbox Code Playgroud)

当我尝试做这样的事情时:

steps {
    script {
        def xmlfile = readFile "pom.xml"
        def xml = new XmlSlurper().parseText(xmlfile)
        def version = "${xml.version}"
        def mystring = "blabhalbhab-${version}"
        echo mystring
    }
}
Run Code Online (Sandbox Code Playgroud)

管道突然失败并显示错误:

Caused: java.io.NotSerializableException: groovy.util.slurpersupport.NodeChild
Run Code Online (Sandbox Code Playgroud)

这里可能有什么问题?

编辑:只需为其他使用相同用例的人添加它。我的具体问题是关于如何使用 XmlSlurper() 避免 CPS 相关错误。但是对于任何其他试图解析 POM 的人来说,害怕那个据称会弃用的 PR,readMavenPom最安全最专业的方法可能是这样的:

def version = sh script: "mvn help:evaluate -f 'pom.xml' -Dexpression=project.version -q -DforceStdout", returnStdout: true trim()
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以使用 maven 本身来告诉您版本是什么,而不是在该死的地方进行 grepping 或 sedding。如何获取 Maven 项目版本到 bash 命令行

Szy*_*iak 5

一般来说,在 CPS 管道内使用groovy.util.slurpersupport.NodeChild(变量的类型xml)或groovy.util.slurpersupport.NodeChildren(的类型xml.version)是一个坏主意。这两个类都不可序列化,因此您无法在 Groovy CPS 中预测它们的行为。例如,我在 Jenkins Pipeline 中成功运行了您的第二个示例。很可能是因为您给出的示例不完整或类似的原因。

groovy:000> xml = new XmlSlurper().parseText("<tag></tag>")
===> 
groovy:000> xml instanceof Serializable
===> false
groovy:000> xml.tag instanceof Serializable
===> false
groovy:000> xml.dump()
===> <groovy.util.slurpersupport.NodeChild@0 node=groovy.util.slurpersupport.Node@5b1f29fa parent= name=tag namespacePrefix=* namespaceMap=[xml:http://www.w3.org/XML/1998/namespace] namespaceTagHints=[xml:http://www.w3.org/XML/1998/namespace]>
groovy:000> xml.tag.dump()
===> <groovy.util.slurpersupport.NodeChildren@0 size=-1 parent= name=tag namespacePrefix=* namespaceMap=[xml:http://www.w3.org/XML/1998/namespace] namespaceTagHints=[xml:http://www.w3.org/XML/1998/namespace]>
groovy:000> 
Run Code Online (Sandbox Code Playgroud)

如果要读取pom.xml文件,请使用readMavenPom管道步骤。它专门用于读取 pom 文件,最重要的是 - 无需应用任何解决方法即可安全地执行此操作。此步骤随pipeline-utility-steps插件一起提供。

但是,如果您出于某种原因想要使用它XmlSlurper,则需要在用 注释的方法内部使用它@NonCPS。这样您就可以访问“纯”Groovy 并避免遇到的问题。(然而,仍然使用readMavenPom是实现您想要做的事情的最安全的方法。)这里的要点是在范围内使用任何不可序列化的对象,@NonCPS这样管道就不会尝试序列化它。

您可以在下面找到显示这两种方法的简单管道示例。

groovy:000> xml = new XmlSlurper().parseText("<tag></tag>")
===> 
groovy:000> xml instanceof Serializable
===> false
groovy:000> xml.tag instanceof Serializable
===> false
groovy:000> xml.dump()
===> <groovy.util.slurpersupport.NodeChild@0 node=groovy.util.slurpersupport.Node@5b1f29fa parent= name=tag namespacePrefix=* namespaceMap=[xml:http://www.w3.org/XML/1998/namespace] namespaceTagHints=[xml:http://www.w3.org/XML/1998/namespace]>
groovy:000> xml.tag.dump()
===> <groovy.util.slurpersupport.NodeChildren@0 size=-1 parent= name=tag namespacePrefix=* namespaceMap=[xml:http://www.w3.org/XML/1998/namespace] namespaceTagHints=[xml:http://www.w3.org/XML/1998/namespace]>
groovy:000> 
Run Code Online (Sandbox Code Playgroud)

PS:更不用说使用XmlSlurper至少需要脚本3批准才能开始使用。