具有包含点(。)的变量名的Groovy列表被转换为字符串

时间:2018-09-25 20:02:22

标签: groovy jenkins-pipeline

我在groovy中有一个列表,定义为

env.list = ["abc","def"]

如果我尝试在for循环中使用它

for (letters in env.list) {
  print("Letter is $letters")
}

它将遍历每个字母并打印以下内容-

Letter is [
Letter is "
Letter is a
.....

如果我将列表定义如下-

list = ["abc","def"]

它将视为一个列表。 for循环将显示以下内容。

Letter is abc
Letter is def

使用groovy运行我的Jenkins管道。

  1. 为什么根据名称有区别?
  2. 我们如何使用带点(。)的变量名定义列表?

2 个答案:

答案 0 :(得分:3)

在詹金斯管道中,env-是保存环境变量列表的变量:

https://jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables

并且环境变量只能包含一个字符串

因此,当您尝试为环境变量分配一个列表时-它会自动转换为字符串

env.list = ["abc","def"]

等同于

env.list = ["abc","def"].toString()

然后按字符迭代字符串...

答案 1 :(得分:0)

要解释为什么会发生这种现象,最好转向Jenkins源代码。

全局变量名称为env,将我们带到org.jenkinsci.plugins.workflow.cps.EnvActionImpl.Binder。它将值绑定到脚本(在本例中为管道)。

Source code

    @Override public EnvActionImpl getValue(CpsScript script) throws Exception {
        Run<?,?> run = script.$build();
        if (run != null) {
            return EnvActionImpl.forRun(run);
        } else {
            throw new IllegalStateException("no associated build");
        }
    }

EnvActionImpl扩展了Groovy类型GroovyObjectSupport (source code)GroovyObjectSupport在其文档中有此内容:

  

对于希望成为Groovy对象的Java对象的有用基类

因此,这是Jenkins允许Java实现,使其可以为Groovy设置其行为。您使用的方法是public java.lang.Object getProperty(java.lang.String property)public void setProperty(java.lang.String property, java.lang.Object newValue),因此我们将更详细地研究EnvActionImpl的实现。

对于setProperty,实现为here

@Override public void setProperty(String propertyName, Object newValue) {
    env.put(propertyName, String.valueOf(newValue));
    try {
        owner.save();
    } catch (IOException x) {
        throw new RuntimeException(x);
    }
}

在该类的更高一级,我们看到env的声明是private final Map<String,String> env;。属性名称用作键(在您的示例中为list),值是String.valueOf的{​​{1}}返回,在您的情况下为字符串化的newValue。 / p>

setProperty

["abc","def"]

了解@Override public String getProperty(String propertyName) { try { CpsThread t = CpsThread.current(); return EnvironmentExpander.getEffectiveEnvironment(getEnvironment(), t.getContextVariable(EnvVars.class), t.getContextVariable(EnvironmentExpander.class)).get(propertyName); } catch (Exception x) { LOGGER.log(Level.WARNING, null, x); return null; } } EnvironmentExpander的机制可以做得更多,但是最快的方法是仅检查签名-CpsThread

这说明了詹金斯在管道脚本中使用public String变量在幕后所做的事情,以及为什么迭代是在env的字符上发生的原因,而不是您期望的列表。如果您创建了自己的变量并自己进行了尝试,您将看到例如StringMap类型之间的行为差​​异。

EnvActionImpl