将整个 Jenkins 阶段提取到共享库?

问题描述 投票:0回答:2

是否可以获取整个

stage('foo') {...}
定义并将其提取到 Jenkins 内的共享库中?文档非常清楚如何提取单个步骤,但我找不到任何方法来获取整个阶段、对其进行参数化并在全局范围内重新使用它。我认为也许只是
return stage...
可以工作,但它会错误地显示为无效的返回值。

jenkins groovy jenkins-pipeline
2个回答
43
投票

这取决于您是否使用脚本化声明式管道。

脚本化管道更加灵活,它允许您例如根据某些条件创建阶段(每个管道运行可以有不同数量和类型的阶段)。在这种管道中,您可以将完整阶段提取到共享库类并从

node {}
块内部调用它。考虑以下示例:

// src/ScriptedFooStage.groovy
class ScriptedFooStage {
    private final Script script

    ScriptedFooStage(Script script) {
        this.script = script
    }

    // You can pass as many parameters as needed
    void execute(String name, boolean param1) {
        script.stage(name) {
            script.echo "Triggering ${name} stage..."
            script.sh "echo 'Execute your desired bash command here'"

            if (param1) {
                script.sh "echo 'Executing conditional command, because param1 == true'"
            }
        }
    }
}

然后 Jenkinsfile 可能看起来像这样:

node {
    new ScriptedFooStage(this).execute('Foo', true)
}

如您所见,整个阶段都封装在

ScriptedFooStage.execute()
方法中。它的名称也取自参数
name
- 脚本化管道允许您执行此类操作。


另一方面,

声明式管道更加严格和固执己见。如果涉及阶段数量及其名称,它是固定的(您无法动态建模每个构建存在哪些阶段以及它们的名称是什么)。您仍然可以利用共享库类,但只能在

script {}
块内的
stage('Name') { steps {} }
块内执行它们。这意味着您无法将整个阶段提取到单独的类中,而只能提取在步骤级别执行的部分部分。考虑以下示例:

// src/DeclarativeFooStage.groovy
class DeclarativeFooStage {
    private final Script script

    DeclarativeFooStage(Script script) {
        this.script = script
    }

    // You can pass as many parameters as needed
    void execute(String name, boolean param1) {
        script.echo "Triggering script with name == ${name}"
        script.sh "echo 'Execute your desired bash command here'"

        if (param1) {
            script.sh "echo 'Executing conditional command, because param1 == true'"
        }
    }
}

并且 Jenkinsfile 可能如下所示:

// Jenkinsfile
pipeline {
    agent any

    stages {
        stage('Foo') {
            steps {
                script {
                    new DeclarativeFooStage(this).execute('something', false)
                }
            }
        }
    }
}

如果我们尝试在声明性管道中的

new DeclarativeFooStage(this).execute('something', false)
块之外执行
script {}
,我们将收到编译错误。

结论

脚本化管道或声明式管道之间的选择取决于具体的用例。如果您希望在对管道业务逻辑进行建模时获得最佳灵活性,脚本化管道可能是不错的选择。然而,它是有一定代价的。例如,脚本化管道不支持从特定阶段重新启动管道构建 - 这仅由声明性管道支持。 (假设您的管道中有 10 个阶段,第 7 阶段由于一些愚蠢的错误而失败,并且您想从第 7 阶段重新启动构建 - 在脚本化管道中,您必须从头开始重新运行,而声明式管道可以重新启动从第 7 阶段开始,记住前 6 个阶段的结果)。


2
投票

要完成 Szymon Stepniak 的回答,我将在此处留下注意,在声明式管道中,您也可以共享整个管道:

// vars/myDeliveryPipeline.groovy
def call(Map pipelineParams) {

    pipeline {
        agent any
        stages {
            stage('build') {
                ...
            }

            stage ('test') {
                ...
            }

            ...
        }
    }
}

然后调用它

@Library(['my-shared-library-name'])_

// (...)

// Jenkinsfile
myDeliveryPipeline(foo: 'FOO', bar: 'BAR')

但请记住,您可能只在 Jenkins 文件中调用一个管道,这使得它不太可定制。

*my-shared-library-name 是 Jenkins 共享库详细信息中配置的库的名称。

来源

© www.soinside.com 2019 - 2024. All rights reserved.