我在所有管道上隐式加载了global shared library on Jenkins,然后我的Jenkinsfile
就是这样:
new com.company.Pipeline()()
然后共享库在目录src/com/company
上有一些文件,位于Pipeline.groovy
类之下:
package com.company
import static Utils.*
def call() {
// some stuff here...
}
问题是,这种方式我必须静态声明所有方法,因此我丢失了上下文,并且在没有Pipeline
类'实例的情况下无法轻松访问jenkins的方法。正如您可以看到here他们将this
传递给方法mvn
。
想到避免这种情况我想知道通过调用Utils.install this
而不是import static Utils.*
来动态地将所有方法添加为闭包,那么我的Utils.groovy
就是这样:
package com.company
private Utils() {}
static def install(def instance) {
def utils = new Utils()
// Some extra check needed here I know, but it is not the problem now
for (def method in (utils.metaClass.methods*.name as Set) - (instance.metaClass.methods*.name as Set)) {
def closure = utils.&"$method"
closure.delegate = instance
instance.metaClass."$method" = closure
}
}
def someMethod() {
// here I want to use sh(), tool(), and other stuff freely.
}
但它引发GStringImpl
无法转换为String
错误,我相信.&
不能使用变量,如何将方法转换为具有方法名称的闭包变量?我有MetaMethod
主要是CachedMethod
实例,如果有可能将它变为ClosureMetaMethod
实例,问题可以解决,但每当我搜索groovy的闭包转换方法时我刚刚找到了.&
解决方案!
如果我使用instance.metaClass.someMethod = utils.&someMethod
它可以正常工作,但我希望它是动态的,因为我添加新方法而无需担心共享它。
答案 0 :(得分:2)
有一种方法可以动态完成。符号utils.&someMethod
返回一个MethodClosure
对象,可以使用其构造函数进行简单实例化:
MethodClosure(Object owner, String method)
请考虑以下示例:
class Utils {
def foo() {
println "Hello, Foo!"
}
def bar() {
println "Hello, Bar!"
}
}
class Consumer {
}
def instance = new Consumer()
def utils = new Utils()
(utils.metaClass.methods*.name - instance.metaClass.methods*.name).each { method ->
def closure = new MethodClosure(utils, method)
closure.delegate = instance
instance.metaClass."$method" = closure
}
instance.foo() // Prints "Hello, Foo!"
instance.bar() // Prints "Hello, Bar!"
在此示例中,我使用def closure = new MethodClosure(utils, method)
获取对象方法引用,然后将此方法添加到instance
对象。我希望它有所帮助。