在 workflow-cps groovy 代码中获取 CpsScript 实例?
Obtain CpsScript instance in workflow-cps groovy code?
目前正在为非常具体的 jenkins 场景编码很多 groovy。
问题是我必须跟踪上下文的当前 CpsScript
-实例(获取属性、环境等)及其 invokeMethod
(工作流程步骤等).
目前这意味着我将管道 groovy 脚本中的 this
传递到我的条目 class 并从那里分别传递到每个 class,这是 很烦人。
脚本实例由 CpsFlowExecution
创建并存储在 Continuable
实例和 CpsThreadGroup
中,两者都不允许您检索它。
似乎 GlobalVariable
派生扩展收到它,因此它们有一个上下文,但我目前的知识不足以编写我自己的扩展来利用它。
所以问题是:
有谁知道跟踪 CpsScript
实例的方法,不需要我将它传递给我创建的每个新 class 实例? (或者:从任何地方获取 - 这真的需要这么难吗?)
继续研究实现此目标的方法。甚至写了一个提供 cpsScript
全局变量的 jenkins 插件。不幸的是,您需要该实例为该调用提供上下文,因此它没有用。
因此,作为 "least bad solution"(tm),我创建了一个 class,我称之为 ScriptContext
,我可以将其用作我的管道 class 的基础 classes(它实现了 Serializable
)。
当你编写你的管道脚本时,你要么将它CpsScript
静态传递一次:
ScriptContext.script = this
或者,如果您从它派生(确保调用 super()
):
new MyPipeline(this)
如果您的 class 来自 ScriptContext
,您的工作就完成了。一切都会像您没有创建 class 而只是使用自动转换一样工作。如果您使用除 println 之外的任何 CpsScript 级函数,您可能也想在此处添加这些函数。
您可以在其他任何地方调用 ScriptContext.script
来获取脚本实例。
class 代码(删除了大部分注释以使其尽可能短):
package ...
import org.jenkinsci.plugins.workflow.cps.*
class ScriptContext implements Serializable {
protected static CpsScript _script = null
ScriptContext(CpsScript script = null) {
if (!_script && script) {
_script = script
}
}
ScriptContext withScript(CpsScript script) {
setScript(script)
this
}
static void setScript(CpsScript script) {
if (!_script && script) {
_script = script
}
}
static CpsScript getScript()
{
_script
}
// functions defined in CpsScript itself are not automatically found
void println(what) {
_script.println(what)
}
/**
* For derived classes we provide missing method functionality by trying to
* invoke the method in script context
*/
def methodMissing(String name, args) {
if (!_script) {
throw new GroovyRuntimeException('ScriptContext: No script instance available.')
}
return _script.invokeMethod(name, args)
}
/**
* For derived classes we provide missing property functionality.
* Note: Since it's sometimes unclear whether a property is an actual property or
* just a function name without brackets, use evaluate for this instead of getProperty.
* @param name
* @param args
* @return
*/
def propertyMissing(String name) {
if (!_script) {
throw new GroovyRuntimeException('ScriptContext: No script instance available.')
}
_script.evaluate(name)
}
/**
* Wrap in node if needed
* @param body
* @return
*/
protected <V> V node(Closure<V> body) {
if (_script.env.NODE_NAME != null) {
// Already inside a node block.
body()
} else {
_script.node {
body()
}
}
}
}
目前正在为非常具体的 jenkins 场景编码很多 groovy。
问题是我必须跟踪上下文的当前 CpsScript
-实例(获取属性、环境等)及其 invokeMethod
(工作流程步骤等).
目前这意味着我将管道 groovy 脚本中的 this
传递到我的条目 class 并从那里分别传递到每个 class,这是 很烦人。
脚本实例由 CpsFlowExecution
创建并存储在 Continuable
实例和 CpsThreadGroup
中,两者都不允许您检索它。
似乎 GlobalVariable
派生扩展收到它,因此它们有一个上下文,但我目前的知识不足以编写我自己的扩展来利用它。
所以问题是:
有谁知道跟踪 CpsScript
实例的方法,不需要我将它传递给我创建的每个新 class 实例? (或者:从任何地方获取 - 这真的需要这么难吗?)
继续研究实现此目标的方法。甚至写了一个提供 cpsScript
全局变量的 jenkins 插件。不幸的是,您需要该实例为该调用提供上下文,因此它没有用。
因此,作为 "least bad solution"(tm),我创建了一个 class,我称之为 ScriptContext
,我可以将其用作我的管道 class 的基础 classes(它实现了 Serializable
)。
当你编写你的管道脚本时,你要么将它CpsScript
静态传递一次:
ScriptContext.script = this
或者,如果您从它派生(确保调用 super()
):
new MyPipeline(this)
如果您的 class 来自 ScriptContext
,您的工作就完成了。一切都会像您没有创建 class 而只是使用自动转换一样工作。如果您使用除 println 之外的任何 CpsScript 级函数,您可能也想在此处添加这些函数。
您可以在其他任何地方调用 ScriptContext.script
来获取脚本实例。
class 代码(删除了大部分注释以使其尽可能短):
package ...
import org.jenkinsci.plugins.workflow.cps.*
class ScriptContext implements Serializable {
protected static CpsScript _script = null
ScriptContext(CpsScript script = null) {
if (!_script && script) {
_script = script
}
}
ScriptContext withScript(CpsScript script) {
setScript(script)
this
}
static void setScript(CpsScript script) {
if (!_script && script) {
_script = script
}
}
static CpsScript getScript()
{
_script
}
// functions defined in CpsScript itself are not automatically found
void println(what) {
_script.println(what)
}
/**
* For derived classes we provide missing method functionality by trying to
* invoke the method in script context
*/
def methodMissing(String name, args) {
if (!_script) {
throw new GroovyRuntimeException('ScriptContext: No script instance available.')
}
return _script.invokeMethod(name, args)
}
/**
* For derived classes we provide missing property functionality.
* Note: Since it's sometimes unclear whether a property is an actual property or
* just a function name without brackets, use evaluate for this instead of getProperty.
* @param name
* @param args
* @return
*/
def propertyMissing(String name) {
if (!_script) {
throw new GroovyRuntimeException('ScriptContext: No script instance available.')
}
_script.evaluate(name)
}
/**
* Wrap in node if needed
* @param body
* @return
*/
protected <V> V node(Closure<V> body) {
if (_script.env.NODE_NAME != null) {
// Already inside a node block.
body()
} else {
_script.node {
body()
}
}
}
}