繁体   English   中英

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

[英]Jenkins pipeline script - wait for running build

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

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等待Y触发的结果X。

我想我需要迭代所有正在运行的构建并检查是否有任何相同类型的构建正在运行。 如果是,那么等待它。 以下代码可以等待构建完成:

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

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

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

我该如何检索这类数据?

我知道詹金斯有静默期特征,但在期限到期后,新工作将被触发。

EDIT1

只是为了澄清为什么我需要这个功能。 我有构建应用程序和库的作业。 应用程序依赖于libs和libs依赖于其他libs。 当触发构建时,它会触发下游作业(它所依赖的库)。

样本依赖树:

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

所以当我触发A然后B,C,D,E被触发并且F也被触发(4次)。 我想只触发一次F。

我有beta / PoC解决方案(下面)几乎可以工作。 现在我有这个代码的以下问题:

  • 在job.future.get()结束之前,回显文本“找不到正在运行的作业”不会刷新到屏幕
  • 我有这个丑陋的“等待”(对于(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 } 

我有类似的问题需要解决。 但是,我正在做的是迭代作业(因为活动作业可能还没有在执行程序上执行)。

触发在我的解决方案中如下工作:

  • 如果手动或通过VCS触发作业,则会触发所有(递归)下游作业
  • 如果某个作业已被另一个上游作业触发,则不会触发任何操作

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

@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 ,但它导致了死锁(我没有试过最后一个版本的管道插件,可能已经解决了)。 我正在寻找解决这个问题的方法 - 这就是我找到你问题的方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM