使用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
问题分析
- 沙箱权限限制:Active Choice的Groovy脚本默认在沙箱环境运行,直接调用
command.execute()执行外部git命令会被沙箱拦截,导致脚本执行失败返回null,这就是报错中choices=null的核心原因。 - 命令执行未处理异常:即使沙箱允许执行外部命令,直接执行
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脚本执行外部命令:
- 进入Jenkins 管理Jenkins → 全局安全配置
- 在脚本安全部分,添加
method java.lang.Runtime exec java.lang.String[]到允许的方法列表 - 然后修改脚本,完善命令执行的错误处理:
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

