运行 与 Jenkins 声明式管道中的矩阵并行的非矩阵阶段

Running non-matrix stages in parallel to a matrix in Jenkins declarative-pipeline

我正在转换我们的企业构建,以便它使用 'matrix' 指令 (https://www.jenkins.io/blog/2019/11/22/welcome-to-the-matrix/),但在优化它时遇到了问题。在 pre-matrix 世界中,我们有一个构建步骤(生成 jar),然后是并行的 'package' 步骤(生成 linux 和 windows 发行版),本质上是 'system test' 阶段(在各种 JVM 上执行 windows 和 linux 发行版),我们在打包和系统测试阶段并行进行一些 'code quality' 检查。

其中大部分似乎适合使用 'matrix'。因此,'packaging' 显然是用于制作 windows 和 linux 平台的矩阵。而'system test'又是一个platform和jvm的双轴矩阵。我可以轻松地使一个矩阵跟随另一个矩阵。到目前为止,还不错。

但是,我坚持认为 'code quality' 是异常值。有没有办法 运行 那些平行于矩阵 运行 的阶段。一旦创建构建,它们就是独立的(它们不需要等待打包)。它们也很耗时,因此 运行 将它们与两个矩阵相串联会使构建时间更长。如果将矩阵放入并行阶段,Jenkins 会抱怨。

关于如何 运行 非矩阵阶段与矩阵并行的任何想法?

我有一个 work-around 我自己的问题。

根据文档 (https://www.jenkins.io/doc/book/pipeline/syntax/#declarative-matrix),我所寻找的是不可能的。 “矩阵中的每个单元格都可以包含一个或多个阶段 运行 按顺序使用该单元格的配置。请注意,一个阶段必须具有且只有一个步骤、阶段、并行或矩阵。它不是如果阶段指令嵌套在并行或矩阵块本身中,则可以在阶段指令中嵌套并行或矩阵块。"

但是....你可以作弊。我能够将矩阵变成一个通用的调度队列。即每个组合调用 N 个阶段 - 对我来说,2 我称它们为“准备”和“执行”。我传递了一个额外的“matrixtype”参数。matrixtype 为矩阵本身获取 1 个值,以及为 non-matrix 的每一行获取附加值。然后我使用矩阵 'excludes' 来确保 non-matrix 行只执行一次。实际上,这将非矩阵折叠成按矩阵类型区分的矩阵。

Original (parallel-stages in series with a subsequent matrix)
    stage {
        parallel {
           stage("alpha") {
                alpha(..)
           }
           stage("beta") {
               beta(..)
           }
           // etc
       }
    }
    stage {
        matrix {
            axes {
                axis {
                    name 'ORIGAXIS'
                    values 'FOO','BAR','BAZ'
                }
            }
            stages {
               stage("First") {
                  originalFirst( ...)
               }
               stage("Second") {
                  originalSecond(...)
               }
            }
         }
      }

Replacement (parallel folded into matrix)
    stage {
        matrix {
            axes {
                axis {
                    name 'MATRIXTYPE
                    values 'ORIGINAL', 'ALPHA', 'BETA'
                axis {
                    name 'ORIGAXIS'
                    values 'FOO','BAR','BAZ'
                }
                excludes {
                    // Execute Alpha and Beta only once (during 'FOO')
                    exclude {
                        axis {
                            name 'MATRIXTYPE'
                            values 'ALPHA', 'BETA'
                        }
                        axis {
                            name 'ORIGAXIS'
                            values 'BAR','BAZ'
                        }
                    }
                }
            }
            stages {
               stage("First") {
                  dispatchFirst( "${MATRIXTYPE}", ...)
               }
               stage("Second") {
                  dispatchSecond( "${MATRIXTYPE}", ...)
               }
            }
         }
      }

dispatchFirst(..) 和 dispatchSecond(..) 是共享库中检查矩阵类型并调用 originalFirst(..)、originalSecond(..)、alpha(..) 的简单调度方法, beta(..) 或 no-op 视情况而定。它有点笨拙,相当于将并行阶段硬塞进矩阵,但它确实有效。而且,您可以获得并行化的好处 (build speed-optimization)

希望以后能有更优雅的东西

我想出了一个有点恕我直言的“更好”的解决方案:

stage {
    matrix {
        axes {
            axis {
                name 'ORIGAXIS'
                values 'ALPHA','BETA','BAR','BAZ'
            }
        }
        stages {
           stage ("alpha") {
               when { expression { env.ORIGAXIS == "ALPHA" } }
               steps {
                   alpha()
               }           
           stage ("beta") {
               when { expression { env.ORIGAXIS == "BETA" } }
               steps {
                   beta()
               }
           }
           stage ("Tests") {
               when { allOf
                   expression { env.ORIGAXIS != "ALPHA" }
                   expression { env.ORIGAXIS != "BETA" }
               }
               stages {
                   stage("First") {
                      originalFirst( ...)
                    }
                   stage("Second") {
                      originalSecond(...)
                   }
                }
            }
     }
}

当然,最终的布局并不完美。但是,它有效,没有那么麻烦并且仍然易于维护。