Jenkins管道脚本-等待运行构建

bq9c1y66  于 2023-10-17  发布在  Jenkins
关注(0)|答案(1)|浏览(167)

我有jenkins groovy pipeline触发其他构建。它在以下脚本中完成:

for (int i = 0; i < projectsPath.size(); i++) {
    stepsForParallel[jenkinsPath] = {
        stage("build-${jenkinsPath}") {
            def absoluteJenkinsPath = "/${jenkinsPath}/BUILD"
            build job: absoluteJenkinsPath, parameters: [[$class: 'StringParameterValue', name: 'GIT_BRANCH', value: branch],
                                                         [$class: 'StringParameterValue', name: 'ROOT_EXECUTOR', value: rootExecutor]]
        }
    }
}
parallel stepsForParallel

问题是,我的工作依赖于其他共同的工作,即。作业X触发作业Y,作业Z触发作业Y。我想实现的是,作业X触发作业Y,作业Z等待X触发的Y的结果。
我想我需要检查所有正在运行的构建,并检查是否有相同类型的构建正在运行。如果是,那就等着吧。下面的代码可以等待编译完成:

def busyExecutors = Jenkins.instance.computers
                        .collect { 
                          c -> c.executors.findAll { it.isBusy() }
                        }
                        .flatten()
busyExecutors.each { e -> 
    e.getCurrentWorkUnit().context.future.get()
}

我的问题是我需要告诉我需要等待哪个正在运行的作业。为此,我需要检查:

  • 构建参数
  • 构建环境变量
  • 作业名称

我如何才能检索到这种数据?
我知道Jenkins有沉默期功能,但在期限届满后,新的工作将被触发。

编辑1

只是为了说明为什么我需要这个功能。我的工作是构建应用程序和库。应用程序依赖于库,库依赖于其他库。当构建被触发时,它会触发下游作业(它所依赖的库)。
示例依赖关系树:

A -> B,C,D,E
B -> F
C -> F
D -> F
E -> F

因此,当我触发A时,B、C、D、E被触发,F也被触发(4次)。我只想触发F一次。
我有beta/beta解决方案(下面),几乎工作。现在我有以下问题与此代码:

  • 在job.future.get()结束之前,带有文本“found already running job”的echo不会刷新到屏幕
  • 我有这个丑陋的“等待”(for(i = 0; i < 1000; ++i){})。这是因为get方法返回时没有设置结果字段
import hudson.model.*

def getMatchingJob(projectName, branchName, rootExecutor){

    result = null

    def busyExecutors = []
    for(i = 0; i < Jenkins.instance.computers.size(); ++i){
        def computer = Jenkins.instance.computers[i]
        for(j = 0; j < computer.getExecutors().size(); ++j){
            def executor = computer.executors[j]
            if(executor.isBusy()){
                busyExecutors.add(executor)
            }
        }
    }

    for(i = 0; i < busyExecutors.size(); ++i){
        def workUnit = busyExecutors[i].getCurrentWorkUnit()
        if(!projectName.equals(workUnit.work.context.executionRef.job)){
            continue
        }
        def context = workUnit.context
        context.future.waitForStart()

        def parameters
        def env
        for(action in context.task.context.executionRef.run.getAllActions()){
            if(action instanceof hudson.model.ParametersAction){
                parameters = action
            } else if(action instanceof org.jenkinsci.plugins.workflow.cps.EnvActionImpl){
                env = action
            }
        }

        def gitBranchParam = parameters.getParameter("GIT_BRANCH")
        def rootExecutorParam = parameters.getParameter("ROOT_EXECUTOR")

        gitBranchParam = gitBranchParam ? gitBranchParam.getValue() : null
        rootExecutorParam = rootExecutorParam ? rootExecutorParam.getValue() : null

        println rootExecutorParam
        println gitBranchParam

        if(
            branchName.equals(gitBranchParam)
            && (rootExecutor == null || rootExecutor.equals(rootExecutorParam))
        ){
            result = [
                "future" : context.future,
                "run" : context.task.context.executionRef.run,
                "url" : busyExecutors[i].getCurrentExecutable().getUrl()
            ]
        }
    }
    result
}

job = getMatchingJob('project/module/BUILD', 'branch', null)
if(job != null){
    echo "found already running job"
    println job
    def done = job.future.get()
    for(i = 0; i < 1000; ++i){}
    result = done.getParent().context.executionRef.run.result
    println done.toString()
    if(!"SUCCESS".equals(result)){
        error 'project/module/BUILD: ' + result
    }
    println job.run.result
}
zzlelutf

zzlelutf1#

我也有类似的问题要解决。不过,我所做的是迭代作业(因为活动作业可能还没有在执行器上执行)。
在我的解决方案中,触发是这样工作的:

  • 如果作业已手动触发或由Oracle触发,则它将触发其所有(递归)下游作业
  • 如果某个作业已被另一个上游作业触发,则它不会触发任何内容

这样,作业将按其触发原因分组,可以使用

@NonCPS
def getTriggerBuild(currentBuild)
{
    def triggerBuild = currentBuild.rawBuild.getCause(hudson.model.Cause$UpstreamCause)
    if (triggerBuild) {
        return [triggerBuild.getUpstreamProject(), triggerBuild.getUpstreamBuild()]
    }
    return null
}

我给给予每个作业它所拥有的直接上游作业的列表。然后,作业可以检查上游作业是否已完成同一组中的生成,

@NonCPS
def findBuildTriggeredBy(job, triggerJob, triggerBuild)
{
    def jobBuilds = job.getBuilds()
    for (buildIndex = 0; buildIndex < jobBuilds.size(); ++buildIndex)
    {
        def build = jobBuilds[buildIndex]
        def buildCause = build.getCause(hudson.model.Cause$UpstreamCause)
        if (buildCause)
        {
            def causeJob   = buildCause.getUpstreamProject()
            def causeBuild = buildCause.getUpstreamBuild()
            if (causeJob == triggerJob && causeBuild == triggerBuild)
            {
                return build.getNumber()
            }
        }
    }
    return null
}

从那里开始,一旦上游构建的列表被制作出来,我就等待他们。

def waitForUpstreamBuilds(upstreamBuilds)
{
    // Iterate list -- NOTE: we cannot use groovy style or even modern java style iteration
    for (upstreamBuildIndex = 0; upstreamBuildIndex < upstreamBuilds.size(); ++upstreamBuildIndex)
    {
        def entry = upstreamBuilds[upstreamBuildIndex]
        def upstreamJobName = entry[0]
        def upstreamBuildId = entry[1]
        while (true)
        {
            def status = isUpstreamOK(upstreamJobName, upstreamBuildId)
            if (status == 'OK')
            {
                break
            }
            else if (status == 'IN_PROGRESS')
            {
                echo "waiting for job ${upstreamJobName}#${upstreamBuildId} to finish"
                sleep 10
            }
            else if (status == 'FAILED')
            {
                echo "${upstreamJobName}#${upstreamBuildId} did not finish successfully, aborting this build"
                return false
            }
        }
    }
    return true
}

如果一个上游构建失败,则中止当前构建(这很好地翻译为“中止构建”而不是“失败构建”)。
完整的代码在那里:https://github.com/doudou/autoproj-jenkins/blob/use_autoproj_to_bootstrap_in_packages/lib/autoproj/jenkins/templates/library.pipeline.erb
我的解决方案的主要缺点是,当有很多构建等待时,等待是昂贵的CPU明智的。有内置的waitUntil,但它导致了死锁(我还没有尝试过管道插件的最后一个版本,可能已经解决了)。我正在寻找解决这个问题的方法-这就是我发现你的问题的原因。

相关问题