web-dev-qa-db-fra.com

Jenkins Build Pipeline - Redémarrer à l'étape

J'ai le pipeline de build suivant configuré en tant que travail:

Stage 1 - verify all dependencies exist
Stage 2 - build the new jar
Stage 3 - Run integration tests
Stage 4 - Deploy to staging environment (manual step)
Stage 5 - Deploy to production environment (manual step)

Je cherche un moyen de démarrer le pipeline de construction à partir d'une étape particulière en cas de défaillance transitoire. Par exemple, supposons qu'il y ait eu un problème de réseau lorsque l'utilisateur a cliqué pour se déployer en production. Je ne pense pas qu'il soit logique de démarrer le pipeline à partir de l'étape 1 ... J'aimerais réessayer cette étape et continuer à partir de là dans le pipeline. Je ne vois aucune fonctionnalité comme celle-ci dans le plugin Build Pipeline.

Merci!!

28
threejeez

Je pense que checkpoint est ce que vous recherchez. Malheureusement, il n'est disponible que dans la suite CloudBees Jenkins Enterprise, pas dans la version gratuite.

Espérons que cela devienne la version open source car il semble que ce soit un cas d'utilisation très courant.

13
tarantoga

Une meilleure solution est une solution similaire à ce que j'ai suggéré dans cette question :

Écrivez un script de pipelining qui a des gardes "if" autour des différentes étapes, comme ceci:

stage "s1"
if (theStage in ["s1"]) {
    sleep 2
}

stage "s2"
if (theStage in ["s1", "s2"]) {
    sleep 2
}

stage "s3"
if (theStage in ["s1", "s2", "s3"]) {
    sleep 2
}

Ensuite, vous pouvez créer un travail "principal" qui utilise ce script et exécute toutes les étapes à la fois en définissant le paramètre "theStage" sur "s1". Ce travail collectera les statistiques lorsque toutes les étapes sont exécutées en même temps et vous donnera des temps d'estimation utiles.

De plus, vous pouvez créer un travail "d'exécution partielle" qui utilise ce script et qui est paramétré avec l'étape avec laquelle vous souhaitez commencer. L'estimation ne sera cependant pas très utile.

8
olenz

Pendant ce temps, de nombreuses autres réponses sont obsolètes, car Jenkins fournit une solution intégrée qui vous permet de redémarrer un travail à partir de n'importe quelle étape: https://jenkins.io/doc/book/pipeline/running-pipelines/ Il s'applique à pipeline déclaratif uniquement via .

8
olenz

Vous pouvez encapsuler votre code dans une étape retry :

stage "Deployment"
retry(3) {
  sh "deploy.."
}

EDIT: Cela pourrait aider dans la version gratuite de Jenkins. Utilisateurs de CloudBees Enterprise , veuillez voir la réponse de @ tarantoga .

4
StephenKing

Un sujet un peu ancien mais comme Jenkins ne le supporte toujours pas (!), J'envoie une autre solution pour les implémentations de pipeline scriptées. Il est basé sur la création dynamique d'une liste d'étapes lors de l'exécution du pipeline.

  1. étape - énumération de définition d'étapes
enum Steps {
  PREPARE(0, "prepare"), 
    BUILD(1, "build"), 
    ANALYSE(2, "analyse"), 
    CHECKQG(3, "checkQG"), 
    PROVISION(4, "provision"), 
    DEPLOY(5, "deploy"), 
    ACTIVATE(6, "activate"), 
    VERIFY(7, "verify"), 
    CLEANUP(8, "cleanup")

  Steps(int id, String name) {
      this.id = id
          this.name = name
  }

  private final int id
    private final String name

  int getId() {
      id
  }

      String getName() {
      name
  }

    public static Steps getByName(String name) {
        println "getting by name " + name
        for(Steps step : Steps.values()) {
          if(step.name.equalsIgnoreCase(name)) { 
              return step 
          }
        }
        throw new IllegalArgumentException()
    }
}
  1. méthode créant la liste des étapes finales
  def prepareStages(def startPoint){
        println "preparing build steps starting from " + startPoint
        Set steps = new LinkedHashSet()
        steps.add(Steps.PREPARE)
        steps.add(Steps.BUILD)
        steps.add(Steps.ANALYSE)
        steps.add(Steps.CHECKQG)
        steps.add(Steps.PROVISION)
        steps.add(Steps.DEPLOY)
        steps.add(Steps.ACTIVATE)
        steps.add(Steps.VERIFY)
        steps.add(Steps.CLEANUP)
        List finalSteps = new ArrayList()
        steps.each{
            step ->
                if (step.id >= startPoint.id) {
                    finalSteps.add(step)
                }
        }
        return finalSteps
    }
  1. et vous pouvez l'utiliser comme ça

def stages = prepareStages (Steps.getByName ("$ {startStage}"))

node {
    try {
        //pipelineTriggers([pollSCM('${settings.scmPoolInterval}')])  //this can be used in future to get rid build hooks 

        sh "echo building " + buildVersionNumber(${settings.isTagDriven})
        tool name: 'mvn_339_jenkins', type: 'maven'

        script {             
            println "running: " + stages
        }

        stage('Prepare') {
            if (stages.contains(Steps.PREPARE)) {
                script { currentStage = 'Prepare' }
               //.....
            }
        } //...

le "startStage" est un paramètre de construction défini comme suit

paramètres {choiceParam ('startStage', ['prepare', 'build', 'analyz', 'checkQG', 'provision', 'deploy', 'activate', 'verify', 'cleanup'], 'Pick up the étape à partir de laquelle vous souhaitez commencer ')}

Cela me permet de choisir l'étape à partir de laquelle je veux démarrer le pipeline (l'étape de préparation est définie par défaut)

3
masala

Voici une autre esquisse pour exécuter les étapes de manière conditionnelle sans casser l'historique du plug-in Stage View.

Comme ils disent :

Stades dynamiques: en général, si vous souhaitez visualiser des stades changeant dynamiquement, rendez-le conditionnel pour exécuter le contenu de la scène, pas conditionnel pour inclure la scène

Voici ce que j'ai trouvé jusqu'à présent. Semble fonctionner principalement: (Ignorez simplement les autres étapes factices)

Nous définissons une petite fonction d'assistance conditionalStage qui enveloppe proprement la vérification du nom de la scène à partir de JP_STAGE Paramètre de travail Jenkins.

Remarquez comment conditionalStage en premier ouvre le stage puis vérifie stageIsActive dans la scène, sautant simplement toutes les étapes. De cette façon, le plugin Stage View voit toutes les étapes et ne gâche pas, mais les étapes des étapes sont toujours ignorées.

def stageSelect = JP_STAGE.toLowerCase()

// test if stage or any of sub-stages is active
def stageIsActive(theStage, theStages) { 
    // echo "pass: $theStages"
    // ARGL: https://issues.jenkins-ci.org/browse/JENKINS-26481
    // def lcStages = theStages.collect {it.toLowerCase()}
    def lcStages = []
    for (def s : theStages) { lcStages += s.toLowerCase() }
    def lcAllStages = lcStages + ['all']
    // echo "check: $lcAllStages"
    // echo JP_STAGE.toLowerCase()
    if (JP_STAGE.toLowerCase() in lcAllStages) {
        echo "Run: Stage '$theStage' is active through '$JP_STAGE'."
        return true
    } else {
        echo "Skip: Stage '$theStage' is NOT active through '$JP_STAGE'."
        return false
    }
}

// 1st element should be the stage, optionally followed by all sub-stages
def conditionalStage(names, stageBody) {
  stage(names[0]) { if (stageIsActive(names[0], names)) {
    stageBody()
  }}  
}

timestamps {
// --S--

conditionalStage(['Intro']) { 
    echo 'Outside Node'

    build job: 'FreeX', wait: true
    sleep 3
}

// --S--
conditionalStage(['AtNode', 'Hello', 'Done']) {
    node {
        // Cloudbees Enterprise Only: checkpoint 'Now'
        conditionalStage(['Hello']) {
            echo 'Hello World @ Node'
            sleep 4
        }
        conditionalStage(['Done']) {
            dir('C:/local') {
                echo pwd()
            }
        }
    }
}

}//timestamps
2
Martin Ba

Ce que vous pourriez faire, c'est de mettre les étapes simples dans des scripts groovy. Ensuite, vous pouvez créer un travail "runAll" qui charge tous les scripts dans le bon ordre et des travaux uniques pour les différentes étapes.

Bien que cela puisse fonctionner, je ne pense pas que ce soit la solution idéale, car cela signifie que vous devez faire attention à la façon dont les différentes étapes échangent des informations, afin que les étapes puissent s'exécuter de manière indépendante.

Une solution intégrée serait bien meilleure.

0
olenz