Jenkins 管道多配置项目

10

原始情况:

我在 Jenkins 中有一个正在运行 ant 脚本的任务。我很容易地使用“多配置项目”测试了这个 ant 脚本在多个软件版本上的情况。

这种类型的项目非常棒,因为它允许我指定我需要的两个软件版本(在我的情况下是 Java 和 Matlab)的所有版本,并使用我的参数组合运行我的 ant 脚本。

然后,这些参数会被用作字符串拼接,在可执行文件的位置定义中使用。

例如:env.MATLAB_EXE=/usr/local/MATLAB/${MATLAB_VERSION}/bin/matlab

这个方案完美地运行,但现在我正在将这些脚本迁移到管道版本中

管道迁移:

我成功地在管道方式下实现了相同的脚本,使用了参数化管道插件。通过这个方法,如果我手动触发构建,我可以手动选择要使用的软件版本,我也找到了一种方法来周期性地选择每次运行时想要使用的参数来执行此操作。

这个解决方案似乎工作得很好,但并不是很令人满意。

我的多配置项目有一些此方法没有的功能:

  1. 使用多个参数,我可以设置插值并执行每个组合
  2. 执行清楚地分离,并且在构建历史记录/构建详细信息中很容易识别使用了哪些设置
  3. 只需将新的“可能”值添加到参数即可生成所需的执行

请求:

因此,我想知道是否有更好的解决方案来解决我的问题,也能满足上述要点。

长话短说:是否有一种方法可以在 Jenkins 中实现多配置项目,但使用管道技术呢?

2个回答

9

最近我看到很多类似的问题,所以我觉得这将是一个有趣的练习……

通过代码可视化,矩阵/多配置作业实际上只需要几个嵌套的for循环,每个参数轴都需要一个。

你可以用一些硬编码的for循环来构建一个相当简单的东西来遍历一些列表。或者你可以变得更加复杂,并做一些递归循环,这样你就不必硬编码特定的循环。

免责声明: 我做的运维比写代码多。我也很新于groovy,所以这可能可以更干净地完成,并且可能还有很多更酷的事情可以做,但无论如何它都可以完成工作。

稍加修改,这个matrixBuilder可以包装在一个类中,这样你就可以传递一个任务闭包和轴列表,并获得任务映射。把它放在共享库中,随时使用。应该很容易添加一些其他多配置作业的功能,例如过滤器。

这个尝试使用一个递归的matrixBuilder函数来处理任意数量的参数轴并构建所有组合。然后并行执行它们(显然取决于节点的可用性)。

/*
    All the config axes are defined here
    Add as many lists of axes in the axisList as you need.
    All combinations will be built
*/
def axisList = [
    ["ubuntu","rhel","windows","osx"],           //agents
    ["jdk6","jdk7","jdk8"],                      //tools
    ["banana","apple","orange","pineapple"]      //fruit
]



def tasks = [:]
def comboBuilder
def comboEntry = []


def task = {
    // builds and returns the task for each combination

    /* Map the entries back to a more readable format
       the index will correspond to the position of this axis in axisList[] */
    def myAgent = it[0]
    def myJdk   = it[1]
    def myFruit = it[2]

    return {
        // This is where the important work happens for each combination
        node(myAgent) {
            println "Executing combination ${it.join('-')}"
            def javaHome = tool myJdk
            println "Node=${env.NODE_NAME}"
            println "Java=${javaHome}"
        }

        //We won't declare a specific agent this part
        node {
            println "fruit=${myFruit}"
        }
    }
}


/*
    This is where the magic happens
    recursively work through the axisList and build all combinations
*/
comboBuilder = { def axes, int level ->
    for ( entry in axes[0] ) {
        comboEntry[level] = entry
        if (axes.size() > 1 ) {
            comboBuilder(axes[1..-1], level + 1)
        }
        else {
            tasks[comboEntry.join("-")] = task(comboEntry.collect())
        }
    }
}

stage ("Setup") {
    node {
        println "Initial Setup"
    }
}

stage ("Setup Combinations") {
    node {
        comboBuilder(axisList, 0)
    }
}

stage ("Multiconfiguration Parallel Tasks") {
    //Run the tasks in parallel
    parallel tasks
}

stage("The End") {
    node {
        echo "That's all folks"
    }
}

您可以在构建页面的“Pipeline Steps”链接下查看作业详细流程。具体链接为:http://localhost:8080/job/multi-configPipeline/[build]/flowGraphTable/
编辑: 您可以将阶段移动到“任务”创建中,然后更清晰地查看每个阶段的详细信息,但不像多配置作业那样整齐地显示在矩阵中。
...
return {
    // This is where the important work happens for each combination
    stage ("${it.join('-')}--build") {
        node(myAgent) {
            println "Executing combination ${it.join('-')}"
            def javaHome = tool myJdk
            println "Node=${env.NODE_NAME}"
            println "Java=${javaHome}"
        }
        //Node irrelevant for this part
        node {
            println "fruit=${myFruit}"
        }
    }
}
...

或者您可以为每个节点单独包装一个stage,以获得更详细的信息。

在这样做时,我注意到了我的先前代码中的一个错误(现已修复)。我将comboEntry引用传递给任务。我应该发送一份副本,因为尽管阶段名称是正确的,但当它实际执行它们时,值显然都是遇到的最后一个条目。因此,我将其更改为tasks [comboEntry.join(“ - ”)] = task(comboEntry.collect())

我注意到您可以保留并行任务的执行周围的原始stage(“Multiconfiguration Parallel Tasks”) {} 。现在从技术上讲,您有嵌套阶段。我不确定Jenkins应该如何处理它,但它没有抱怨。但是,“父”阶段的计时不包括并行阶段的计时。

我还注意到,当新构建开始运行时,在作业的“阶段视图”中,所有以前的构建都会消失,可能是因为阶段名称不完全匹配。但是在构建完成运行之后,它们全部匹配,并且旧构建再次显示出来。

最后,Blue Ocean似乎没有以相同的方式进行可视化。它不识别并行进程中的“阶段”,只识别封闭阶段(如果存在)或如果不存在,则为“并行”。然后仅显示各个并行进程,而不是其中的阶段。


1
我考虑过这个,但这并不能满足我的结果展示需求。矩阵/多配置作业将呈现不同的“内部”作业,每个作业都显示其状态和测试结果趋势。这就是为什么我想要一个不同的解决方案。 - rakwaht
我刚刚添加了一个编辑,可以更细致地呈现细节。但不像矩阵作业那样漂亮的小矩阵。 - Rob Hales
好的,至少你尝试了并且得到了一个不错的近似值。然而,我仍然更喜欢矩阵可视化。 - rakwaht
1
顺便提一下,指向 localhost 地址的链接没有什么帮助。 - Jesse Chisholm
你肯定明白我不知道你的Jenkins实例的主机名。如果你注意到了,我也猜不出你实际构建的名称。你需要自己动点脑筋,指向一个对你有用的URL。 - Rob Hales
不幸的是,这似乎也不允许选择矩阵组合参数的选项(特别是带有弹性轴)。:-/ 有什么想法吗? - Mark

1

我对第1点和第3点不是很清楚,但我猜想您只是想使用“脚本化”而不是“声明式”Pipeline语法,如果是这样,您可以使您的任务做任何您想做的事情——任何矩阵项目轴和轴过滤器允许的事情以及更多内容,包括并行执行。 声明式语法在语法简单性(友好于“往返”编辑工具和“linters”)与灵活性之间进行权衡。

第2点是关于结果可视化,而不是执行本身。虽然这是一个复杂的主题,但通常的具体请求并不像Blue Ocean等现有可视化所支持的那样能够通过轴组合来区分测试结果。 这由JENKINS-27395和一些相关问题跟踪,正在进行设计。


是的,这基本上意味着我的问题没有完整的解决方案,但我们有部分解决方案(例如@RobHales的答案)可以解决1和3号问题,但是目前没有解决第2个问题的解决方案,对吧?顺便说一句,我觉得很奇怪,到现在为止没有人有与我完全相同的需求。 - rakwaht
@rakwaht 关于“没有人有同样的需求”,或者更确切地说,没有人有解决它的同样紧迫感。每次我使用Jenkins(因为我的所有项目都是复杂的多平台、多工具集),我都感到这种需求,但我可以通过大量的额外输入来克服这个问题。循环的能力是维护的福音,但不是推出项目所必需的。一旦Jenkins文件运行起来了,它几乎永远不会改变。 - Jesse Chisholm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接