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

使用Active Choice参数实现Jenkins作业可选Git标签遇错求助

使用Active Choice参数实现Jenkins动态选择Git标签的正确方式

问题背景

我已经通过Input Step实现了Jenkins作业中获取Git仓库标签并提供选择的功能,代码如下:

stage('get tags') {
    steps {
        script {
            tags = sh(script:"git ls-remote --t --refs git@gitserver:my_repo1.git", returnStdout: true).trim()
            tags = (tags =~ /(?m).*refs\/tags\/(.*)/).collect{it[1]} 
            selected_tag = input message: 'Select a tag:', 
                              parameters: [choice(choices: tags, name: '')]                 
        } 
    }
}

但尝试用Active Choice参数(CascadeChoiceParameter)实现相同功能时遇到问题:只要包含git命令执行相关代码就会报错,移除这些代码则正常运行。测试代码如下:

properties([
    parameters([
        [$class: 'CascadeChoiceParameter', 
            choiceType: 'PT_SINGLE_SELECT',
            description: 'Select a tag',
            filterLength: 1,
            filterable: true,
            name: 'select_tag',
            referencedParameters: 'my_repositories',
            script: [$class: 'GroovyScript',
                  fallbackScript: [
                     classpath: [], 
                     sandbox: true, 
                     script: 'return ["ERROR"]'
                  ],
                  script: [
                     classpath: [], 
                     sandbox: true, 
                     script: """
                        def command = ['git', 'ls-remote', '--t', '--refs', 'git@gitserver:my_repo1.git']
                        def proc = command.execute()
                        if (my_repositories == 'repo1') { 
                              return['aaa','bbb']
                        }
                        else {
                              return['ccc', 'ddd']
                        }
                     """.stripIndent()
                  ]
            ]
        ]
    ])
])   

报错信息:

Caused: hudson.remoting.ProxyException:
java.lang.IllegalArgumentException: Could not instantiate
{message=Select the tag to Use:,
parameters=[@choice(choices=null,description=blah,name=)]} for
org.jenkinsci.plugins.workflow.support.steps.input.InputStep:
java.lang.IllegalArgumentException: Could not instantiate
{choices=null, description=blah, name=} for
hudson.model.ChoiceParameterDefinition:
java.lang.reflect.InvocationTargetException

问题分析

  1. 沙箱权限限制:Active Choice的Groovy脚本默认在沙箱环境运行,直接调用command.execute()执行外部git命令会被沙箱拦截,导致脚本执行失败返回null,这就是报错中choices=null的核心原因。
  2. 命令执行未处理异常:即使沙箱允许执行外部命令,直接执行git ls-remote也没有处理命令执行失败的情况(比如网络问题、权限不足),一旦命令出错,脚本会抛出异常,同样导致返回值为空。

正确实现方式

方案1:使用Git插件API安全获取标签(推荐)

通过Jenkins Git插件提供的API来获取仓库标签,避免直接执行外部命令,同时兼容沙箱环境:

properties([
    parameters([
        [$class: 'CascadeChoiceParameter', 
            choiceType: 'PT_SINGLE_SELECT',
            description: 'Select a tag',
            filterLength: 1,
            filterable: true,
            name: 'select_tag',
            referencedParameters: 'my_repositories',
            script: [$class: 'GroovyScript',
                fallbackScript: [
                    classpath: [], 
                    sandbox: true, 
                    script: 'return ["ERROR: Failed to load tags"]'
                ],
                script: [
                    classpath: [], 
                    sandbox: true, 
                    script: """
                        def tags = []
                        try {
                            if (my_repositories == 'repo1') {
                                // 使用Git插件API调用git命令
                                def repoUrl = 'git@gitserver:my_repo1.git'
                                def gitTool = new hudson.plugins.git.GitTool('Default')
                                def cmd = gitTool.getGitExe() + " ls-remote --t --refs " + repoUrl
                                def proc = cmd.execute()
                                proc.waitFor()
                                def output = proc.in.text.trim()
                                tags = (output =~ /(?m).*refs\/tags\/(.*)/).collect{ it[1] }
                                // 处理空标签场景
                                if (tags.isEmpty()) {
                                    tags = ["No tags found"]
                                }
                            } else {
                                tags = ["ccc", "ddd"]
                            }
                        } catch (Exception e) {
                            tags = ["ERROR: " + e.getMessage()]
                        }
                        return tags
                    """.stripIndent()
                ]
            ]
        ]
    ])
])

方案2:授权沙箱执行外部命令

如果必须使用git命令行工具,需要先在Jenkins全局安全配置中授权Groovy脚本执行外部命令:

  1. 进入Jenkins 管理Jenkins → 全局安全配置
  2. 在脚本安全部分,添加method java.lang.Runtime exec java.lang.String[]到允许的方法列表
  3. 然后修改脚本,完善命令执行的错误处理:
properties([
    parameters([
        [$class: 'CascadeChoiceParameter', 
            choiceType: 'PT_SINGLE_SELECT',
            description: 'Select a tag',
            filterLength: 1,
            filterable: true,
            name: 'select_tag',
            referencedParameters: 'my_repositories',
            script: [$class: 'GroovyScript',
                fallbackScript: [
                    classpath: [], 
                    sandbox: true, 
                    script: 'return ["ERROR: Failed to load tags"]'
                ],
                script: [
                    classpath: [], 
                    sandbox: true, 
                    script: """
                        def tags = []
                        try {
                            if (my_repositories == 'repo1') {
                                def command = ['git', 'ls-remote', '--t', '--refs', 'git@gitserver:my_repo1.git']
                                def proc = command.execute()
                                proc.waitFor()
                                // 检查命令执行状态
                                if (proc.exitValue() != 0) {
                                    def errorMsg = proc.err.text.trim()
                                    tags = ["ERROR: Git command failed: " + errorMsg]
                                } else {
                                    def output = proc.in.text.trim()
                                    tags = (output =~ /(?m).*refs\/tags\/(.*)/).collect{ it[1] }
                                    if (tags.isEmpty()) {
                                        tags = ["No tags found"]
                                    }
                                }
                            } else {
                                tags = ["ccc", "ddd"]
                            }
                        } catch (Exception e) {
                            tags = ["ERROR: " + e.getMessage()]
                        }
                        return tags
                    """.stripIndent()
                ]
            ]
        ]
    ])
])

关键注意事项

  • 异常捕获:必须添加完整的异常处理逻辑,确保无论脚本执行成功还是失败,都返回一个非空的选项列表,避免choices=null的报错。
  • 沙箱兼容:优先使用Jenkins插件提供的API来操作Git,减少对外部命令的依赖,避免沙箱权限问题。
  • 命令状态检查:如果使用外部命令,必须检查命令的退出码,处理错误输出,避免因命令执行失败导致的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 22:05:01