Tips: 先说个感想,要开发Jenkins插件,真的要多看其他插件的源码。
添加功能菜单到每个任务
先看效果,如下图。一个普通的任务,我们想在侧边栏加上自己的功能。
官方给的Demo里,讲的是如何在build,也就是每次构建
的侧边栏加功能菜单。其实差不多,先需要一个Action。build里加action是在perform
方法中addAction
,而我们需要继承一个扩展点类,在其createFor
方法中返回action,具体如下:
- 添加扩展点,注意不要漏掉注解
@Extension
@Extension
public class PaasTransientProjectActionFactory extends TransientProjectActionFactory {
@Override
public Collection<? extends Action> createFor(AbstractProject target) {
return Collections.singleton(new StopAction(target));
}
}
- Action类没啥特别的,多的doLog方法我们后边讲。
public class StopAction implements Action {
private AbstractProject target;
public StopAction(AbstractProject target) {
this.target = target;
}
public void doLog(StaplerRequest req, StaplerResponse rsp) throws IOException {
boolean flag = false;
String name = req.getParameter("jobName");
for (Thread thread : Thread.getAllStackTraces().keySet()) {
if (thread.getName().contains(name)) {
thread.stop();
rsp.getWriter().write("1");
flag = true;
break;
}
}
if (!flag) {
rsp.getWriter().write("0");
}
}
public AbstractProject getTarget() {
return target;
}
@Override
public String getIconFileName() {
return "document.png";
}
@Override
public String getDisplayName() {
return "僵尸任务终止器";
}
@Override
public String getUrlName() {
return "zombie";
}
}
前后台通信
之前我分享过一篇【Jenkins插件开发4】自定义后台接口,这次又有不一样的后台接口方式。
Jenkins使用一种叫Stapler的方式,将对象与url绑定起来,大家感兴趣可以自行搜索学习,我这里只说实现。
jelly页面如下,功能很简单,页面上有个按钮,点击就请求后台接口执行:
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout" xmlns:st="jelly:stapler">
<l:layout title="Greeting">
<l:side-panel>
<st:include page="sidepanel.jelly" it="${it.target}" optional="true" />
</l:side-panel>
<l:main-panel>
<b>此方法存在不安全可能,非必要不使用。正常停止任务请在build后点击停止按钮。</b>
<button onclick="stop()">立即终止${it.target.fullName}</button>
</l:main-panel>
</l:layout>
<script>
function stop() {
new Ajax.Request(location.href + "/log", {
parameters:"jobName=${it.target.fullName}",
onComplete:function(rs) {
alert(rs.responseText==1?'已终止,请稍后':'未成功');
}
});
}
</script>
</j:jelly>
这里后台接口的地址是:job任务地址 + action类urlName + action类方法名
大家意会一下吧,以我为例
Jenkins地址是:http://localhost:8080/jenkins
Job地址是:http://localhost:8080/jenkins/job/123
Job功能菜单地址是:http://localhost:8080/jenkins/job/123/zombie
Job功能后台地址是:http://localhost:8080/jenkins/job/123/zombie/log
,对应Action里的doLog方法
啥是僵尸任务
这是我遇到的一个问题,任务都执行完了,但build还是运行状态,并且点stop也终止不了。最后我终于找到了一个不太优雅的解决办法(ps:当然,重启是可以解决的。)那就是执行以下脚本:
String name = "你的任务全名"
Thread.getAllStackTraces().keySet().each() {
t -> if (t.getName().contains(name)) { t.stop(); }
}
在下图的地方执行:
不过,我们公司大规模使用,权限分离,这个全局的脚本执行页面是不开放给每个组的,我只好将他开发成上面的功能了。