You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否在Jenkins自定义步骤中定义完整Stage并与常规Stage混用?

Jenkins共享库中封装可复用Stage的实现方案

现有正常运行的代码

当前共享库已实现通过Jenkinsfile传递参数、模块化自定义步骤的流水线,代码如下:

// 项目仓库中的Jenkinsfile
@Library('shared-lib') _
mySharedPipeline ([
    myParam: "sdlkfjlskdjfsd"
])

// 共享库 vars/mySharedPipeline.groovy
def call(Map config) {
    def someVar = config.myParam
    def someOtherVar = params.SomeUIParam

    pipeline {
        agent none
        stages {
            stage ('one') {
                steps {
                    script { 
                        myCustomStep derp: someVar
                    }
                }
            }
            stage ('two') {
                steps {
                    script { 
                        myCustomStep derp: someVar
                    }
                }
            }
            stage ('three') {
                steps {
                    script { 
                        myCustomStep derp: someVar
                    }
                }
            }
        }
    }
}

// 共享库 vars/myCustomStep.groovy
def call(Map config) {
    def derp = config.derp
    // 执行具体逻辑
}

需求

将完整Stage封装为自定义步骤,使其能在stages{}块的任意位置插入,与常规Stage混用。

失败尝试及报错

多次尝试均触发Expected a stage错误:

  • 直接定义Stage并引用:自定义步骤直接写Stage代码,在流水线中直接调用,报错。
  • 自定义步骤嵌套Stage:在自定义步骤的call方法中写Stage代码,流水线中调用,报错。
  • 实例化Stage对象:通过Jenkins API创建Stage对象并插入,报错。

核心原因:Declarative Pipeline的stages块是严格DSL结构,仅允许stage作为直接子元素,无法直接调用自定义步骤或插入对象。

可行解决方案

方案1:自定义步骤返回Stage配置闭包(推荐)

通过自定义步骤返回包含Stage内容的闭包,在流水线的stage指令中调用该闭包,完美适配Declarative DSL。

共享库自定义Stage实现(vars/mySharedStage.groovy)

def call(Map config) {
    // 接收外部传入的参数,比如变量、代理配置、运行条件等
    return {
        agent { label config.agent ?: 'none' }
        when {
            expression { config.shouldRun ?: true }
        }
        steps {
            script {
                myCustomStep derp: config.someVar
            }
        }
        post {
            success {
                echo "Shared stage executed successfully"
            }
        }
    }
}

共享流水线中调用自定义Stage(vars/mySharedPipeline.groovy)

def call(Map config) {
    def someVar = config.myParam
    def someOtherVar = params.SomeUIParam

    pipeline {
        agent none
        stages {
            // 插入自定义共享Stage,可传递参数
            stage('My Reusable Stage') {
                mySharedStage someVar: someVar, agent: 'build-node', shouldRun: true
            }

            // 保留常规Stage定义
            stage('one') {
                steps {
                    script { 
                        myCustomStep derp: someVar
                    }
                }
            }
            stage('two') {
                steps {
                    script { 
                        myCustomStep derp: someVar
                    }
                }
            }
        }
    }
}

方案2:Scripted Pipeline封装(复杂场景备选)

如果需要更灵活的逻辑控制,可在自定义步骤中用Scripted Pipeline语法实现Stage,然后在Declarative的script块中调用。此方式会部分丢失Declarative特性,仅推荐用于特殊场景:

// vars/mySharedStage.groovy
def call(Map config) {
    stage('My Scripted Shared Stage') {
        agent { label config.agent }
        steps {
            script {
                myCustomStep derp: config.someVar
            }
        }
    }
}

// 流水线中调用(需放在script块内)
pipeline {
    agent none
    stages {
        stage('Wrapper Stage') {
            steps {
                script {
                    mySharedStage someVar: someVar, agent: 'build-node'
                }
            }
        }
    }
}

关键说明

  • Declarative Pipeline的stages块仅接受stage指令作为直接子元素,所有自定义Stage必须通过stage包裹。
  • 方案1完全兼容Declarative的所有特性,是优先推荐的实现方式。
  • 注意Groovy Map语法:传递参数时用key: value而非key = value。

内容的提问来源于stack exchange,提问作者red888

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 02:31:32