Jenkins构建管道 - 在阶段重新启动

时间:2016-06-30 17:27:51

标签: jenkins jenkins-workflow jenkins-pipeline

我将以下构建管道设置为作业:

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)

我正在寻找一种方法,以便在发生瞬态故障时从特定阶段启动构建管道。例如,假设用户单击以部署到生产时出现网络问题。我不认为从第1阶段启动管道是有意义的......我想再次尝试这一步并继续从那里开始。我没有在Build Pipeline Plugin中看到这样的任何功能。

谢谢!

7 个答案:

答案 0 :(得分:12)

我认为checkpoint正是您所寻找的。不幸的是,它仅适用于CloudBees Jenkins Enterprise套件,而不是免费版本。

让我们希望它成为开源版本,因为它似乎是一个非常常见的用例。

答案 1 :(得分:8)

更好的解决方案是类似于我在this question中建议的解决方案:

编写一个流水线脚本,其中包含" if" -guards围绕单个阶段,如下所示:

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
}

然后你可以制作一个" main"使用此脚本并通过设置参数" theStage"一次运行所有阶段的作业到" s1"。这项工作将在所有阶段一次运行时收集统计数据,并为您提供有用的估计时间。

此外,您可以进行"部分运行"使用此脚本并使用您要开始的阶段进行参数化的作业。但估计不会很有用。

答案 2 :(得分:4)

同时,其他所有答案都已过时,因为Jenkins提供了内置的解决方案,可让您从任何阶段重新启动作业:https://jenkins.io/doc/book/pipeline/running-pipelines/

答案 3 :(得分:3)

您可以将代码包装在retry步骤中:

a

编辑:这可能有助于Jenkins的免费版本。 CloudBees Enterprise 的用户,请参阅 @tarantoga 的回答。

答案 4 :(得分:2)

这是另一个有条件地运行阶段而不破坏Stage View插件历史的草图。

作为they say

  

动态阶段:通常,如果要动态可视化   改变阶段,使其有条件执行阶段内容,   没有条件包括阶段

这是我到目前为止所提出的。似乎主要工作:(只是忽略其他虚拟步骤)

我们定义了一个小conditionalStage辅助函数,它整齐地包装了JP_STAGE Jenkins Job参数中的阶段名称检查。

注意conditionalStage 首先如何打开stage然后检查阶段中的stageIsActive,只是跳过所有步骤。这样,舞台视图插件可以看到所有阶段并且不会搞砸,但阶段的步骤仍然会被跳过。

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

答案 5 :(得分:2)

有点老话题,但由于Jenkins仍然(!)不支持这个,我正在为脚本管道实现发送另一个解决方案。 它基于运行管道时动态构建阶段列表。

  1. 步骤 - 阶段定义枚举
  2. 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. 创建最终步骤列表的方法
    2.   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. 你可以像这样使用它
      2. def阶段= 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' }
                       //.....
                    }
                } //...
        

        “startStage”是一个构建参数,定义如下

        参数{                     choiceParam('startStage',[                             '准备',                             '建立',                             '分析',                             'checkQG',                             '规定',                             '部署',                             '启用',                             '校验',                             '清理'                     ],'拿起你想要开始的舞台')                 }

        这允许我从我想要启动管道的阶段(默认设置准备阶段)

答案 6 :(得分:0)

您可以做的是将单个步骤放入groovy脚本中。然后你可以制作一个“runAll” - 按正确顺序加载所有脚本的工作,以及不同步骤的单个作业。

虽然这是一种应该有效的方法,但我认为这不是理想的解决方案,因为这意味着您必须注意不同步骤如何交换信息,以便步骤可以独立运行。

内置解决方案会好得多。