【问题标题】:Passing parameters from Jenkinsfile to a shared library将参数从 Jenkinsfile 传递到共享库
【发布时间】:2019-01-11 12:08:01
【问题描述】:

我有几个组件(带有自己的 Bitbucket 存储库的代码项目),每个组件都有一个 Jenkinsfile,如下所示:

properties([parameters([string(defaultValue: "", description: "List of components", name: 'componentsToUpdate'),
                        string(defaultValue: "refs%2Fheads%2Fproject%2Fintegration", description: "BuildInfo CommitID", name: 'commitId'),
                        string(defaultValue: "", description: "Tag to release, e.g. 1.1.0-integration", name: 'releaseTag'),
                        string(defaultValue: "", description: "Forked buildInfo repo. Be aware right commit ID!!!", name: 'fork')]),
                        [$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '7', numToKeepStr: '5']],
                        disableConcurrentBuilds()])

@Library('jenkins-shared-stages')

import mergePipeline
import releasePipeline
import ripplePipeline
import componentPipeline


def branchName = env.BRANCH_NAME
def rewriteDependencies = ""
def returnValue = null
def forkedRepo = params.fork
def buildInfoCommitId = params.commitId
def tagToRelease = params.releaseTag
println "buildInfoCommitId: " + buildInfoCommitId
if(params.componentsToUpdate) {
    rewriteDependencies = params.componentsToUpdate
}

if (branchName == "project/integration") {
    mergePipeline {
    }
} else if (branchName == 'master') {
    releasePipeline {
        releaseTag = tagToRelease
    }
} else {
    returnValue = componentPipeline {
        componentsToUpdate = rewriteDependencies
        commitId = buildInfoCommitId
        runOnForkedRepo = forkedRepo
    }

    rewriteDependencies = rewriteDependencies.isEmpty() ? returnValue : rewriteDependencies + "," + returnValue
    println "WHAT is rewriteDependencies? " + rewriteDependencies
    println "The return value: " + returnValue
    ripplePipeline {
        commitId = buildInfoCommitId
        componentName = returnValue
        runOnForkedRepo = forkedRepo
        componentsToUpdate = rewriteDependencies
    }
}

需要使用“包装器”管道,例如 wrapperPipeline.groovy:

import mergePipeline
import releasePipeline
import ripplePipeline
import componentPipeline
import org.slf4j.Logger
import org.slf4j.LoggerFactory

def call(body) {

    final Logger logger = LoggerFactory.getLogger(wrapperPipeline)

    def config = [:]
    body.resolveStrategy = Closure.DELEGATE_FIRST
    body.delegate = config
    body()

    // Assuming we have multibranch pipeline job or defined branch name in the env
    def branchName = env.BRANCH_NAME
    // There is a bug in the Jenkins it will pass a string "null" as a gradle build parameter instead of NULL object if there is
    // empty parameter has been passed!!!
    def rewriteDependencies = ""
    def returnValue = null
    def forkedRepo = config.runOnForkedRepo
    def buildInfoCommitId = config.commitId
    def tagToRelease = config.releaseTag

    def globalVars = new se.GlobalVars()
    def notifyHandler = new se.NotifyHandler()

    node(globalVars.getAgent('buildAgent')) {
        def PIPELINE_NAME = "wrapperPipeline"

        try {
            logger.info("The buildInfoCommitId is {}", buildInfoCommitId)
            logger.info("Branch name: {}", branchName)

            println "buildInfoCommitId:  "+buildInfoCommitId
            println"Branch name: "+branchName

            if (config.componentsToUpdate) {
                rewriteDependencies = config.componentsToUpdate
            }

    // keep the same integration pipeline for the master branch for now
            if (branchName == "project/integration") {
                logger.info("Invoking mergePipeline")
                println "Invoking mergePipeline"
                mergePipeline {
                }
            } else if (branchName == 'master') {
                logger.info("Invoking releasePipeline")
                println "Invoking releasePipeline"
                releasePipeline {
                    releaseTag = tagToRelease
                }
            } else {
                logger.info("Invoking componentPipeline")
                println "Invoking componentPipeline"

                returnValue = componentPipeline {
                    componentsToUpdate = rewriteDependencies
                    commitId = buildInfoCommitId
                    runOnForkedRepo = forkedRepo
                }
                logger.info("Component pipeline has returned {}", returnValue)
                println "Component pipeline has returned"+returnValue

                // We need to provide new version of the component to the Ripple builds
                rewriteDependencies = rewriteDependencies.isEmpty() ? returnValue : rewriteDependencies + "," + returnValue
                logger.info("rewriteDependencies: {}", rewriteDependencies)
                println "The return value: " + returnValue
                ripplePipeline {
                    commitId = buildInfoCommitId
                    componentName = returnValue
                    runOnForkedRepo = forkedRepo
                    componentsToUpdate = rewriteDependencies
                }
            }
        }
        catch (err) {
            def build_status = "Exception ${err.message} in build ${env.BUILD_ID}"
            logger.error(build_status,err)
            notifyHandler.NotifyFail(build_status, PIPELINE_NAME)

            throw err
        }

    }
}

修改后的 Jenkinsfile:

properties([parameters([string(defaultValue: "", description: "List of components", name: 'componentsToUpdate'),
                        string(defaultValue: "refs%2Fheads%2Fproject%2Fintegration", description: "BuildInfo CommitID", name: 'commitId'),
                        string(defaultValue: "", description: "Tag to release, e.g. 1.1.0-integration", name: 'releaseTag'),
                        string(defaultValue: "", description: "Forked buildInfo repo. Be aware right commit ID!!!", name: 'fork')]),
                        [$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '7', numToKeepStr: '5']],
                        disableConcurrentBuilds()])

@Library('jenkins-shared-stages@integration/CICD-959-wrapper-pipeline-for-the-jenkinsfile') _

import wrapperPipeline

wrapperPipeline{}

现在,我怀疑 params 对象(来自 Jenkinsfile 的属性)没有正确填充。例如

def buildInfoCommitId = config.commitId
.
.
.
println "buildInfoCommitId:  "+buildInfoCommitId

打印空值。

如何正确调用 wrapperPipeline?

注意:我是 Jenkins 管道和 Groovy 的新手 :)

【问题讨论】:

    标签: jenkins jenkins-pipeline


    【解决方案1】:

    因为这些是 Jenkins 参数,所以它们不在配置对象中。

    您将以params.commitId 访问commitId

    如果您在调用 wrapperPipeline() 时在闭包中有某些内容,那么这些内容将在 config 对象中。例如

    wrapperPipeline({
        param="value"
    })
    

    那么config.param 将导致"value"

    但是,作为忠告,我建议在调用存储在共享库中的 vars/ 下的库时避免使用闭包。请参阅 http://groovy-lang.org/closures.html 了解什么是闭包。关键是,它们相当复杂,如果由于实例化闭包而最终尝试传递动态变量,它们可能会引入一些问题。 (他们有自己的位置,但对于简单的事情,我认为避免更好)

    我建议改为实现一个帮助函数,允许您使用映射或闭包来调用共享库。

    在您的 src 路径下添加一个名为 buildConfig 的共享库:

    package net.my.jenkins.workflow
    import com.cloudbees.groovy.cps.NonCPS
    
    class BuildConfig implements Serializable {
        static Map resolve(def body = [:]) {
    
            Map config = [:]
            config = body
            if (body in Map) {
                config = body
            } else if (body in Closure) {
                body.resolveStrategy = Closure.DELEGATE_FIRST
                body.delegate = config
                body()
            } else {
                throw  new Exception(sprintf("Unsupported build config type:%s", [config.getClass()]))
            }
            return config
        }
    }
    

    然后在你的共享库下的 vars/ 开始

    import net.my.jenkins.workflow.BuildConfig
    
    def call(def body = [:]) {
        // evaluate the body block, and collect configuration into the object
        config = BuildConfig.resolve(body)
    

    然后,您可以使用 Maps 来消除复杂性,因此您可以重新分配它(不是这样,因为您只会使用 params.commitId)。

    wrapperPipeline ([
        "commitId": params.commitId,
    ])
    

    这意味着config.commitId 现在的值是params.commitId

    如果您需要更多详细信息,请告诉我。

    TL;DR - 你应该使用 params 对象,因为你已经定义了参数。 如果您确实开始通过共享 lib 调用传递参数,我会在闭包上使用映射。 (需要一些最小的实现)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-05
      • 2017-01-30
      • 1970-01-01
      • 2019-07-13
      • 1970-01-01
      相关资源
      最近更新 更多