如何封装Jenkins参数化构建中的动态选项获取代码片段?

业务背景

项目中每个Jenkins构建任务, 有两个参数是动态生成的,一个是构建的git分支,一个是要回退的镜像tag, 这两个参数的获取,都需要运行一段80-100行的程序片段,要是只在一个项目中使用,倒也无妨,冗长一点就冗长一点。可是要在三四十个项目中使用,就需要考虑代码优雅和易维护性问题,所以想对这里的逻辑做一下封装。

封装方案

Jenkins的Active Choices Reactive Parameter中的script脚本,限制很多:例如无法读取env变量,params变量,currentBuild变量,无法引用共享库,而且调试困难。所以要想按照常规的封装方式实现这一目的,是比较困难的。但可以曲线救国,迂回一下,还是可以实现同等封装效果的。怎么迂回呢?

第一步 安装Scriptler插件

Jenkins的Scriptler 插件允许用户在 Jenkins 环境中存储、管理和执行 Groovy 脚本,提供了一个便捷的方法来共享和复用groovy脚本代码。打开 Jenkins 仪表盘,导航到 系统管理==> 插件管理,在Available plugins标签下搜索"Scriptler",找到后点击安装并重启 Jenkins。

安装完之后, 进入到Scriptler面板

第二步 编写封装脚本

点击页面左侧的"Add a New Script", 编写封装脚本。id是引用时使用的名称,name是展示名称,comment是备注说明。

编写的业务脚本需要用def定义至少一个函数,暴露给外部使用。示例:下面的脚本片段定义了一个readYamlConfig函数,参数是git项目名称,用于读取远程git仓库下项目yaml文件配置参数。注意,不能有下面这些操作:读取env变量,params变量,currentBuild变量,引用共享库等。

js 复制代码
import org.yaml.snakeyaml.Yaml

def readYamlConfig(String projectName) {
    def yamlUrl = "https://git.xxx.com/api/v4/projects/650/repository/files/common-jenkins-config%2Fresources%2Fproject-config-js%2F${projectName}.yaml/raw?ref=frontend-common"
    def token = "xxx-token"
    def connection = new URL(yamlUrl).openConnection()
    if (token) connection.setRequestProperty("PRIVATE-TOKEN", token)
    connection.setRequestProperty("Accept", "application/x-yaml")
    connection.connect()
    if (connection.responseCode == 200) {
        def yamlText = connection.inputStream.withReader { it.text }
        return new Yaml().load(yamlText)
    } else {
        throw new RuntimeException("读取YAML失败,HTTP状态码: ${connection.responseCode}")
    }
}

第三步 审批脚本

写完保存之后,脚本并不能使用,因为还需要管理员审批。为了防止恶意代码注入,Jenkins有个脚本安全的检查机制,自定义的groovy脚本需要管理员审批之后才能运行。

进入到Dashboard==>系统管理==>ScriptApproval菜单,就能看到待审批的脚本,找到自己刚刚写的脚本。每次修改之后,都需要审批,才能生效。新手一般没经验,容易在这里踩坑。

第四步 引入封装脚本

在Active Choices Reactive Parameter的script脚本编辑区域, 引入上面编写好的脚本。引入方法,也是摸索了一阵子,最终才找到可用的,就是下面这种写法。因为Scriptler下的脚本都存放在/var/jenkins_home/scriptler/scripts目录下,所以可以确切的知道一个脚本的绝对路径,接着用File api加载这个文件的文本内容,最后调用执行函数运行脚本逻辑。这里有一个细节需要注意: $scriptgetFilteredBranchesByEnv('$projectName', '$deployEnv')要用换行或空格进行分隔,这一块的写法是不太优雅,不过我目前没有找到更好的导入方法。

js 复制代码
def script = new File('/var/jenkins_home/scriptler/scripts/getChoiceParams.groovy').text
def deployEnv =  binding.getVariable('ManualDeployEnv') ?: 'dev'
def projectName=binding.getVariable('ProjectName')

return evaluate("$script \n getFilteredBranchesByEnv('$projectName', '$deployEnv')")

第五步 配置依赖参数

如果封装调用的方法不止一个,若这些方法有一些公共参数,并且构建时不允许手动编辑,那么把这些共同参数,设置成隐藏构建参数,是比较好的选择。隐藏参数不是Jenkins默认自带的功能。需要先安装Hidden Parameter Plugin插件,之后在Jenkins Job配置面板,添加参数选项列表,才会显示出这个选项。

隐藏参数一般是字符串类型,在构建面板不会显示出来。

创建好隐藏参数之后,需要配置一下参数关联,才能通过binding.getVariable('ProjectName')这样的语法,获取到参数值。这里轻描淡写的一句,背后也是踩了几个小时的坑,才尝试过来唯一正确的写法。

效果验证

原来这两个选项的代码片段,至少都是80行以上,经过封装,只剩下4行,看着很清爽。

那么,能不能正确获取的选项列表呢?现在验证一下,效果如下图所示:参数获取正常,封装成功。接下来把这个方案推广到其余项目。写到这里,发现项目多了之后,项目中的不合理部分会被放大好多倍,这个时候代码的组织方式就显得比较重要了,就得做一个有修养的程序员。程序员的修养,有时是主动的,有时是形势倒逼。希望看这篇文章的掘友,都是前者。本文完!

相关推荐
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端
爱敲代码的小鱼8 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax