Jenkins - прекратите работу, если новый
Я использую Jenkins и Multibranch Pipeline. У меня есть работа для каждой активной ветки git.
Новая сборка запускается нажатием в репозитории git. Я хочу, чтобы прервать запущенные сборки в текущей ветке, если новая одна появляется в одной ветки.
Например: я фиксирую и нажимаю на ветвь feature1
. Тогда BUILD_1
началось в Дженкинсе. Я делаю еще одну фиксацию и нажимаю на ветвь feature1
, пока BUILD_1
все еще работает. Я хочу BUILD_1
прерваться и начать BUILD_2
.
Я попытался использовать параметр stage concurrency=x
и stage-lock-milestone, но мне не удалось решить мою проблему.
Также я прочитал эту тему Остановить работу Jenkins в случае запуска более новой версии, но для моей проблемы нет решения.
Знаете ли вы какое-либо решение?
Ответы
Ответ 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)
}
}
}