【问题标题】:Groovy/Jenkins: when are variables null, when are they empty strings, and when are they missing?Groovy/Jenkins:变量何时为空,何时为空字符串,何时丢失?
【发布时间】:2021-06-04 00:03:12
【问题描述】:

我正在尝试了解 Groovy/Jenkinsfiles/声明性语法中围绕变量的规则。

通用 webhook 触发器捕获 HTTP POST 内容并将它们作为变量提供给您的 Jenkinsfile。例如:

pipeline {
  agent any
  triggers {
    GenericTrigger (
      genericVariables: [
        [ key: "POST_actor_name", value: "\$.actor.name" ]
      ],

      token: "foo"
    )
  }

  stages {

    stage( "Set up" ) {
      steps {
        script {
          echo "env var ${env.actor_name}"
          echo "global var ${actor_name}"
        }
    }
  }
}

如果 HTTP POST 内容包含一个带有 actor_name 字段值为“foo”的 JSON 对象,则打印如下:

env var foo
global var foo

如果 HTTP POST 内容不包含 JSON 字段 actor_name,则打印出来

env var null

...然后断言/中止并出现No such property 错误。

Jenkins 作业也有一个“这个项目是参数化的”设置,这似乎引入了另一种将变量注入到 Jenkinsfile 中的方法。下面的 Jenkinsfile 打印一个填充的、参数化的构建变量、一个未填充的变量和一个故意不存在的变量:

pipeline {
  agent any

  stages {

    stage( "Set up" ) {
      steps {
        script {
          echo "1 [${env.populated_var}]"
          echo "2 [${env.unpopulated_var}]"
          echo "3 [${env.dontexist}]"
          echo "4 [${params.populated_var}]"
          echo "5 [${params.unpopulated_var}]"
          echo "6 [${params.dontexist}]"
          echo "7 [${populated_var}]"
          echo "8 [${unpopulated_var}]"
          echo "9 [${dontexist}]"
        }
      }
    }
  }
}

结果是:

1 [foo]
2 []
3 [null]
4 [foo]
5 []
6 [null]
7 [foo]
8 []

...然后断言/中止并出现No such property 错误。

我能确定的模式是:

  1. env.-scoped 变量如果来自未填充的 HTTP POST 内容,则将为 NULL。
  2. env.-scoped 变量如果来自未填充的参数化构建变量,则它们将是空字符串。
  3. 如果参数化构建变量中不存在env.-scoped 变量,则该变量将为 NULL。
  4. 如果引用全局范围的变量来自未填充的 HTTP POST 内容,则会断言它们。
  5. 如果引用全局范围的变量来自未填充的参数化构建变量,则它们将为空字符串。
  6. params.-scoped 变量如果在参数化构建变量中不存在,则它们将为 NULL。
  7. params.-scoped 变量如果来自未填充的参数化构建变量,则它们将是空字符串。

我对此有几个问题 - 我相信它们是合理相关的,所以我将它们包括在这篇文章中:

  1. 当变量为 NULL 且为空字符串时,其背后的基本模式/逻辑是什么?
  2. 为什么变量在不同的“范围”中可用:env.params. 和全局,它们之间的关系是什么(为什么它们不总是 1:1)?
  3. 有没有办法让参数化构建中的未填充值成为 Jenkinsfile 中的空值变量而不是空字符串?

上下文:在我的第一个 Jenkinsfile 项目中,我使用了由 HTTP POST 内容填充的变量。通过这个,我将一个值的缺失与相应的.env 变量的空值联系起来。现在,我正在处理来自参数化构建值的变量,当未填充值时,对应的.env 变量不为空——它是一个空字符串。因此,我想了解这些变量何时以及为何为空而不为空背后的模式,以便我可以编写可靠而简单的代码来处理来自 HTTP POST 内容和参数化构建值的值的缺失/未填充。

【问题讨论】:

    标签: jenkins groovy jenkins-pipeline jenkins-declarative-pipeline


    【解决方案1】:

    答案有点复杂。

    对于 1 和 2:

    首先,流水线、阶段、步骤...都是 groovy 类。里面的所有东西都被定义为对象/变量。

    env 是一个包含几乎所有东西的对象,

    params 保存所有参数;)

    它们都是 Map,如果你访问一个空值它是空的,如果你访问一个不存在的它是 null。

    全局变量本身就是变量,如果您尝试访问不存在的变量,编译器会报错。

    对于 3:

    您可以定义“默认”参数:

    pipeline {
      agent any
    
      stages {
    
        stage( "Set up" ) {
          steps {
            script {
              params = setConfig(params);
            }
          }
        }
      }
    }
    
    def merge(Map lhs, Map rhs) {
        return rhs.inject(lhs.clone()) { map, entry ->
            if (map[entry.key] instanceof Map && entry.value instanceof Map) {
                map[entry.key] = merge(map[entry.key], entry.value)
            } else {
                map[entry.key] = entry.value
            }
            return map
        }
    }
    
    def setConfig(givenConfig = [:]) {
      def defaultConfig = [
        "populated_var": "",
        "unpopulated_var": "",
        "dontexist": ""
      ];
     
      effectiveConfig = merge(defaultConfig, givenConfig);
       
      return effectiveConfig
    }
    

    【讨论】:

    • 很好,全面的答案,谢谢。你知道为什么吗:如果一个变量是从 HTTP POST 内容中填充的,但该变量在 HTTP POST 中完全不存在,那么对应的 env. 变量为 null but 如果相同的变量是从构建参数填充,并且构建参数留空,那么env. 变量是空字符串?我试图理解为什么“变量未填充”的一个“路径”导致一个空变量,而另一个“路径”导致一个空变量的原因。
    • 我不确定。但这可能与 GenericTrigger 插件有关。在这两种情况下,它都是一个设计决策。插件和参数(很可能)是由不同的人开发的,即使不是,两种情况下的决定也不同。我认为参数是用“”初始化的,而在 GenericTrigger 插件中不是。
    猜你喜欢
    • 2012-02-01
    • 2012-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-31
    • 2014-03-23
    • 1970-01-01
    • 2016-08-13
    相关资源
    最近更新 更多