web-dev-qa-db-fra.com

Jenkins - abandonne la construction en cours si une nouvelle est démarrée

J'utilise Jenkins et Multibranch Pipeline. J'ai un travail pour chaque branche git active .. La nouvelle construction est déclenchée par le dépôt Push in git. Ce que je veux, c'est abandonner les constructions en cours dans la branche actuelle si une nouvelle apparaît dans la même branche. 

Par exemple: je commets et Push to branch feature1. Alors BUILD_1 a commencé à Jenkins. Je fais un autre commit et Push to branch feature1 alors que BUILD_1 est toujours en cours d'exécution. Je veux que BUILD_1 soit abandonné et que je commence BUILD_2

J'ai essayé d'utiliser l'option stage concurrency=x et stage-lock-milestone feature, mais je n'ai pas réussi à résoudre mon problème.

J'ai aussi lu ce fil Arrêter le travail de Jenkins au cas où un nouveau poste serait lancé , mais il n'y a pas de solution à mon problème.

Connaissez-vous une solution à cela?

18
kakty3

activer le travail en parallèle pour votre projet avec Execute concurrent builds if necessary 

utilisez execute system groovy script comme première étape de construction:

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

et dans les travaux interrompus, il y aura un journal:

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

Si quelqu'un en a besoin dans Jenkins Pipeline Multibranch, vous pouvez le faire dans Jenkinsfile comme ceci:

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

Le faire fonctionner en ayant le script suivant dans la bibliothèque partagée globale:

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

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

Et en l'appelant dans mon pipeline:

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

Edit: En fonction de la force avec laquelle vous souhaitez supprimer oldBuild, vous pouvez utiliser doStop (), doTerm () ou doKill ()!

6
C4stor

Sur la base de l’idée de @ C4stor, j’ai réalisé cette version améliorée ... Je la trouve plus lisible depuis la version de @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()
    }
}
2
Stefanos Kalantzis