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

dav*_*rez 33 jenkins jenkins-pipeline

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

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

stage('foo') {
   ...
}
Run Code Online (Sandbox Code Playgroud)

我见过这个例子,但我没有使用声明性语法.

dav*_*rez 23

使用脚本化语法,该语法允许比声明性语法更灵活,即使声明更详细和推荐.

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

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

  • 这似乎不起作用。你能提供一个完整的例子吗?从我不理解的角度来看,我们需要创建一个Pipeline项目,然后该代码段不起作用... (2认同)

Ant*_*nko 22

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

def list
pipeline {
    agent none
    options {buildDiscarder(logRotator(daysToKeepStr: '7', numToKeepStr: '1'))}
    stages {
        stage('Create List') {
            agent {node 'nodename'}
            steps {
                script {
                    // you may create your list here, lets say reading from a file after checkout
                    list = ["Test-1", "Test-2", "Test-3", "Test-4", "Test-5"]
                }
            }
            post {
                cleanup {
                    cleanWs()
                }
            }
        }
        stage('Dynamic Stages') {
            agent {node 'nodename'}
            steps {
                script {
                    for(int i=0; i < list.size(); i++) {
                        stage(list[i]){
                            echo "Element: $i"
                        }
                    }
                }
            }
            post {
                cleanup {
                    cleanWs()
                }
            }
        }
    }
}

Run Code Online (Sandbox Code Playgroud)

这将导致: 动态顺序阶段

  • 非常感谢,伙计!作为 `for (...) {` 的替代方案,我可以使用 `list.each { listItem -&gt;`。我认为对于那些碰巧需要索引的人来说,“list.eachWithIndex { listItem, i -&gt;”也可以工作。 (2认同)

Aar*_*sco 14

你可能想看看这个例子 - 你可以让一个函数返回一个闭包,它应该能够有一个阶段.

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

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
Run Code Online (Sandbox Code Playgroud)

  • @Aaron,创建数组后,如何才能不并行运行它? (2认同)

小智 11

@Jorge Machado:因为我无法发表评论,所以我不得不将其作为答案发布.我最近解决了.我希望它能帮到你.

声明性管道:

一个简单的静态示例:

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

                        echo('new one echo')

                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

动态现实生活中的例子:

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

}
Run Code Online (Sandbox Code Playgroud)

  • 感谢您发布此信息!我没有像我应该的那样关注你的回应,因为内部阶段定义中缺少“步骤”块非常重要。希望这可以帮助那些只是略读而不是真正阅读的人:) (6认同)

Krz*_*cki 9

只是对@np2807@Anton Yurchenko已经提出的内容的补充:您可以动态创建阶段并通过简单地延迟阶段创建列表(但保留其声明)来并行运行,例如:

def parallelStagesMap

def generateStage(job) {
    return {
        stage("stage: ${job}") {
                echo "This is ${job}."
        }
    }
}
 
pipeline {
    agent { label 'master' }
 
    stages {
        stage('Create List of Stages to run in Parallel') {
            steps {
                script {
                    def list = ["Test-1", "Test-2", "Test-3", "Test-4", "Test-5"]
                    // you may create your list here, lets say reading from a file after checkout
                    // personally, I like to use scriptler scripts and load the as simple as:
                    // list = load '/var/lib/jenkins/scriptler/scripts/load-list-script.groovy'
                    parallelStagesMap = list.collectEntries {
                        ["${it}" : generateStage(it)]
                    }
                }
            }
        }
 
        stage('Run Stages in Parallel') {
            steps {
                script {
                    parallel parallelStagesMap
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这将导致动态并行阶段: 动态并行阶段管线图


np2*_*807 8

如果您不想使用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
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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
                }
            }
        }        
    }
}
Run Code Online (Sandbox Code Playgroud)

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

请记住return在功能上generateStage是必须的。