我可以在Jenkins管道中创建动态阶段吗?

时间:2017-03-16 14:34:54

标签: jenkins jenkins-pipeline

我需要在声明性管道中启动一组动态测试。 为了更好的可视化目的,我想为每个测试创建一个阶段。 有办法吗?

创建我所知道的舞台的唯一方法是:

stage('foo') {
   ...
}

我见过this example,但我没有使用声明性语法。

7 个答案:

答案 0 :(得分:16)

使用脚本化语法,它允许比声明性语法更灵活,即使声明性更具记录性和推荐性。

例如,可以在循环中创建阶段:

def tests = params.Tests.split(',')
for (int i = 0; i < tests.length; i++) {
    stage("Test ${tests[i]}") {
        sh '....'
    }
}

答案 1 :(得分:11)

你可能想看一下this example - 你可以让一个函数返回一个应该能够在其中有一个阶段的闭包。

此代码显示了该概念,但没有一个阶段。

def transformDeployBuildStep(OS) {
    return {
        node ('master') { 
        wrap([$class: 'TimestamperBuildWrapper']) {
...
        } } // ts / node
    } // closure
} // transformDeployBuildStep

stage("Yum Deploy") {
  stepsForParallel = [:]
  for (int i = 0; i < TargetOSs.size(); i++) {
      def s = TargetOSs.get(i)
      def stepName = "CentOS ${s} Deployment"
      stepsForParallel[stepName] = transformDeployBuildStep(s)
  }
  stepsForParallel['failFast'] = false
  parallel stepsForParallel
} // stage

答案 2 :(得分:7)

@Jorge Machado:因为我无法发表评论,所以我不得不将其发布为答案。我最近已经解决了。希望对您有帮助。

说明性管道:

一个简单的静态示例:

stage('Dynamic') {
        steps {
            script {
                stage('NewOne') {

                        echo('new one echo')

                }
            }
        }
    }

动态真实示例:

    // in a declarative pipeline
        stage('Trigger Building') {
              when {
                environment(name: 'DO_BUILD_PACKAGES', value: 'true')
              }
              steps {
                executeModuleScripts('build') // local method, see at the end of this script
              }
            }


    // at the end of the file or in a shared library
        void executeModuleScripts(String operation) {

          def allModules = ['module1', 'module2', 'module3', 'module4', 'module11']

          allModules.each { module ->  
          String action = "${operation}:${module}"  

          echo("---- ${action.toUpperCase()} ----")        
          String command = "npm run ${action} -ddd"                   

            // here is the trick           
            script {
              stage(module) {
                bat(command)
              }
            }
          }

}

答案 3 :(得分:6)

如果您不想使用 for 循环,并且生成的管道要并行执行,那么这里有一个答案。

def jobs = ["JobA", "JobB", "JobC"]
 
def parallelStagesMap = jobs.collectEntries {
    ["${it}" : generateStage(it)]
}
 
def generateStage(job) {
    return {
        stage("stage: ${job}") {
                echo "This is ${job}."
        }
    }
}
 
pipeline {
    agent none
 
    stages {
        stage('non-parallel stage') {
            steps {
                echo 'This stage will be executed first.'
            }
        }
 
        stage('parallel stage') {
            steps {
                script {
                    parallel parallelStagesMap
                }
            }
        }
    }
}

Note 表示所有生成的阶段都将在 1 个节点中执行。 如果您愿意将生成的阶段执行到不同的节点中。

def agents  = ['master', 'agent1', 'agent2']
// enter valid agent name in array.

def generateStage(nodeLabel) {
    return {
        stage("Runs on ${nodeLabel}") { 
            node(nodeLabel) {
                echo "Running on ${nodeLabel}"
            }
        }
    }
}
def parallelStagesMap = agents.collectEntries {
    ["${it}" : generateStage(it)]
}
pipeline {
    agent none
    stages {
        stage('non-parallel stage') {
            steps {
                echo 'This stage will be executed first.'
            }
        }

        stage('parallel stage') {
            steps {
                script {
                    parallel parallelStagesMap
                }
            }
        }        
    }
}

您当然可以添加 1 个以上的参数,并且可以将 collectEntries 用于 2 个参数。

请记住 return 函数中的 generateStage 是必须的。

答案 4 :(得分:2)

我用它来生成包含Jenkins作业的舞台。 build_list是我想要从我的主Jenkins作业触发的Jenkins作业列表,但是为每个触发的作业都有一个阶段。

build_list = ['job1', 'job2', 'job3']
        for(int i=0; i < build_list.size(); i++) {
          stage(build_list[i]){
               build job: build_list[i], propagate: false
          }
        }

答案 5 :(得分:0)

如JamesD所建议的那样,您可以像这样动态创建阶段(但它们将是顺序的):

<h:panelGrid id="packcapacityinfo" columns="2">
    <h:outputText value="Capacity:"/>
    <p:spinner value="#{penPackBackingBean.packCapacity}" min="1" max="50">
        <p:ajax event="change" update="@this,packcapacityinfo"/>
    </p:spinner>
    <h:outputText value="Allowed Broken Pens:"/>
    <p:spinner value="#{penPackBackingBean.generalAllowedBrokenPens}" min="0" max="#{penPackBackingBean.packCapacity}">
        <p:ajax event="change" update="@this,packcapacityinfo"/>
    </p:spinner>
    <h:outputText value="Maximum Allowed Broken Pens:"/>
    <p:spinner value="#{penPackBackingBean.maxAllowedBrokenPens}" min="#{penPackBackingBean.generalAllowedBrokenPens}" max="#{penPackBackingBean.packCapacity}">
        <p:ajax event="change" update="@this,packcapacityinfo"/>
    </p:spinner>
</h:panelGrid>

这将导致: dynamic-sequential-stages

答案 6 :(得分:0)

如果您使用的是Jenkinsfile,则可以通过动态创建阶段,并行运行它们以及让Jenkinsfile UI显示单独的列来实现。这假设并行步骤彼此独立(否则不要使用并行),并且您可以将它们嵌套到所需的深度(取决于要嵌套以创建阶段的for循环的数目)。

Jenkinsfile Pipeline DSL: How to Show Multi-Columns in Jobs dashboard GUI - For all Dynamically created stages - When within PIPELINE section有关更多信息,请参见此处。