我有一个Jenkins shared library,其中包含以下文件:
def foo() {
echo 'foo'
}
def bar(body) {
body.delegate = [:]
body.resolveStrategy = Closure.DELEGATE_FIRST
body()
}
管道脚本如下:
library 'testlib@master'
testlib.foo()
testlib.bar {
testlib.foo()
}
我得到以下输出:
[Pipeline] echo
foo
[Pipeline] End of Pipeline
java.lang.NullPointerException: Cannot invoke method foo() on null object
由于某种原因,传递给testlib.bar
的闭包不会再看到testlib
。只有在决议战略有利于代表时才会发生这种情况;如果我使用OWNER_ONLY
或OWNER_FIRST
则可行。如果我在代理中提供testlib
,也可以通过在地图中进行设置或仅设置body.delegate = body.owner
来实现,如果我通过仅提及owner.testlib.foo
来避免解决方案,它也会有效关闭。此外,这只发生在库代码中;如果我只是在Jenkinsfile中创建一个测试类,它可以正常工作。
似乎解决方案策略是检查委托,并且委托不提供该属性,它立即失败而不必费心去检查所有者。我做错了吗?
答案 0 :(得分:1)
我无法解释Jenkins管道中Groovy闭包委托的确切内容,但我遇到了类似的问题,我修复了这样的问题:
<强>乏/ foo.groovy:强>
def call() {
echo 'foo'
}
<强>乏/ bar.groovy:强>
//
// Something like:
//
// bar {
// script = {
// foo()
// return 'Called foo'
// }
// }
//
def call(body) {
def config = [:]
body.delegate = config
body.resolveStrategy = Closure.DELEGATE_FIRST
body()
// In the bar DSL element
echo 'I am bar'
// Expecting a script element as a closure. The insanceof needs script approvals
//assert config.script != null, 'A script element was not supplied'
//assert config.script instanceof Closure, 'The script element supplied must be a closure'
// Call the script closure
config.script.delegate = this
config.script.resolveStrategy = Closure.DELEGATE_FIRST
def result = config.script.call()
// Returning the script result
return result
}
<强> Jenkinsfile:强>
library 'testlib@master'
def result = bar {
script = {
foo()
return 'Called foo'
}
}
echo "result from bar: ${result}"
Jenkins输出:
[Pipeline] echo
I am bar
[Pipeline] echo
foo
[Pipeline] echo
result from bar: Called foo
[Pipeline] End of Pipeline
Finished: SUCCESS
只需考虑'bar'DSL闭包体传递,因为某些配置以某些赋值形式传递,例如“x = y”。因此,将其中一个作为由bar()的实现执行的闭包元素,然后您可以调用已定义的其他库元素。我在我的Github上有这个例子的代码:https://github.com/macg33zr/jenkins-pipeline-experiments。您可能还想在Jenkins之外尝试单元测试 - 我在这里使用库JenkinsPipelineUnit:https://github.com/macg33zr/pipelineUnit。如果在管道中做一些复杂的工作,我推荐这种单元测试方法,因为它会保持你的理智!