如何封装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行,看着很清爽。

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

相关推荐
用户4081281200381几秒前
三栏布局
前端
雲墨款哥1 分钟前
Vue3.0 项目初始化及 Element Plus 配置实战
前端·vue.js
拾光拾趣录2 分钟前
Webpack 打包中的 Hash 生成机制
前端·webpack·前端工程化
十盒半价3 分钟前
闭包:JS 里的 “背包客”,背走了变量的秘密
前端·javascript·trae
Rasir4 分钟前
第三章:命令行交互与流程控制
前端
然我5 分钟前
打工人必看!Flex “驯服” 前端面试,让代码像整理工位一样顺
前端·面试·html
根本学不完5 分钟前
前端之美:探寻封装函数解耦的诗意世界
前端
zhanshuo5 分钟前
打造一个可维护、可复用的前端权限控制方案(含完整Demo)
前端
前端小饭桌6 分钟前
关于 Vue 3 的 ref,这些细节你了解了多少?
前端·vue.js
光影少年21 分钟前
vue3.0性能提升主要通过那几方面体现的?
前端·vue.js