首页 > 解决方案 > 多个节点上的声明式 Jenkins 管道中的并行结帐

问题描述

我正在为 CI 构建开发一个声明性的 Jenkins 管道,由 Gitlab 触发。我现在拥有的:


// variable definitions

pipeline {
    agent none

    parameters {
            string(defaultValue: 'develop',
                description: 'Commit ID or branch name to build', 
                name: 'branch', 
                trim: false)
    }

    stages {
        stage('Checkout') {
            parallel {
                stage ('Windows') {
                    agent {
                        label 'build' && 'windows'
                    }

                    steps {
                        script {

                            def checkout_ext = [[$class: 'CleanCheckout'],
                                                [$class: 'CleanBeforeCheckout']] // calls git clean -fdx and git reset --hard

                            if (env.gitlabActionType == "MERGE"){   
                                  checkout_ext.add([$class: 'PreBuildMerge', 
                                                    options: [ mergeRemote: "origin",
                                                              mergeTarget: "${env.gitlabTargetBranch}"]])
                            }
                        }

                        checkout([
                                $class: 'GitSCM', 
                                branches: [[name: "${params.branch}"]],
                                userRemoteConfigs: [[ url: "${git_url}",                                          credentialsId: "${git_credentials_id}" ]],
                                extensions:   checkout_ext 
                        ])
                    }
                }

                stage('Linux') {
                    agent {
                        label 'build' && 'linux'
                    }
                    steps {
                        script {

                            def checkout_ext = [[$class: 'CleanCheckout'], 
                                                [$class: 'CleanBeforeCheckout']] // calls git clean -fdx and git reset --hard

                            if (env.gitlabActionType == "MERGE"){   
                               checkout_ext.add([$class: 'PreBuildMerge', 
                                                 options: [ mergeRemote: "origin",
                                                 mergeTarget: "${env.gitlabTargetBranch}"]])
                            }
                        }

                        checkout([
                                $class: 'GitSCM', 
                                branches: [[name: "${params.branch}"]],
                                userRemoteConfigs: [[ url: "${git_url}", credentialsId: "${git_credentials_id}"]],
                                extensions:   checkout_ext 
                        ])
                    }
                }
            }
        }
    }
}

结帐阶段有些复杂。如果gitlabActionTypeMERGE,则首先尝试合并到目标分支,以确保合并请求不会破坏其中的任何内容。

这两个操作系统的代码是相同的。我想避免代码重复,但无法找出正确的语法。

我尝试将结帐步骤的定义移至全局变量,但出现语法错误。


def checkout_step = {
    script {
   ...
    }
    checkout (... )
}

pipeline {
...
   stages {
        stage('Checkout') {
            parallel {
                stage ('Windows') {
                    agent {
                        label 'build' && 'windows'
                    }

                    steps {
                        checkout_step
                    }
                }
                stage ('Linux') {
                    agent {
                        label 'build' && 'linux'
                    }

                    steps {
                        checkout_step
                    }
                }
            }
        }
    }
}

如果 add steps,还有一个错误:


def checkout_step = steps {
    script {
   ...
    }
    checkout (... )
}

pipeline {
...
   stages {
        stage('Checkout') {
            parallel {
                stage ('Windows') {
                    agent {
                        label 'build' && 'windows'
                    }

                    checkout_step

                }
                stage ('Linux') {
                    agent {
                        label 'build' && 'linux'
                    }

                    checkout_step

                }
            }
        }
    }
}

标签: jenkinsjenkins-declarative-pipeline

解决方案


在这里找到了解决方案


git_url = "git@gitserver.corp.com:group/repo.git"
git_credentials_id = 'aaaaaaa-bbbb-cccc-dddd-eefefefefef'


def checkout_tasks(os_labels) {
    tasks = [:]

    for (int i = 0; i < os_labels.size(); i++) {
        def os = os_labels[i]
        tasks["${os}"] = {
            node("build && ${os}"){

                def checkout_ext = [[$class: 'CleanCheckout'], [$class: 'CleanBeforeCheckout']] // calls git clean -fdx and git reset --hard

                if (env.gitlabActionType == "MERGE"){   
                    checkout_ext.add([
                            $class: 'PreBuildMerge', 
                            options: [ 
                            mergeRemote: "origin", 
                            mergeTarget: "${env.gitlabTargetBranch}" 
                            ]
                    ])
                         /* using this extension requires .gitconfig with section [user for Jenkins]
                            Example
                            [user]
                            email = jenkins@builder
                            name = Jenkins

                          */
                }

                checkout([
                        $class: 'GitSCM', 
                        branches: [[name: "${params.branch}"]],
                        userRemoteConfigs: [[
                            url: "${git_url}", 
                            credentialsId: "${git_credentials_id}"
                        ]],
                        extensions:  checkout_ext 
                ])

            }
        }
    }
    return tasks
}


pipeline {
    agent none

    parameters {
        string(defaultValue: 'develop',
               description: 'Commit ID or branch name to build', 
               name: 'branch', 
               trim: false)
    }

    stages {
        stage('Checkout') {
            steps {
                script {
                    def OSes = ["windows", "linux"]
                    parallel checkout_tasks(OSes)
                }
            }
        }
   }
}

git_url声明and git_credentials_idwithout也很重要def,以便函数可以读取它们。

这个问题的更多细节


推荐阅读