Jenkins 在一行中解释多个对象声明

Spa*_*kle 9 groovy jenkins jenkins-groovy jenkins-pipeline

这不是一个问题,而是一个警示故事:我试图节省一些空间并在 Jenkins 声明式管道中声明我的变量,如下所示:

int a, b, c
Run Code Online (Sandbox Code Playgroud)

然后,我将它们初始化为:

a = b = c = 0
Run Code Online (Sandbox Code Playgroud)

在我的代码中,我使用这些整数作为 for 循环中的计数器。我的脚本一遍又一遍地失败,抛出了一些异常:

java.lang.NullPointerException: Cannot invoke method next() on null object
Run Code Online (Sandbox Code Playgroud)

我确信我的列表是有效的,因为它是硬编码的。所以,我开始想知道这些计数器发生了什么,当我对它们调用 getClass() 时,Jenkins 高兴地告诉我它们不是整数,而是

org.codehaus.groovy.runtime.NullObject
Run Code Online (Sandbox Code Playgroud)

更改代码后

int a = 0
int b = 0
int c = 0
Run Code Online (Sandbox Code Playgroud)

一切都像魅力一样。只是想分享这个。也许它会帮助某人避免一些挫折。

Szy*_*iak 12

Jenkins 管道使用groovy-cps解释器以连续传递风格执行 Groovy 代码。这不是普通的 Groovy,您可以直接在 IDE 或 Groovy Shell 中执行。

Groovy CPS 转换您的代码以支持继续传递样式和正确的 Groovy 表达式,例如:

a = b = c = 0
Run Code Online (Sandbox Code Playgroud)

变成了看起来更像的东西:

eval(
  var("a"), 
  assign(
    eval(
      var("b"), 
      assign(
        eval(
          var("c"), 
          assign(0)
        )
      )
    )
  )
)
Run Code Online (Sandbox Code Playgroud)

CPS 解释器中这个表达式的问题是赋值不返回任何值,因此null值被分配给变量b,同样的事情发生在变量a

如果你想深入挖掘 CPS 调用块,你可以克隆 groovy-cps 项目并在com.cloudbees.groovy.cps.CpsTransformerTest类中编写一个简单的测试用例。

a = b = c = 0
Run Code Online (Sandbox Code Playgroud)

然后你可以在 上放置一个断点println cps并运行调试器。当您打开检查窗口时,您将看到类似于此的图片:

在此处输入图片说明

作为旁注,请记住,当将代码编译为字节码时,Groovy 编译器还会转换您的单行分配。如果您编译一个简单的 Groovy 脚本,例如:

eval(
  var("a"), 
  assign(
    eval(
      var("b"), 
      assign(
        eval(
          var("c"), 
          assign(0)
        )
      )
    )
  )
)
Run Code Online (Sandbox Code Playgroud)

然后在 IDE 中打开它的类文件以将字节码反编译为 Java 等效项,您将看到如下内容:

@Test
void testMultiVariablesInlineCPS() {
    def cps = parseCps('''
int a, b, c
a = b = c = 0
''')
    println cps
}
Run Code Online (Sandbox Code Playgroud)