为什么这个 Jenkins Pipeline 代码不成功?

Why does this Jenkins Pipeline code not succeed?

这是我的情况:我的一个项目由多个子项目组成,大致分为前端和后端,它们位于颠覆存储库中的不同位置。

我将 checkout 插件提取到一个函数中,该函数已经为结帐正确参数化:

def svn(String url, String dir = '.') {
    checkout([
        $class: 'SubversionSCM',
        locations: [[
            remote: url,
            credentialsId: '...'
            local: dir,
        ]],
        workspaceUpdater: [$class: 'UpdateUpdater']
    ])
}

这样,我就可以通过这种方式(简化)进行结帐:

stage "1. Build"

parallel (
    "Backend": { node {
        svn('https://svn.acme.com/Backend/trunk')
        sh 'gradle build'
    }},

    "Frontend": { node {
        svn('https://svn.acme.com/Frontend/trunk')
        sh 'gradle build'
    }}
)

同时检出导致 Jenkins 遇到变更集 xml 文件的问题,据我从堆栈跟踪中猜测。

由于我还想重用项目名称及其 svn url,我继续迭代地图并连续检出,并在第一阶段存储文件以进行后续并行构建-仅阶段:

stage "1. Checkout"

node {
    [
        'Backend':  'https://svn.acme.com/Backend/trunk',
        'Frontend': 'https://svn.acme.com/Frontend/trunk', 
    ].each { name, url ->
        // Checkout in subdirectory
        svn(url, name)
        // Unstash by project name
        dir(name) { stash name }
    }
}

stage "2. Build"
// ...

不知何故 Jenkins 的管道不支持这个,所以我使用了一个简单的 for-in 循环:

node {
    def projects = [
        'Backend': '..'
        // ...
    ]

    for ( project in projects ) {
         def name = project.getKey()
         def url  = project.getValue()

         svn(url, name)
         dir(name) { stash name }
    }

    project = projects = name = url = null
}

效果不佳并退出构建并出现异常:java.io.NotSerializableException: java.util.LinkedHashMap$Entry。如您所见,我将每个 属性 设置为空,因为我在某处读到,这可以防止这种行为。你能帮我解决这个问题并解释一下,这里到底发生了什么吗?

谢谢!

我认为这是 for 循环中的一个已知 Jenkins 错误:

https://issues.jenkins-ci.org/browse/JENKINS-27421

但是 .each 样式循环也存在一个已知错误

https://issues.jenkins-ci.org/browse/JENKINS-26481

因此,目前您似乎无法在 Jenkins 管道中迭代地图。我建议创建一个列表作为解决方法,并使用 "classic loop" 样式对其进行迭代:

def myList = ["Backend|https://svn.acme.com/Backend/trunk", "Frontend|https://svn.acme.com/Frontend/trunk"]

for (i = 0; i < myList.size(); i++) {
  //get current list item : myList[i] and split at pipe | ->escape pipe with \
  def (name, url) = myList[i].tokenize( '\|' )
  //do operations
  svn(url, name)
  dir(name) { stash name }
}