Задание Jenkins с параметрами, которое ставит в очередь только одну сборку - PullRequest
16 голосов
/ 23 января 2012

Представьте себе задание Jenkins A, выполнение которого занимает 1 минуту, и задание B, которое занимает 5 минут.

Если мы настроим задание A на запуск задания B, в то время как задание B выполняется, задание A может выполняться 5 раз до завершения B. Однако Дженкинс не добавляет 5 сборок в очередь задания B, и это здорово, потому что в противном случае быстрое задание A создало бы постоянно растущее отставание сборок для плохой медленной работы B.

Однако теперь мы хотим, чтобы триггер B задания A был параметризованным заданием, используя плагин параметризованного запуска . Задания с параметрами do ставят в очередь невыполненное задание, что означает, что задание A успешно создает огромную кучу сборок для задания B, которое не может быть в курсе.

Имеет смысл добавлять новую параметризованную сборку в очередь каждый раз, когда она запускается, поскольку параметры могут отличаться. Дженкинс не всегда должен предполагать, что новая параметризованная сборка делает ненужными ранее поставленные в очередь.

Однако в нашем случае нам бы действительно хотелось этого. Job A создает и упаковывает наше приложение, затем Job B развертывает его в производственной среде и выполняет более сложный набор интеграционных тестов. У нас также есть сборка C, которая развертывается в другой среде и проводит еще больше тестов, поэтому для нас это расширяющийся паттерн.

Мы бы хотели, чтобы очередь для нашего параметризованного задания B сохраняла только последнюю добавленную сборку; каждая новая сборка заменяет любое задание, находящееся в очереди.

Есть ли хороший способ добиться этого?

Ответы [ 7 ]

6 голосов
/ 27 мая 2016

Добавьте шаг предварительной сборки «Системный Groovy Script» к заданию B, которое проверяет (более новые) задания с одинаковыми именами и помещает их в очередь, если найдено:

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"
}
2 голосов
/ 29 января 2012

Вы можете избавиться от Parameterized Trigger Plugin, и вместо этого использовать традиционный запуск. Как вы сказали, это предотвратит накопление очереди заданий B.

Как передать параметры из А в Б? Сделайте задание A, чтобы получить параметры в выводе консоли. В задании B, чтобы получить эти параметры сборки, проверьте вывод консоли последней сборки A (возможно, со скриптом Python?).

1 голос
/ 24 февраля 2013

В случае, если вы используете Git, теперь это поддерживается «Объединить git-хэши в очереди» под опцией Triggering / Parameters / Pass-through. Первая версия плагина Git, которая на самом деле должна работать с этим, - 1.1.27 (см. Jenkins-15160 )

1 голос
/ 29 января 2012

Вот один из обходных путей:

0 голосов
/ 18 января 2017

Следующее основано на решении Рона, но с некоторыми исправлениями для работы на моем Jenkins 2, включая удаление исключения java.io.NotSerializableException и обработку того, что формат getName() в несколько раз отличается от формата JOB_NAME

// Exception to distinguish abort due to newer jobs in queue
class NewerJobsException extends hudson.AbortException {
    public NewerJobsException(String message) { super(message); }
}

// Find jenkins job name from url name (which is the most consistently named
// field in the task object)
// Known forms:
//   job/NAME/
//   job/NAME/98/
@NonCPS
def name_from_url(url)
{
    url = url.substring(url.indexOf("/") + 1);
    url = url.substring(0, url.indexOf("/"));
    return url
}

// Depending on installed plugins multiple jobs may be queued. If that is the
// case skip this one.
// http://stackoverflow.com/questions/26845003/how-to-execute-only-the-most-recent-queued-job-in-jenkins
// http://stackoverflow.com/questions/8974170/jenkins-parameterized-job-that-only-queues-one-build
@NonCPS
def check_queue()
{
    def name = env.JOB_NAME
    def queue = jenkins.model.Jenkins.getInstance().getQueue().getItems()
    if (queue.any{ name_from_url(it.task.getUrl()) == name }) {
        print "Newer ${name} job(s) in queue, aborting"
        throw new NewerJobsException("Newer ${name} job(s) in queue, aborting")
    } else {
        print "No newer ${name} job(s) in queue, proceeding"
    }
}
0 голосов
/ 25 августа 2016

Вот более гибкий вариант, если вы заботитесь только о совпадении нескольких параметров. Это особенно полезно, когда задание запускается извне (то есть из 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"
}
0 голосов
/ 29 июля 2016

Решение Рона сработало для меня. Если вам не нравится иметь кучу отмененных сборок в истории сборки, вы можете добавить следующий системный скрипт в задание A, прежде чем запускать задание B:

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()
  }   
}
...