Jenkins参数化了只排队一个构建的作业

时间:2012-01-23 15:35:30

标签: hudson jenkins jenkins-plugins

想象一下Jenkins工作A需要1分钟才能运行,而工作B需要5分钟。

如果我们将作业A配置为触发作业B,则作业B正在运行作业A可能在B完成之前运行5次。但是,Jenkins不会在作业B的队列中添加5个构建,这很好,因为否则快速的工作A会为不良的慢作业B创建不断增长的构建积压。

但是,现在我们希望使用parameterized trigger plugin将作业A触发器B作为参数化作业。参数化作业执行排队积压,这意味着作业A很乐意为作业B创建大量构建,这可能无法跟上。

每次触发时,为队列添加新的参数化构建是有意义的,因为参数可能不同。 Jenkins不应该总是假设新的参数化构建不需要渲染先前排队的构建。

然而,在我们的案例中,我们实际上是这样想的。作业A构建并打包我们的应用程序,然后作业B将其部署到类似生产的环境中并运行更多的集成测试。我们还有一个构建C,它可以部署到另一个环境并进行更多测试,所以这对我们来说是一个不断升级的模式。

我们希望参数化作业B的队列只保留添加的最后一个构建;每个新构建都将替换当前队列中的任何作业。

有没有很好的方法来实现这个目标?

7 个答案:

答案 0 :(得分:6)

向作业B添加“系统Groovy脚本”预构建步骤,以检查具有相同名称的(较新的)排队作业,并在找到时解除阻止:

def name = build.properties.environment.JOB_NAME
def queue = jenkins.model.Jenkins.getInstance().getQueue().getItems()
if (queue.any{ it.task.getName() == name }) {
  println "Newer " + name + " job(s) in queue, aborting"
  build.doStop()
} else {
  println "No newer " + name + " job(s) in queue, proceeding"
}

答案 1 :(得分:2)

你可以摆脱参数化触发插件,而是使用传统的触发。正如你所说,这会阻止作业B队列堆积。

如何将参数从A传递到B呢?使作业A在其控制台输出中产生参数。在作业B中,要获取这些构建参数,请检查最新A构建的控制台输出(可能使用Python脚本吗?)。

答案 2 :(得分:1)

这是一个解决方法:

答案 3 :(得分:1)

如果你正在使用Git,现在支持Triggering / Parameters / Pass-through选项下的“Combine Queued git hashes”。 应该实际使用的第一个Git插件版本是1.1.27(参见Jenkins-15160

答案 4 :(得分:0)

罗恩的解决方案对我有用。如果您不想在构建历史记录中包含大量已取消的构建,则可以在触发作业B之前将以下系统groovy脚本添加到作业A:

import hudson.model.*  
def q = jenkins.model.Jenkins.getInstance().getQueue()   
def items = q.getItems()  
for (i=0;i<items.length;i++){  
  if(items[i].task.getName() == "JobB"){  
    items[i].doCancelQueue()
  }   
}

答案 5 :(得分:0)

如果你只关心一些参数匹配,这里有一个更灵活的选择。当从外部触发作业(即从GitHub或Stash)触发作业时,这尤其有用,而某些参数不需要单独的构建。

如果检查的参数在当前构建和排队构建中同时存在值和存在,则当前构建将被中止,并且描述将显示将来构建包含相同的已检查参数(以及它们是什么)

如果您不希望拥有显示已中止作业的构建历史记录,则可以将其修改为取消除最后一个以外的所有其他排队作业。

    checkedParams = [ 
    "PARAM1",
    "PARAM2",
    "PARAM3",
    "PARAM4",
]

def buildParams = null
def name = build.project.name
def queuedItems = jenkins.model.Jenkins.getInstance().getQueue().getItems()

yieldToQueuedItem = false
for(hudson.model.Queue.Item item : queuedItems.findAll { it.task.getName() == name }) {
    if(buildParams == null) {    
        buildParams = [:]
        paramAction = build.getAction(hudson.model.ParametersAction.class)
        if(paramAction) {
            buildParams = paramAction.getParameters().collectEntries {
                [(it.getName()) : it.getValue()]
            }
        }
    }
    itemParams = [:]
    paramAction = item.getAction(hudson.model.ParametersAction.class)
    if(paramAction) {
        itemParams = paramAction.getParameters().collectEntries {
            [(it.getName()) : it.getValue()]
        }
    }

    equalParams = true
    for(String compareParam : checkedParams) {
        itemHasKey = itemParams.containsKey(compareParam)
        buildHasKey = buildParams.containsKey(compareParam)
        if(itemHasKey != buildHasKey || (itemHasKey && itemParams[compareParam] != buildParams[compareParam])) {
            equalParams = false
            break;
        }
    }
    if(equalParams) {
        yieldToQueuedItem = true
        break
    }
}

if (yieldToQueuedItem) {
    out.println "Newer " + name + " job(s) in queue with matching checked parameters, aborting"
    build.description = "Yielded to future build with:"
    checkedParams.each {
        build.description += "<br>" + it + " = " + build.buildVariables[it]
    }

    build.doStop()
    return
} else {
    out.println "No newer " + name + " job(s) in queue with matching checked parameters, proceeding"
}

答案 6 :(得分:0)

以下是基于Ron的解决方案,但有一些修复工作在我的Jenkins 2上,包括删除java.io.NotSerializableException异常并处理getName()的格式与{{1}的格式有些不同}}

JOB_NAME