Подтвердить что ты не робот

Jenkins - прекратите работу, если новый

Я использую Jenkins и Multibranch Pipeline. У меня есть работа для каждой активной ветки git. Новая сборка запускается нажатием в репозитории git. Я хочу, чтобы прервать запущенные сборки в текущей ветке, если новая одна появляется в одной ветки.

Например: я фиксирую и нажимаю на ветвь feature1. Тогда BUILD_1 началось в Дженкинсе. Я делаю еще одну фиксацию и нажимаю на ветвь feature1, пока BUILD_1 все еще работает. Я хочу BUILD_1 прерваться и начать BUILD_2.

Я попытался использовать параметр stage concurrency=x и stage-lock-milestone, но мне не удалось решить мою проблему.

Также я прочитал эту тему Остановить работу Jenkins в случае запуска более новой версии, но для моей проблемы нет решения.

Знаете ли вы какое-либо решение?

4b9b3361

Ответ 1

включить параллельный запуск задания для вашего проекта с помощью Execute concurrent builds if necessary

В качестве первого шага сборки используйте execute system groovy script:

import hudson.model.Result
import jenkins.model.CauseOfInterruption

//iterate through current project runs
build.getProject()._getRuns().iterator().each{ run ->
  def exec = run.getExecutor()
  //if the run is not a current build and it has executor (running) then stop it
  if( run!=build && exec!=null ){
    //prepare the cause of interruption
    def cause = { "interrupted by build #${build.getId()}" as String } as CauseOfInterruption 
    exec.interrupt(Result.ABORTED, cause)
  }
}

и в прерванной работе (ях) будет журнал:

Build was aborted
interrupted by build #12
Finished: ABORTED 

Ответ 2

Если кому-то это нужно в Jennkins Pipeline Multibranch, это можно сделать в файле Jenkins следующим образом:

def abortPreviousRunningBuilds() {
  def hi = Hudson.instance
  def pname = env.JOB_NAME.split('/')[0]

  hi.getItem(pname).getItem(env.JOB_BASE_NAME).getBuilds().each{ build ->
    def exec = build.getExecutor()

    if (build.number != currentBuild.number && exec != null) {
      exec.interrupt(
        Result.ABORTED,
        new CauseOfInterruption.UserInterruption(
          "Aborted by #${currentBuild.number}"
        )
      )
      println("Aborted previous running build #${build.number}")
    } else {
      println("Build is not running or is current build, not aborting - #${build.number}")
    }
  }
}

Ответ 3

Получил это, имея следующий скрипт в Глобальной общей библиотеке:

import hudson.model.Result
import jenkins.model.CauseOfInterruption.UserInterruption

def killOldBuilds() {
  while(currentBuild.rawBuild.getPreviousBuildInProgress() != null) {
    currentBuild.rawBuild.getPreviousBuildInProgress().doKill()
  }
}

И называя это в моем конвейере:

@Library('librayName')
def pipeline = new killOldBuilds()
[...] 
stage 'purge'
pipeline.killOldBuilds()

Изменение: В зависимости от того, насколько сильно вы хотите убить oldBuild, вы можете использовать doStop(), doTerm() или doKill()!

Ответ 4

Основываясь на идее @C4stor, я сделал эту улучшенную версию... Я считаю ее более читаемой из версии @daggett.

import hudson.model.Result
import hudson.model.Run
import jenkins.model.CauseOfInterruption.UserInterruption

def abortPreviousBuilds() {
    Run previousBuild = currentBuild.rawBuild.getPreviousBuildInProgress()

    while (previousBuild != null) {
        if (previousBuild.isInProgress()) {
            def executor = previousBuild.getExecutor()
            if (executor != null) {
                echo ">> Aborting older build #${previousBuild.number}"
                executor.interrupt(Result.ABORTED, new UserInterruption(
                    "Aborted by newer build #${currentBuild.number}"
                ))
            }
        }

        previousBuild = previousBuild.getPreviousBuildInProgress()
    }
}

Ответ 5

Благодаря безопасности сценариев Jenkins многие решения здесь становятся трудными, поскольку они используют методы, не включенные в белый список.

С этими важными шагами в начале Jenkinsfile это работает для меня:

def buildNumber = env.BUILD_NUMBER as int
if (buildNumber > 1) milestone(buildNumber - 1)
milestone(buildNumber)

Результат здесь будет:

  • Build 1 работает и создает веху 1
  • В то время как сборка 1 работает, строить 2 огня. Он имеет этап 1 и этап 2. Он проходит этап 1, что приводит к прерыванию сборки # 1.

Ответ 6

Я также скомпилировал версию из ранее приведенных с некоторыми незначительными изменениями:

  • цикл while() генерирует несколько выходов для каждой сборки
  • UserInterrupt в настоящее время ожидает userId вместо строки аргумента и нигде не будет отображать строку аргумента. Поэтому это просто обеспечивает userId
def killOldBuilds(userAborting) {
    def killedBuilds = []
    while(currentBuild.rawBuild.getPreviousBuildInProgress() != null) {
        def build = currentBuild.rawBuild.getPreviousBuildInProgress()
        def exec = build.getExecutor()

        if (build.number != currentBuild.number && exec != null && !killedBuilds.contains(build.number)) {
            exec.interrupt(
                    Result.ABORTED,
                    // The line below actually requires a userId, and doesn't output this text anywhere
                    new CauseOfInterruption.UserInterruption(
                            "${userAborting}"
                    )
            )
            println("Aborted previous running build #${build.number}")
            killedBuilds.add(build.number)
        }
    }
}

Ответ 7

Есть ли способ прервать сборку только из одной данной ветки и позволить другим сборкам из другой ветки работать на одном и том же задании. Например, допустим, у меня есть Branch1 и Branch2, работающие в задании. Я хочу иметь возможность прервать всю текущую сборку из Branch1, кроме самой последней, в то же время Branch2 начинает выполнять сборку, и я хочу, чтобы Branch2 могла выполнять их сборку, поскольку это другая ветвь. Является ли это возможным?

Уточнить; У нас много ветвей, поэтому мы не можем просто предотвратить одновременные сборки, отменить последнюю, как только начнется следующая, и т.д. Какой бы метод ни использовался, он должен специально проверять, работает ли для него ветвь, а не задание вообще, уже бежит. Запуск кода выполняется системой Groovy в Jenkins.

import hudson.model.Result
import jenkins.model.CauseOfInterruption
import groovy.transform.Field
import jenkins.model.*

build.getProject()._getRuns().iterator().each{ run ->
def exec = run.getExecutor()

 //from each run get the branch_name and put it into the list, add it to the list
 def branchName = build.environment.get("GIT_BRANCH")
 def list = []
 list.add(branchName)

  for (i = 0; i <list.size(); i++) {
  if( run!=build && exec!=null && branchName == list[i]){

  exec.interrupt(Result.ABORTED)  

 }
 }
 }