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

efzxgjgh  于 2023-06-21  发布在  Jenkins
关注(0)|答案(8)|浏览(169)

我需要在声明性管道中启动一组动态测试。为了更好的可视化,我想为每个测试创建一个阶段。有办法吗?
我所知道的创造舞台的唯一方法是:

stage('foo') {
   ...
}

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

j5fpnvbx

j5fpnvbx1#

使用比声明式语法更灵活的脚本化语法,即使声明式更有文档化和推荐使用。
例如,可以在循环中创建阶段:

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

aydmsdu92#

正如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()
                }
            }
        }
    }
}

这将导致:dynamic-sequential-stages

hm2xizp9

hm2xizp93#

如果你不想使用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个参数。
请记住,generateStage函数中的return是必须的。

xwbd5t1u

xwbd5t1u4#

@Jorge马查多:因为我不能发表评论,我不得不把它作为一个答案。我最近解决了。希望能帮到你。
声明性管道:
一个简单的静态示例:

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

}
oaxa6hgo

oaxa6hgo5#

你可能想看看this example--你可以让一个函数返回一个闭包,这个闭包 * 应该 * 能够在里面有一个stage。
这段代码显示了这个概念,但其中没有stage。

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
y0u0uwnf

y0u0uwnf6#

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

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

这将导致动态并行阶段:

1dkrff03

1dkrff037#

我用它来生成我的阶段,其中包含一个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
          }
        }
vawmfj5a

vawmfj5a8#

如果你正在使用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查看更多。

相关问题