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

Jenkins Active Choices响应式参数无内容显示问题求助

问题描述

我们GitLab仓库中有格式为PROJECT_NAME-ENV_NAME-images.yaml的YAML文件,结构如下:

producta:
  service1:
    image:
      repository: repo
      pullPolicy: Always
      # Overrides the image tag whose default is the chart appVersion.
      tag: "v1.1.80"
  serviceb:
    image:
      repository: repo
      pullPolicy: Always
      # Overrides the image tag whose default is the chart appVersion.
      tag: "v1.1.42"
productb:
  servicec:
    image:
      repository: repo
      pullPolicy: Always
      # Overrides the image tag whose default is the chart appVersion.
      tag: "v1.1.42"
  smoke_test:
    image:
      repository: repo
      pullPolicy: Always
      # Overrides the image tag whose default is the chart appVersion.
      tag: "2dc13f68"
  serviced:
    image:
      repository: repo
      pullPolicy: Always
      # Overrides the image tag whose default is the chart appVersion.
      tag: "v1.1.42"
  servicee:
    image:
      repository: repo
      pullPolicy: Always
      # Overrides the image tag whose default is the chart appVersion.
      tag: "v1.1.42"
  servicee:
    image:
      repository: repo
      pullPolicy: Always
      # Overrides the image tag whose default is the chart appVersion.
      tag: "v0.0.9"

在Jenkins中我们定义了PROJECT_NAME和ENV_NAME输入参数,products是多选类型的Active Choice参数。需求是:用户输入项目、环境及需更新标签的产品列表后,在Active Choices Reactive Reference Parameter类型的servicesToBeUpdated参数中渲染包含对应服务及标签的HTML输入表格。

我们配置的Groovy脚本如下:

def gitlabUrl = "https://gitlab.com/group/helm-charts.git"
def gitlabCredentialsId = "XXXXXX-XXX-XXX-XXXX-XXX"
def gitlabBranch = "v1"
def imagesYamlFile = "images/project/${params.Project}-${params.Env}-images.yaml"

withCredentials([usernamePassword(credentialsId: gitlabCredentialsId, usernameVariable: 'GITLAB_USERNAME', passwordVariable: 'GITLAB_PASSWORD')]) {
    sh """
        rm -rf repo
        git clone --branch ${gitlabBranch} ${gitlabUrl} repo
        cp repo/${imagesYamlFile} .
    """
}


def imagesYaml = readYaml file: imagesYamlFile
def productslist = imagesYaml.keySet()

for (product in productslist) {
  def microservices = imagesYaml[product].keySet()

  def service_list = []

  for (microservice in microservices) {
    def yamlLength = imagesYaml[product][microservice].size()

    if (yamlLength > 1 && microservice.equals("image")) {
      def tag = imagesYaml[product][microservice].tag
      def service = [:]
      service['service'] = microservice
      service['release_tag'] = tag
      service_list.add(service)
    } else if (yamlLength > 1) {
      def msImage = imagesYaml[product][microservice].keySet()

      for (mss in msImage) {
        def mssYamlLength = imagesYaml[product][microservice][mss].size()

        if (mssYamlLength > 1 && mss != "SNOWFLAKE_CONTAINER_IMAGE") {
          def tag = imagesYaml[product][microservice][mss].tag
          def service = [:]
          service['service'] = "${microservice}.${mss}"
          service['release_tag'] = tag
          service_list.add(service)
        }
      }
    } else {
      def image = imagesYaml[product][microservice].image
      def tag = image.tag
      def service = [:]
      service['service'] = microservice
      service['release_tag'] = tag
      service_list.add(service)
    }
  }

  service_tier_map[product] = service_list
}
// Get the list of products to update from the user input
def productsToUpdate = params.products.split(",")


// Loop through each product and its associated services
service_tier_map.each { selectedProduct, services ->
  // Check if the current product is in the list of products to update
  if (productsToUpdate.contains(product)) {
    def updated_services = []

    // Loop through each service and update its release tag
    services.each { service ->
      updated_services.add(service)
    }

    service_to_be_updated_map[product] = updated_services
  }
}
html_to_be_rendered = "<table><tr>"
service_to_be_updated_map.each { product, services ->
  services.each { service ->
    html_to_be_rendered = """
      ${html_to_be_rendered}
      <tr>
      <td>
      <input name=\"value\" alt=\"${service.service}\" json=\"${service.service}\" type=\"checkbox\" class=\" \">
      <label title=\"${service.service}\" class=\" \">${service.service}</label>
      </td>
      <td>
      <input type=\"text\" class=\" \" name=\"value\" value=\"${service.release_tag}\"> </br>
      </td>
      </tr>
  """
  }
}
html_to_be_rendered = "${html_to_be_rendered}</tr></table>"
return html_to_be_rendered

问题:修改products输入参数的值后,Jenkins界面上的servicesToBeUpdated参数下无任何内容显示。


问题排查与修复

1. 初始化核心映射变量

脚本中service_tier_map和service_to_be_updated_map两个关键映射未提前初始化,Groovy会因未定义变量触发运行时错误,直接跳过后续逻辑。

修复:在读取YAML后添加初始化代码:

def service_tier_map = [:]
def service_to_be_updated_map = [:]

2. 修正循环变量引用错误

遍历service_tier_map时,判断条件误用了外部循环的product变量,而非当前迭代的selectedProduct,导致无法匹配用户选择的产品,service_to_be_updated_map始终为空。

修复:调整判断与赋值逻辑:

service_tier_map.each { selectedProduct, services ->
  if (productsToUpdate.contains(selectedProduct)) {
    service_to_be_updated_map[selectedProduct] = services
  }
}

3. 适配实际YAML结构解析逻辑

原脚本的分支判断不符合实际YAML结构:你的YAML中每个服务(如service1)下直接是image节点,不存在microservice.equals("image")的场景,导致标签提取失败。

修复:简化服务遍历逻辑:

for (product in productslist) {
  def microservices = imagesYaml[product].keySet()
  def service_list = []

  for (microservice in microservices) {
    def imageConfig = imagesYaml[product][microservice].image
    if (imageConfig && imageConfig.tag) {
      def service = [:]
      service['service'] = microservice
      service['release_tag'] = imageConfig.tag
      service_list.add(service)
    }
  }

  service_tier_map[product] = service_list
}

注:原YAML中productb下有重复的servicee节点,解析时会覆盖前一个,建议先修复YAML文件的重复键问题。

4. 修复HTML结构错误

原HTML开头和结尾的<tr>标签冗余且结构无效,导致浏览器无法渲染。同时多个输入控件的name属性重复,会导致提交值被覆盖。

修复:重构HTML构造代码:

html_to_be_rendered = "&lt;table&gt;"
service_to_be_updated_map.each { product, services ->
  services.each { service ->
    html_to_be_rendered += """
      &lt;tr&gt;
        &lt;td&gt;
          &lt;input name=\"${service.service}_checkbox\" type=\"checkbox\" class=\"\"&gt;
          &lt;label title=\"${service.service}\" class=\"\"&gt;${service.service}&lt;/label&gt;
        &lt;/td&gt;
        &lt;td&gt;
          &lt;input type=\"text\" class=\"\" name=\"${service.service}_tag\" value=\"${service.release_tag}\"&gt;
        &lt;/td&gt;
      &lt;/tr&gt;
    """
  }
}
html_to_be_rendered += "&lt;/table&gt;"

5. 检查Jenkins参数配置

  • 确认servicesToBeUpdated的Referenced parameters已包含Project、Env、products,确保参数变化时触发脚本重新执行。
  • 确认products参数的返回值是逗号分隔的字符串,与params.products.split(",")的解析逻辑匹配。
  • 在Jenkins脚本控制台测试核心逻辑,排除Git拉取、YAML读取的权限或路径问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 04:55:08