在Jenkins声明性管道中与矩阵并行运行非矩阵阶段

在Jenkins声明性管道中与矩阵并行运行非矩阵阶段,jenkins,jenkins-declarative-pipeline,Jenkins,Jenkins Declarative Pipeline,我正在转换我们的企业构建,以便它使用“矩阵”指令(),但在优化它时遇到了困难。在pre-matrix世界中,我们有一个构建步骤(生成JAR),然后是一个并行的“包”步骤(生成linux和windows发行版),基本上是一个“系统测试”阶段(在各种JVM上执行windows和linux发行版),我们在包和系统测试阶段并行地执行一些“代码质量”检查 其中大部分似乎适合使用“矩阵”。因此,“打包”显然是一个矩阵,用于构建windows和linux平台。“系统测试”是平台和jvm的另一个双轴矩阵。我可以

我正在转换我们的企业构建,以便它使用“矩阵”指令(),但在优化它时遇到了困难。在pre-matrix世界中,我们有一个构建步骤(生成JAR),然后是一个并行的“包”步骤(生成linux和windows发行版),基本上是一个“系统测试”阶段(在各种JVM上执行windows和linux发行版),我们在包和系统测试阶段并行地执行一些“代码质量”检查

其中大部分似乎适合使用“矩阵”。因此,“打包”显然是一个矩阵,用于构建windows和linux平台。“系统测试”是平台和jvm的另一个双轴矩阵。我可以很容易地让一个矩阵跟随另一个矩阵。到目前为止,一切顺利

然而,我一直把“代码质量”作为离群值。是否有一种方法可以使这些阶段与矩阵运行并行运行。创建构建后,它们是独立的(不需要等待打包)。它们也很耗时,所以在两个矩阵阶段连续运行它们会延长构建时间。詹金斯抱怨说,如果你把一个矩阵放在一个平行的阶段


关于如何与矩阵并行运行非矩阵阶段,有什么想法吗?

我有一个解决我自己问题的办法

根据文档()我要找的是不可能的。“矩阵中的每个单元格都可以包括一个或多个要使用该单元格的配置顺序运行的阶段。请注意,一个阶段必须有且只能有一个步骤、阶段、并行或矩阵。如果该阶段指令嵌套在并行或矩阵块中,则无法在该阶段指令中嵌套并行或矩阵块。”自我。”

但是。。。。你可以作弊。我能够将矩阵转换为通用调度队列。i、 每个组合调用N个阶段——对我来说,2个阶段,我称它们为“准备”和“执行”。我在中传递了一个附加的“matrixtype”参数。matrixtype为矩阵本身获取1个值,并为非矩阵的每行获取附加值。然后我使用矩阵“excludes”来确保非矩阵行只执行一次。有效地,这将非矩阵折叠成按矩阵类型区分的矩阵

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(..)是共享库中的简单分派方法,它们检查matrixtype,并根据需要调用originalFirst(..)、originalSecond(..)、alpha(..)、beta(..)或no op。这有点笨拙,相当于将平行的阶段塞进矩阵,但它是有效的。而且,您还可以获得并行化(构建速度优化)的好处


希望将来会有更优雅的东西。

我有一个解决我自己问题的办法

根据文档()我要找的是不可能的。“矩阵中的每个单元格都可以包括一个或多个要使用该单元格的配置顺序运行的阶段。请注意,一个阶段必须有且只能有一个步骤、阶段、并行或矩阵。如果该阶段指令嵌套在并行或矩阵块中,则无法在该阶段指令中嵌套并行或矩阵块。”自我。”

但是。。。。你可以作弊。我能够将矩阵转换为通用调度队列。i、 每个组合调用N个阶段——对我来说,2个阶段,我称它们为“准备”和“执行”。我在中传递了一个附加的“matrixtype”参数。matrixtype为矩阵本身获取1个值,并为非矩阵的每行获取附加值。然后我使用矩阵“excludes”来确保非矩阵行只执行一次。有效地,这将非矩阵折叠成按矩阵类型区分的矩阵

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(..)是共享库中的简单分派方法,它们检查matrixtype,并根据需要调用originalFirst(..)、originalSecond(..)、alpha(..)、beta(..)或no op。这有点笨拙,相当于将平行的阶段塞进矩阵,但它是有效的。而且,您还可以获得并行化(构建速度优化)的好处


希望将来会有更优雅的东西。

我想出了一个“更好”的解决方案:

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

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

我想出了一个“更好”的解决方案:

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

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

这看起来很有趣。我没有尝试过,但它不会创建一个笛卡尔坐标系,在这里你有alpha/beta/bar/baz的垂直矩阵,并且在每个矩阵中都有一个alpha/beta/bar/baz阶段。当然,bar阶段只在bar矩阵行等中执行,因此它执行正确,代码更少。但正如你所说,显示器很可能是傻乎乎的。显示器是傻乎乎的。。。但是纯粹的声明性管道,所以您可以避免语法验证的缺点(也意味着更好的用户体验)。但无论如何,我注意到在我的例子中我不能使用矩阵:矩阵轴不能是可变的。。。切线。。。矩阵轴不能是可变的,但可以指定所有可能的,然后有条件地关闭不需要的-伪变量这看起来很有趣。我没有尝试过,但它不会创建一个笛卡尔坐标系,在这里你有alpha/beta/bar/baz的垂直矩阵,并且在每个矩阵中都有一个alpha/beta/bar/baz阶段。当然,bar阶段只在bar矩阵行等中执行,因此它执行正确,代码更少。但正如你所说,显示器很可能是傻乎乎的。显示器是傻乎乎的。。。但是纯粹的声明性管道,所以您可以避免语法验证的缺点(也意味着更好的用户体验)。但无论如何,我注意到在我的例子中我不能使用矩阵:矩阵轴不能是可变的。。。切线。。。矩阵轴不能是可变的,但