it-swarm.com.de

Jenkins - bricht den laufenden Build ab, wenn ein neuer gestartet wird

Ich benutze Jenkins und Multibranch Pipeline. Ich habe einen Job für jeden aktiven Git-Zweig .. _. Der neue Build wird durch Push-in-Git-Repository ausgelöst. Ich möchte laufende Builds im aktuellen Zweig abbrechen, wenn ein neuer im selben Zweig erscheint. 

Zum Beispiel: Ich übergebe mich und drücke Push to Branch feature1. Dann begann BUILD_1 in Jenkins. Ich mache ein weiteres Commit und Push to Branch feature1, während BUILD_1 noch läuft. Ich möchte, dass BUILD_1 abgebrochen wird und BUILD_2 startet. 

Ich habe versucht, die stage concurrency=x-Option und die Funktion stage-lock-milestone zu verwenden, konnte das Problem jedoch nicht lösen.

Ich habe auch diesen Thread gelesen Jenkins Job wurde angehalten, falls ein neuer gestartet wird , aber es gibt keine Lösung für mein Problem.

Kennen Sie eine Lösung dafür?

18
kakty3

Mit Jenkins Skriptsicherheit werden viele der hier beschriebenen Lösungen schwierig, da sie Methoden ohne Whitelist verwenden.

Mit diesen Meilensteinschritten zu Beginn des Jenkinsfile funktioniert das für mich:

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

Das Ergebnis wäre hier:

  • Build 1 wird ausgeführt und Meilenstein 1 erstellt
  • Während Build 1 ausgeführt wird, werden Build 2-Brände ausgelöst. Es hat Meilenstein 1 und Meilenstein 2. Es besteht Meilenstein 1, wodurch Build 1 abgebrochen wird.
12

Aktivieren Sie den Job-Parallellauf für Ihr Projekt mit Execute concurrent builds if necessary

verwenden Sie execute system groovy script als ersten Erstellungsschritt:

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

und in den unterbrochenen Aufträgen wird ein Protokoll angezeigt:

Build was aborted
interrupted by build #12
Finished: ABORTED 
12
daggett

Wenn jemand es in Jenkins Pipeline Multibranch benötigt, kann dies in Jenkinsfile wie folgt durchgeführt werden:

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}")
    }
  }
}
11
midN

Um es zu funktionieren, haben Sie das folgende Skript in der Global Shared Library:

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

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

Und ich nenne es in meiner Pipeline:

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

Edit: Abhängig davon, wie stark Sie oldBuild beenden möchten, können Sie doStop (), doTerm () oder doKill () verwenden!

6
C4stor

Basierend auf der Idee von @ C4stor habe ich diese verbesserte Version erstellt ... Ich finde sie aus @daggett's Version lesbarer

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

Ich habe auch eine Version aus den zuvor gegebenen mit ein paar kleinen Verbesserungen zusammengestellt:

  • die while() -Schleife erzeugte mehrere Ausgaben für jeden Build
  • die Benutzerunterbrechung erwartet derzeit eine Benutzer-ID anstelle einer Argumentationszeichenfolge und zeigt nirgendwo eine Argumentationszeichenfolge an. Daher wird hier nur die Benutzer-ID angegeben
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)
        }
    }
}
0

Gibt es eine Möglichkeit, den Build nur für einen bestimmten Zweig abzubrechen und anderen Builds aus einem anderen Zweig die Ausführung für denselben Job zu ermöglichen? Angenommen, Branch1 und Branch2 werden in einem Job ausgeführt. Ich möchte in der Lage sein, alle aktuell ausgeführten Builds von Branch1 abzubrechen, mit Ausnahme des letzten. Gleichzeitig startet Branch2 die Ausführung eines Builds und Branch2 soll in der Lage sein, ihren Build auszuführen, da es sich um einen anderen Zweig handelt. Ist es möglich?

Um klarzustellen; Wir haben viele Zweige, daher können wir nicht nur gleichzeitige Builds verhindern, den letzten abbrechen, sobald der nächste startet usw. Unabhängig von der verwendeten Methode muss speziell geprüft werden, ob in dem Zweig bereits ein Job ausgeführt wird, und nicht, ob der Job im Allgemeinen ausgeführt wird. ist bereits gestartet. Das Ausführen des Codes ist in Jenkins ein grooviges System.

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)  

 }
 }
 }
0
mmm20