XmlSlurper () в конвейере Дженкинса. как избежать java.io.NotSerializableException: groovy.util.slurpersupport.NodeChild - PullRequest
3 голосов
/ 08 ноября 2019

Я пытаюсь прочитать свойства из моего файла pom.xml. Я попробовал следующее, и это сработало:

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

Когда я попытался сделать что-то вроде этого:

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

конвейер неожиданно завершился с ошибкой:

Caused: java.io.NotSerializableException: groovy.util.slurpersupport.NodeChild

В чем может быть проблема здесь?

РЕДАКТИРОВАТЬ: просто добавьте это для других, которые находят его с таким же вариантом использования. Мой конкретный вопрос был о том, как избежать ошибки, связанной с CPS, с помощью XmlSlurper (). НО для тех, кто пытается разобрать POM, боясь того PR, который якобы обесценит readMavenPom, самый безопасный и хитрый способ сделать это, вероятно, что-то вроде:

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

Таким образом, вы используете сам maven дляскажу вам, что это за версия, а не копать и не прятаться по всему проклятому месту. Как получить версию проекта Maven в командной строке bash

1 Ответ

2 голосов
/ 09 ноября 2019

Как правило, использование groovy.util.slurpersupport.NodeChild (тип вашей xml переменной) или groovy.util.slurpersupport.NodeChildren (тип xml.version) внутри конвейера CPS - плохая идея. Оба класса не сериализуемы, поэтому вы не можете предсказать их поведение в Groovy CPS. Например, я успешно запустил ваш второй пример в моем конвейере Jenkins. Скорее всего, потому что приведенный вами пример неполон или что-то в этом роде.

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> 

Если вы хотите прочитать файл pom.xml, используйте шаг конвейера readMavenPom. Он предназначен для чтения файлов pom, и что самое важное - это безопасно делать без каких-либо обходных путей. Этот шаг идет с плагином pipeline-utility-steps .

Однако, если вы хотите по какой-то причине использовать XmlSlurper, вам нужно использовать его внутри метода, помеченного @NonCPS. Таким образом, вы можете получить доступ к «чистому» Groovy и избежать проблем, с которыми вы столкнулись. (Тем не менее, использование readMavenPom является самым безопасным способом достижения того, что вы пытаетесь сделать.) Суть в том, чтобы использовать любые несериализуемые объекты внутри области видимости @NonCPS, чтобы конвейер не пытался ее сериализовать.

Ниже вы можете найти простой пример конвейера, который показывает оба подхода.

pipeline {
    agent any 

    stages {
        stage("Using readMavenPom") {
            steps {
                script {
                    def xmlfile = readMavenPom file: "pom.xml"
                    def version = xmlfile.version
                    echo "version = ${version}"
                }
            }
        }

        stage("Using XmlSlurper") {
            steps {
                script {
                    def xmlfile = readFile "pom.xml"
                    def version = extractFromXml(xmlfile) { xml -> xml.version }
                    echo "version = ${version}"
                }
            }
        }
    }
}

@NonCPS
String extractFromXml(String xml, Closure closure) {
    def node = new XmlSlurper().parseText(xml)
    return closure.call(node)?.text()
}

PS: не говоря уже о том, что для использования XmlSlurper требуется как минимум одобрение сценария 3, прежде чем вы сможете начать его использовать.

...