Jenkinsfile Pipeline DSL:如何在作业仪表板 GUI 中显示多列 - 对于所有动态创建的阶段 - 在 PIPELINE 部分中时
Posted
技术标签:
【中文标题】Jenkinsfile Pipeline DSL:如何在作业仪表板 GUI 中显示多列 - 对于所有动态创建的阶段 - 在 PIPELINE 部分中时【英文标题】:Jenkinsfile Pipeline DSL: How to Show Multi-Columns in Jobs dashboard GUI - For all Dynamically created stages - When within PIPELINE section 【发布时间】:2020-03-12 03:03:37 【问题描述】:Jenkins 2.89.4 滚动
我看到了几乎所有的 *** 帖子,这些帖子展示了我们如何成功地运行并行步骤/阶段(使用列表/地图等)——或者直接对它们进行硬编码——或者甚至为 Jenkinsfile 创建动态阶段(如本文所示:@ 987654321@)
我的要求是:
在“构建”步骤下构建 N 个项目的管道,即在每个项目上并行构建。即它在所有 N 个项目上运行 Gradle。在这里,我有一个由声明性 JOB DSL Groovy 创建的 Jenkinsfile。这里我的 Gradle 项目没有设置为多项目,所以我不能调用*** gradle 说,Gradle 请做你的并行魔法(在 Gradle 内)。
我想在 jenkins 作业的仪表板中看到的 自己单独的并行动态创建阶段(GUI 列) 中运行这 N 个项目的构建。 p>
我想分别查看(Gradle 构建/控制台)每个项目构建的输出,即 我不想混合每个项目构建的控制台输出,它们在只有一列(即名为BUILD
的列)。
在此 URL https://jenkins.io/blog/2017/09/25/declarative-1/ 我明白了,您如何运行并行阶段/步骤,但这样做,要么将这些并行步骤的输出混合在一个列中(我的意思是在 BUILD 列)--或者,如果您希望它在单独的阶段/列下(即帖子说 在 Linux 或 Windows 上测试 单独,那么您就是仍然在 Jenkinsfile 早期硬编码所有阶段/步骤(而不是只使用列表或数组哈希,我更愿意更新它以添加更多或更少的阶段/ 并行步骤,就我而言,它们都遵循相同的标准)。我想要的只是在一个地方更新有多少步骤以及一个地方的所有阶段(列表/数组) )。
我现在不使用Jenkins Blue Ocean。通常,如果您在一个阶段中有并行步骤,则当您单击查看该给定并行步骤/阶段的控制台输出时,所有步骤的控制台标准输出将混合到一个控制台输出/阶段/列中;当您将鼠标悬停在作业仪表板中的 BUILD 列(假设在 BUILD 阶段有并行步骤)时(所有这些步骤的标准输出混合在一起,很难看到单个项目步骤的控制台输出只是为了给定的步骤/阶段)。
如果我们想(动态地)创建单独的阶段,那么 Jenkins 应该能够在并行部分中显示给定步骤/动态阶段的控制台输出(即,每一列都应该显示他们自己项目的构建控制台输出)。
使用上面的URL,我可以在尝试这个脚本后执行以下操作:
// main script block
// could use eg. params.parallel build parameter to choose parallel/serial
def runParallel = true
def buildStages
node('master')
stage('Initializing Parallel Dynamic Stages')
// Set up List<Map<String,Closure>> describing the builds
buildStages = prepareBuildStages()
println("Initialised pipeline.")
for (builds in buildStages)
if (runParallel)
parallel(builds)
else
// run serially (nb. Map is unordered! )
for (build in builds.values())
build.call()
stage('Done')
println('The whole SHENZI is complete.')
// Create List of build stages to suit
def prepareBuildStages()
def buildList = []
for (i=1; i<4; i++)
def buildStages = [:]
for (name in [ 'Alpha', 'Tango', 'Chyarli' ] )
def n = "$name $i"
buildStages.put(n, prepareOneBuildStage(n))
buildList.add(buildStages)
return buildList
def prepareOneBuildStage(String name)
def proj_name = name.split(' ')[0]
def proj_parallel_sub_step = name.split(' ')[1]
//Return the whole chunkoni
return
stage("Build\nProject-$proj_name\nStep $proj_parallel_sub_step")
println("Building $proj_name - $proj_parallel_sub_step")
sh(script:'sleep 15', returnStatus:true)
当我将上述 Groovy 脚本(用于创建 DYNAMIC 阶段)放入 Pipeline Script
或 Pipeline Script from SCM
(即 .groovy 文件中的相同代码)时,它会成功运行并在 BUILD 下创建动态阶段为 3 个项目中的每一个项目执行步骤,并为所有 3 个项目并行运行 3 个步骤(第 N 个),然后为所有 3 个项目开始下一个第 N 个步骤,依此类推。
如果您在下面看到,我们还在 Jenkins 作业仪表板中为他们提供了单独的列。
现在,当我将上述脚本放入 Jenkinsfile (Pipeline DSL) 我有 pipeline ....
部分时,它不起作用并给我以下错误。
使用我的 JOB DSL,我创建了一个新的 Jenkins 管道作业,其中 Pipeline Script from SCM
调用了一个 groovy 文件(现在包含):
//----------------------------------------------------
// Both - Parallel Run and GUI View in JF Jenkins job.
//----------------------------------------------------
def runParallel = true
def buildStages
def wkspace = /var/lib/jenkins/workspaces/ignore_this_variale_or_its_value_for_now
// Create List of build stages to suit
def prepareBuildStages()
def buildList = []
for (i=1; i<3; i++)
def buildStages = [:]
for (name in [ 'Alpha', 'Tango', 'Chyarli' ] )
def n = "$name $i"
buildStages.put(n, prepareOneBuildStage(n))
buildList.add(buildStages)
return buildList
//---
def prepareOneBuildStage(String name)
def proj_name = name.split(' ')[0]
def proj_parallel_sub_step = name.split(' ')[1]
// return the whole chunkoni (i.e. for a given stage) - will be named dynamically.
return
stage("Build\nProject-$proj_name\nStep $proj_parallel_sub_step")
println("Building $proj_name - $proj_parallel_sub_step")
sh(script:'sleep 15', returnStatus:true)
// Set up List<Map<String,Closure>> describing the builds
buildStages = prepareBuildStages()
//---------------------
String jenkinsBaselines
// SEE NOW --- we have this section called 'pipeline'
pipeline
agent
node
label 'rhat6'
customWorkspace wkspace
options
ansiColor('xterm')
timeout(time: 8, unit: 'HOURS')
skipDefaultCheckout()
timestamps()
environment
someEnvVar = 'aValue'
//------------- Stages
stages
stage('Initializing Parallel Dynamic Stages')
// Set up List<Map<String,Closure>> describing the builds
println("Initialised pipeline.")
for (builds in buildStages)
if (runParallel)
parallel(builds)
else
// run serially (nb. Map is unordered! )
for (build in builds.values())
build.call()
stage('Done')
println('The whole SHENZI is complete.')
//---------------------
运行 Jenkinsfile Jenkins 作业现在给我这个错误:
[BFA] Scanning build for known causes...
[BFA] No failure causes found
[BFA] Done. 1s
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 69: Not a valid stage section definition: "buildStages = prepareBuildStages()". Some extra configuration is required. @ line 69, column 5.
stage('Initializing Parallel Dynamic Stages')
^
WorkflowScript: 69: Unknown stage section "println". Starting with version 0.5, steps in a stage must be in a steps block. @ line 69, column 5.
stage('Initializing Parallel Dynamic Stages')
^
WorkflowScript: 75: Expected a stage @ line 75, column 5.
for (builds in buildStages)
^
WorkflowScript: 86: Unknown stage section "println". Starting with version 0.5, steps in a stage must be in a steps block. @ line 86, column 5.
stage('Done')
^
WorkflowScript: 69: No "steps" or "parallel" to execute within stage "Initializing Parallel Dynamic Stages" @ line 69, column 5.
stage('Initializing Parallel Dynamic Stages')
^
WorkflowScript: 86: No "steps" or "parallel" to execute within stage "Done" @ line 86, column 5.
stage('Done')
^
6 errors
at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:310)
at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1085)
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:603)
at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:581)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:558)
at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.doParse(CpsGroovyShell.java:133)
at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:127)
at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:557)
at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:518)
at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:290)
at hudson.model.ResourceController.execute(ResourceController.java:97)
at hudson.model.Executor.run(Executor.java:429)
Finished: FAILURE
我怎样才能在 Jenkinsfile pipeline
部分中运行它,并且仍然能够为给定项目 N 和步骤 M 获取每个动态创建的阶段的各个列?
尝试了下面的方式,还是错误的说方式。
//------------- Stages
stages
stage('Initializing Parallel Dynamic Stages')
// Set up List<Map<String,Closure>> describing the builds
buildStages = prepareBuildStages()
println("Initialised pipeline.")
// tried this way too. within a stage
buildStages.each bld -->
parallel(bld)
stage('Done')
println('The whole SHENZI is complete.')
//---------------------
【问题讨论】:
【参考方案1】:所以我对此进行了一些研究并让它发挥了作用。
Jenkinsfile 中的新代码(用于STAGES)现在是:
//------------- Stages
stages
stage('Start Pipeline')
steps
script
sh "echo HELLO moto razr!"
stage('Initializing Parallel Dynamic Stages')
steps
script
// Run all Nth step for all Projects in Parallel.
buildStages.each bs -> parallel(bs)
// OR uncomment the following code (if conditional on boolean variable).
/*
for (builds in buildStages)
if (runParallel)
parallel(builds)
else
// run serially (nb. Map is unordered! )
for (build in builds.values())
build.call()
*/
stage('Done')
println('The whole SHENZI is complete.')
//---------------------
这就是工作所需要的一切。
为了清晰的消息/阶段名称,我也调整了函数,我们不会在 pipeline ...
中设置这个变量 buildStages
//---
def prepareOneBuildStage(String name)
def proj_name = name.split(' ')[0]
def proj_parallel_sub_step = name.split(' ')[1]
// return the whole chunkoni (i.e. for a given stage) - will be named dynamically.
return
stage("BUILD Project-$proj_name Parallel_Step_$proj_parallel_sub_step")
println("Parallel_Step # $proj_parallel_sub_step of Project => $proj_name")
sh(script:"echo \"Parallel_Step # $proj_parallel_sub_step of Project => $proj_name\" && sleep 20", returnStatus:true)
// -- OR -- you can call Gradle task i.e. rpm / any other / any other command here.
// Set up List<Map<String,Closure>> describing the builds. section now.
buildStages = prepareBuildStages()
//---------------------
此实现现在正在创建 N 否。 并行阶段,即每个项目有一个单独的列,用于给定的第 N 步(查看 Jenkinsfile 作业的仪表板时)对于 P 号的项目。
-
它将为给定的第 N 步并行运行 所有 P 项目。
它将等待所有项目的第 N 步首先完成,然后跳转到下一个第 N 步。
这意味着,如果 Project ALPHA Step #1 完成,它仍然会等待其他 2 个项目的所有 Step #1,然后并行启动所有项目的 Step #2。
挑战:我们如何让 ALPHA 项目的第 2 步在 ALPHA 项目的第 1 步完成后立即开始,即它不会等待其他 2 个项目的第 1 步完成并且可以可能与其他项目的步骤 N(=1) 或 N+1 并行运行 ALPHA 项目 1 的步骤 #2。
这假设所有项目相互独立,并且项目不共享由给定项目/它们的阶段/步骤在任何其他项目/阶段/步骤中生成的内容。
根据您自己的要求,您可能需要等待(即,在所有项目的第 1 步完全完成之前不要运行所有项目的第 2 步)--或者-- 你可能想运行 第 2 步的 ALPHA 项目让我们说 - 第 2 步的 TANGO 项目 而项目 CHYARLI 的第 1 步仍在进行中。
由于这篇文章的主要范围是为每个项目获取单独的动态创建的列/阶段(在 pipeline ...
部分中并行运行),我想,我得到了我想要的。
注意:如果您想运行管道的并发构建,请轻松使用并行。有关运行parallel
构建操作并发相关问题的更多信息,请参阅此处:Jenkins - java.lang.IllegalArgumentException: Last unit does not have enough valid bits & Gradle error: Task 'null' not found in root project
【讨论】:
以上是关于Jenkinsfile Pipeline DSL:如何在作业仪表板 GUI 中显示多列 - 对于所有动态创建的阶段 - 在 PIPELINE 部分中时的主要内容,如果未能解决你的问题,请参考以下文章
持续集成使用 Jenkinsfile 设计直观的 Pipeline
jenkins-使用Jenkinsfile来定义pipeline
Jenkins Pipeline - 工作流 CPS 插件 JAR 依赖项