Jenkins 管道将 vars/mavenBuildSpike.groovy 中的方法调用替换为赋值 "new NullObject"
Jenkins pipeline replaces method call in vars/mavenBuildSpike.groovy with assignment "new NullObject"
我在 vars/mavenBuildSpike.groovy
中有此代码:
@NonCPS
def createSqBuilder(SqBuildConfig config) {
System.out.println("createSqBuilder=${config}")
// The constructor contains code which the CPS transformer can't handle.
def result = new SqBuilder(config)
System.out.println("result=${result}")
return result
}
def call(Closure body) {
echo 'Creating ConfigBuilderWrapper'
def wrapper = new ConfigBuilderWrapper()
echo 'Calling apply()'
wrapper.apply(body)
echo 'Done processing closure'
def config = wrapper.builder.build()
echo "config=${config.dump()}"
echo 'Creating builder'
def builder = createSqBuilder(config) // <<--- This doesn't work.
echo "builder=${builder}"
echo builder.dump()
...
输出为:
...everything looks good...
[Pipeline] echo
Creating builder
[Pipeline] echo
builder=null
[Pipeline] End of Pipeline
java.lang.NullPointerException: Cannot invoke method hashCode() on null object
at org.codehaus.groovy.runtime.NullObject.hashCode(NullObject.java:174)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.dump(DefaultGroovyMethods.java:291)
...
at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:159)
at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:17)
at mavenBuildSpike.call(...\branches\master\builds\libs\sq-pipeline-library-spike\vars\mavenBuildSpike.groovy:33)
at WorkflowScript.run(WorkflowScript:4)
at ___cps.transform___(Native Method)
....
也就是说,方法 createSqBuilder
从未被调用,只是被赋值替换:def builder = new NullObject()
.
为什么会这样,我该如何解决?
在 运行 代码之前,Jenkins 将执行一个名为 "CPS transformation" 的 AST 转换。这个转换器不支持 Groovy 可以做的所有事情,它不会告诉你什么时候不能做 - 你只会得到奇怪或无用的错误消息 运行 结果代码,有时没有错误完全 - 构建将简单地失败,没有任何错误消息或任何堆栈跟踪。
CPS 转换似乎不喜欢用参数调用构造函数。这对我有用:
@Field // groovy.transform.Field
SqBuilder builder = new SqBuilder()
def call(Closure body) {
...
//def builder = createSqBuilder(config) // Doesn't work!!!
builder.init(config) // This works; move the code from the constructor to the init() method.
...
需要 @Field
注释才能将局部变量 builder
转换为 Groovy 将在运行时创建的 class 的字段。这个 class 的名字是 WorkflowScript
.
您也可以只键入 builder = new SqBuilder()
(在变量名称前不键入或 def
)。但这会将 builder
放入全局变量池(在 Groovy 中称为 "Binding")。 Jenkins 把它自己的东西放在那里(比如 env
或 scm
)所以当你安装更多插件时可能会导致奇怪的问题。
另请参阅:
我在 vars/mavenBuildSpike.groovy
中有此代码:
@NonCPS
def createSqBuilder(SqBuildConfig config) {
System.out.println("createSqBuilder=${config}")
// The constructor contains code which the CPS transformer can't handle.
def result = new SqBuilder(config)
System.out.println("result=${result}")
return result
}
def call(Closure body) {
echo 'Creating ConfigBuilderWrapper'
def wrapper = new ConfigBuilderWrapper()
echo 'Calling apply()'
wrapper.apply(body)
echo 'Done processing closure'
def config = wrapper.builder.build()
echo "config=${config.dump()}"
echo 'Creating builder'
def builder = createSqBuilder(config) // <<--- This doesn't work.
echo "builder=${builder}"
echo builder.dump()
...
输出为:
...everything looks good...
[Pipeline] echo
Creating builder
[Pipeline] echo
builder=null
[Pipeline] End of Pipeline
java.lang.NullPointerException: Cannot invoke method hashCode() on null object
at org.codehaus.groovy.runtime.NullObject.hashCode(NullObject.java:174)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.dump(DefaultGroovyMethods.java:291)
...
at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:159)
at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:17)
at mavenBuildSpike.call(...\branches\master\builds\libs\sq-pipeline-library-spike\vars\mavenBuildSpike.groovy:33)
at WorkflowScript.run(WorkflowScript:4)
at ___cps.transform___(Native Method)
....
也就是说,方法 createSqBuilder
从未被调用,只是被赋值替换:def builder = new NullObject()
.
为什么会这样,我该如何解决?
在 运行 代码之前,Jenkins 将执行一个名为 "CPS transformation" 的 AST 转换。这个转换器不支持 Groovy 可以做的所有事情,它不会告诉你什么时候不能做 - 你只会得到奇怪或无用的错误消息 运行 结果代码,有时没有错误完全 - 构建将简单地失败,没有任何错误消息或任何堆栈跟踪。
CPS 转换似乎不喜欢用参数调用构造函数。这对我有用:
@Field // groovy.transform.Field
SqBuilder builder = new SqBuilder()
def call(Closure body) {
...
//def builder = createSqBuilder(config) // Doesn't work!!!
builder.init(config) // This works; move the code from the constructor to the init() method.
...
需要 @Field
注释才能将局部变量 builder
转换为 Groovy 将在运行时创建的 class 的字段。这个 class 的名字是 WorkflowScript
.
您也可以只键入 builder = new SqBuilder()
(在变量名称前不键入或 def
)。但这会将 builder
放入全局变量池(在 Groovy 中称为 "Binding")。 Jenkins 把它自己的东西放在那里(比如 env
或 scm
)所以当你安装更多插件时可能会导致奇怪的问题。
另请参阅: