jenkins插件-从插件内部启动和停止舞台

问题描述 投票:0回答:1

首先,是我想要这个疯狂的东西的背景。我正在Jenkins中构建一个插件,该插件为脚本提供API,这些API是从管道脚本开始的,以与jenkins独立通信。例如,shell脚本然后可以告诉jenkins从正在运行的脚本开始新的阶段。

我已经在脚本和Jenkins之间进行了交流,但是问题是我现在想尝试从代码中的回调开始一个阶段,但是我似乎不知道该怎么做。] >

我尝试过但失败的东西:

开始新的StageStep.java

我似乎找不到正确实例化并将步骤注入生命周期的方法。我研究了DSL.java,但是似乎无法到达实例来调用invokeStep(),也无法找出如何在正确的环境下实例化DSL.java的方法。

StageStepExecution.java并执行其操作。

似乎不是通过环境变量调用主体,而是在没有主体时设置一些操作并将状态保存在配置文件中。我无法确定“管道:舞台视图插件”是如何挂钩的,但是似乎无法读取配置文件。我尝试设置动作(甚至通过反射设置内部类),但似乎没有任何作用。

将自定义字符串作为Groovy正文并使用csc.newBodyInvoker()进行调用>我想到的一个骇人解决方案只是生成groovy脚本并像ParallelStep一样运行它。但是沙盒不允许我调用new GroovyShell().evaluate(""),如果我批准该调用,则“阶段”步骤将引发MissingMethodException。因此,我也不会在正确的环境中使脚本实例化。提供EnvironmentExpander没有任何区别。

参考和修改工作流/ {n} .xml在相关的workflow/{n}.xml中更改阶段的名称并重新启动服务器会更新该阶段的名称,但是将我的自定义阶段修改为看起来像常规阶段一样,似乎并没有将该阶段添加为阶段。

我研究过的东西:

  • 如果其他某个插件做了类似的事情,但我找不到启动其他步骤的任何插件示例。
  • [Jenkins如何处理脚本并开始执行步骤,但是似乎每个步骤都在解析脚本后通过方法名称直接调用,而我发现没有办法进行此操作。
  • 其他通过其他方法使用StageView的插件,但找不到。
  • 将AtomNode作为头部添加到正在运行的线程中,但是我找不到如何替换/添加头部,并且犹豫是否与jenkins的线程打交道。
  • 我在这个看似微不足道的电话上花了很多天,但我似乎无法弄清楚。

首先,是我想要这个疯狂的东西的背景。我正在Jenkins中构建一个插件,该插件为脚本提供API,这些API是从管道脚本开始的,以与jenkins独立通信。 ...

java jenkins jenkins-pipeline jenkins-plugins
1个回答
0
投票

因此,我尝试过的最新操作实际上可以正常工作,并且可以正确显示,但是效果不佳。我基本上重新实现了DSL.invokeStep()的实现,这需要我使用反射A LOT。这是不安全的,并且会随着任何变化而中断,因此我将在詹金斯的票务系统中打开一个问题,希望他们会为此添加一个公共接口。我只是希望这不会给我带来任何怪异的副作用。

// First, get some environment stuff
CpsThread cpsThread = CpsThread.current();
CpsFlowExecution currentFlowExecution = (CpsFlowExecution) getContext().get(FlowExecution.class);

// instantiate the stage's descriptor
StageStep.DescriptorImpl stageStepDescriptor = new StageStep.DescriptorImpl();

// now we need to put a new FlowNode as the head of the step-stack. This is of course not possible directly,
// but everything is also outside of the sandbox, so putting the class in the same package doesn't work
// get the 'head' field
Field cpsHeadField = CpsThread.class.getDeclaredField("head");
cpsHeadField.setAccessible(true);
Object headValue = cpsHeadField.get(cpsThread);
// get it's value
Method head_get = headValue.getClass().getDeclaredMethod("get");
head_get.setAccessible(true);
FlowNode currentHead = (FlowNode) head_get.invoke(headValue);

// crate a new StepAtomNode starting at the current value of 'head'.
FlowNode an = new StepAtomNode(currentFlowExecution, stageStepDescriptor, currentHead);

// now set this as the new head.
Method head_setNewHead = headValue.getClass().getDeclaredMethod("setNewHead", FlowNode.class);
head_setNewHead.setAccessible(true);
head_setNewHead.invoke(headValue, an);

// Create a new CpsStepContext, and as the constructor is protected, use reflection again
Constructor<?> declaredConstructor = CpsStepContext.class.getDeclaredConstructors()[0];
declaredConstructor.setAccessible(true);
CpsStepContext context = (CpsStepContext) declaredConstructor.newInstance(stageStepDescriptor,cpsThread,currentFlowExecution.getOwner(),an,null);

stageStepDescriptor.checkContextAvailability(context); // Good to check stuff I guess

// Create a new instance of the step, passing in arguments as a Map
Map<String, Object> stageArguments = new HashMap<>();
stageArguments.put("name", "mynutest");
Step stageStep = stageStepDescriptor.newInstance(stageArguments);

// so start the damd thing
StepExecution execution = stageStep.start(context);

// now that we have a callable instance, we set the step on the Cps Thread. Reflection to the rescue
Method mSetStep = cpsThread.getClass().getDeclaredMethod("setStep", StepExecution.class);
mSetStep.setAccessible(true);
mSetStep.invoke(cpsThread, execution);

// Finally. Start running the step
execution.start();
© www.soinside.com 2019 - 2024. All rights reserved.