当前位置: 首页 > 知识库问答 >
问题:

从 Jenkins 2.0 管道中的并行执行访问构建

鱼志诚
2023-03-14

我目前使用的是Build Flow插件,在Jenkins 2.0中,这个插件似乎已经被放弃,转而支持管道。

在使用新管道重建现有工作时遇到了一些问题。

目前,我有类似这样的代码:

ignore(FAILURE) {
  join = parallel([
    job1: {build('job1')},
    job2: {build('job2')},
    job3: {build('job3')}
  ])
}
results = [join.job1.result.toString(), join.job2.result.toString(), join.job2.result.toString()]

if(join.job1.result.toString() == 'SUCCESS') {
  buildList << join.job1.lastBuild.getDisplayName()
}

此处的目标是并行运行多个现有作业,然后访问有关已完成的生成的信息。这在构建流插件中一直没有问题。

我无法找到使用新管道访问这些数据的方法。

echo 'Checking streams for latest builds'
join = [:] 

join['Job1'] = { build job: 'Job1', parameters: [[$class: 'StringParameterValue', name: 'TimeWindow', value: '1200']], propagate: false} 
join['Job2'] = { build job: 'Job2', parameters: [[$class: 'StringParameterValue', name: 'TimeWindow', value: '1200']], propagate: false} 
join['Job3'] = { build job: 'Job3', parameters: [[$class: 'StringParameterValue', name: 'TimeWindow', value: '1200']], propagate: false}

parallel join

join['Job1']的转储不会像构建流插件那样提供对抽象构建或类似内容的访问。相反,它显示:

<org.jenkinsci.plugins.workflow.cps.CpsClosure2@2eac6ed9
def=com.cloudbees.groovy.cps.impl.CpsClosureDef@59647704
delegate=WorkflowScript@3aa1807f 
owner=WorkflowScript@3aa1807f
thisObject=WorkflowScript@3aa1807f 
resolveStrategy=0 
directive=0
parameterTypes=null 
maximumNumberOfParameters=0 
bcw=null>

使用新的管道,是否有一种方法来访问像job1.result、job1-lastBuild、job11-lastbould.getDisplayName()这样的数据?

共有3个答案

郎言
2023-03-14

在<code>并行</code>步骤之后,您可以使用Jenkins API访问该数据:

Jenkins.instance.getItemByFullName('Job1').lastBuild
韩英锐
2023-03-14

这与Steve-B的答案非常相似,但实际上不需要显式定义runwrapper,也不需要将其放在额外的映射中。

tl; dr您可以将并行构建存储到hashMap并通过直接循环到它的keySet来访问该映射

对这个回答要有所保留,我用的是老版本的pipeline (Jenkins 2.7.2和Pipeline 2.2)。

您可以将并行构建结果存储到一个hashMap中,并在Map的键集上循环,以获得一些关于构建的信息。

def create_build_job(job_name, pool_label="master", propagate=false) {
  build job: job_name, parameters: [[$class: 'LabelParameterValue', name: "node_label", label: "${pool_label}"]], propagate: propagate, wait:true
}

def buildmap = [:]
def build_results

stage 'Perform Build'
    //test1 is set to fail, test2 is set to succeed
    buildmap['test1'] = {create_build_job('test1', "your_node_label")}
    buildmap['test2'] = {create_build_job('test2', "your_node_label")}

    build_results = parallel buildmap

    for(k in build_results.keySet()){
      println build_results["${k}"].getProperties()
    }

对于这个管道,我只是转储存储在地图项目中的RunWrapper的所有属性,但是您可以直接访问每个属性,所以如果您想要构建的结果,您可以这样做:

build_results["${k}"].result

此管道产生的控制台输出(任何可能的识别信息都已编辑)是:

Started by user <user>
[Pipeline] stage (Perform Build)
Entering stage Perform Build
Proceeding
[Pipeline] parallel
[Pipeline] [test1] { (Branch: test1)
[Pipeline] [test2] { (Branch: test2)
[Pipeline] [test1] build (Building test1)
[test1] Scheduling project: test1
[test1] Starting building: test1 #11
[Pipeline] [test2] build (Building test2)
[test2] Scheduling project: test2
[test2] Starting building: test2 #11
[Pipeline] }
[Pipeline] }
[Pipeline] // parallel
[Pipeline] echo
{rawBuild=test1 #11, class=class org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper, absoluteUrl=<jenkins_url>/job/test1/11/, buildVariables={}, previousBuild=org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper@1480013a, id=11, nextBuild=null, changeSets=[], result=FAILURE, description=null, startTimeInMillis=1509667550519, timeInMillis=1509667550510, duration=956, number=11, displayName=#11}
[Pipeline] echo
{rawBuild=test2 #11, class=class org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper, absoluteUrl=<jenkins_url>/job/test2/11/, buildVariables={}, previousBuild=org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper@2d9c7128, id=11, nextBuild=null, changeSets=[], result=SUCCESS, description=null, startTimeInMillis=1509667550546, timeInMillis=1509667550539, duration=992, number=11, displayName=#11}
[Pipeline] End of Pipeline
Finished: SUCCESS
狄海
2023-03-14

有点晚,但您也可以在闭包中定义由build命令返回的runWrapper对象,并将其放置在并行命令之外定义的映射中。

这是一个例子。注意:我使用传播:false,这样就不会抛出异常(JUnit测试失败等)。您必须决定如何处理异常,尝试/catch/last等。

要执行的示例管道作业(需要使用字符串paramcommandStr)参数化):

env.PASSED_CMD="${params.commandStr}"
stage('command-exec') {
    node {
        sh "${commandStr}"
    }
}

正在执行作业(配置):

buildRuns = [:]
buildResults = [:]
def buildClosure(String jobKey, String paramAValue) {
    return {
        def runWrapper = build(
            job: 'command-test-job',
            propagate: false,
            parameters: [[$class: 'StringParameterValue', name: 'commandStr', value: paramAValue]]
        )
        buildResults."$jobKey" = runWrapper
    }
}
buildRuns."job1" = buildClosure("job1", "echo 'HI' && exit 0")
buildRuns."job2" = buildClosure("job2", "echo 'HO' && exit 0")
parallel buildRuns
for(k in buildRuns.keySet()) {
    def runResult = buildResults."$k"
    echo "$k -> ${runResult.result}"
    echo "$k -> ${runResult.buildVariables.PASSED_CMD}"
}

构建日志显示:

[Pipeline] parallel
[Pipeline] [job1] { (Branch: job1)
[Pipeline] [job2] { (Branch: job2)
[Pipeline] [job1] build (Building command-test-job)
[job1] Scheduling project: command-test-job
[Pipeline] [job2] build (Building command-test-job)
[job2] Scheduling project: command-test-job
[job1] Starting building: command-test-job #7
[job2] Starting building: command-test-job #8
[Pipeline] [job2] }
[Pipeline] [job1] }
[Pipeline] // parallel
[Pipeline] echo
job1 -> SUCCESS
[Pipeline] echo
job1 -> echo 'HI' && exit 0
[Pipeline] echo
job2 -> SUCCESS
[Pipeline] echo
job2 -> echo 'HO' && exit 0
[Pipeline] End of Pipeline
Finished: SUCCESS
 类似资料:
  • 我使用Jenkins和Build Pipeline插件来构建一些相当复杂的项目,这些项目需要多个编译步骤: 构建源RPM。 构建二进制RPM(这是执行两次,一次为每个平台)。 部署到YUM仓库。 我解决构建需求的策略包括将公共工作拆分为参数化作业,这些作业可以跨项目和分支重用,每个作业代表管道中的一个阶段。每个阶段都由参数触发,并将构建工件传递给管道中的下一个作业。然而,我在这个策略上遇到了一些麻

  • 为了实现自动化,我希望用管道作业初始化Jenkins2.0实例。我想创建一个Groovy脚本,该脚本在启动时复制到文件夹。该脚本应该创建一个Jenkins2.0管道作业,用于处理来自SCM的Jenkinsfile。

  • 问题内容: 我有一个jenkins管道,该管道可以构建Java工件,将其复制到目录中,然后尝试执行外部脚本。 我在管道脚本中使用此语法来执行外部脚本 该脚本只是一个简单的Docker构建脚本,但是由于以下异常,构建将失败: 由于脚本不会创建任何目录,因此该错误令人困惑。它只是构建一个docker映像,并将新构建的java工件放置在该映像中。 如果我在jenkins中创建另一个作业,该作业执行外部脚

  • 我正在将并行执行引入我的testNG套件中。当我将“parallel”设置为“tests”时,两个浏览器打开,两个测试的第一个类同时开始--这是我所期望的。当我将其设置为“classes”时,我希望第一个测试中的两个类同时开始,但是只有一个浏览器打开,第一个类中的第一个方法执行,然后用第二个类中的第一个方法打开一个新的浏览器,依此类推。谁能告诉我我做错了什么? 下面是我的xml文件:

  • 我试图使用Selenium和TestNG进行测试设计,我将每个@test放在一个单独的类中,并对所有类使用once@beforeSuite&@afterSuite,原因是: 代码易于维护 数据驱动,以便能够选择通过文件运行的类。 案例1类: 注意:如果上面的代码在套件中使用单个运行,它就可以正常工作。 问题是它是否像下面的配置那样并行运行。

  • 我已经尝试将Shell可执行文件设置为C:\windows\system32\cmd.exe和C:\cygwin64\bin\sh.exe,但是我遇到了同样的错误。我怎样才能解决这个问题?