热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Jenkins系列:如何进行Jenkins插件开发

2019独角兽企业重金招聘Python工程师标准Jenkins介绍Jenkins是一个开源项目,提供了一种易于使用的持续集成系统,使开发者从繁杂的

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

Jenkins介绍

Jenkins 是一个开源项目,提供了一种易于使用的持续集成系统,使开发者从繁杂的集成中解脱出来,专注于更为重要的业务逻辑实现上。同时 Jenkins 能实施监控集成中存在的错误,提供详细的日志文件和提醒功能,还能用图表的形式形象地展示项目构建的趋势和稳定性。

在前面我们看见jenkins可以支持git, svn, maven等很多功能,这些都是Jenkins的插件,jenkins本身不提供很多功能,我们可以通过使用插件来满足我们的使用,接下来就介绍一下插件的原理以及我们怎么通过写一个自己的插件来满足我们的需求。

jenkins有很多的扩展点(ExtensitonPoint),它是Jenkins系统的某个方面的接口或抽象类。这些接口定义了需要实现的方法;而Jenkins插件需要实现这些方法,也可以叫做在此扩展点之上进行扩展Jenkins。有关扩展点的详细信息,请参阅Jenkins 官方ExtentionPoints文档。通过这些扩展点我们可以写插件来实现自己的需求。
下面是一些常用的扩展点:

  • Scm:代表源码管理的一个步骤,如下面的Git,Subversion就是扩展的Scm;

      143046_q48O_2470917.png

  • Trigger:代表一个构建的触发,当满足一个什么样的条件时触发这个项目开始构建。比较常用的触发就是当代码变更时触发,如果我们需要实现一些比较复杂的触发逻辑,就需要扩展Trigger这个扩展点;

          143505_jkQG_2470917.png

  • Builder: 代表构建的一个步骤,如下图中在构建过程中,我们可以增加一个构建步骤,而每一个选项都是对应一个Builder,在每一个Builder中都有自己不同的功能。如Execute shell,这就是一个ShellBuilder,意味着在构建过程中会执行一个shell命令;

           143347_ZG6B_2470917.png

  • Publisher:Publisher代表一个项目构建完成后需要执行的步骤,如选项中的E-Mail Notifaction就是一个Publisher插件,选择这个选项后,当项目构建完成,就会使用email来通知用户,假如想要在项目构建完成后将构建目标产物发送到服务器上,则可以扩展此扩展点。

         143657_tYB4_2470917.png

上面简单描述了一下插件和扩展点,接着我们可以搭建一个插件的开发环境。

Jenkins插件开发

这边我们创建一个名叫“jenkins-plugin-hello-world”的maven项目,具体如果创建maven项目,我这边不再详细描述。目录结构如下:

153520_73cJ_2470917.png

pom.xml

4.0.0jenkins-plugin-hello-worldorg.jenkins-ci.pluginsplugin1.565.3com.nd.component.java1.0.0-SNAPSHOTjenkins-plugin-hello-worldhpijunitjunit3.8.1test

HelloWorldBuilder.java

package com.lian.builder;import hudson.Extension;
import hudson.Launcher;
import hudson.model.BuildListener;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Descriptor;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Builder;import java.io.IOException;
import java.io.Serializable;import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;public class HelloWorldBuilder extends Builder implements Serializable {/** * Member Description*/private static final long serialVersionUID = 1L;/* job模板配置的属性值,即config.jelly中的print属性值 */private boolean print;// Fields in config.jelly must names in "DataBoundConstructor"@DataBoundConstructorpublic HelloWorldBuilder(boolean print) {this.print = print;}// We'll use this from the config.jelly.public boolean isPrint() {return print;}@Overridepublic boolean perform(AbstractBuild build, Launcher launcher, final BuildListener listener) throws IOException, InterruptedException {listener.getLogger().println("[INFO] isPrint: " + print);if (print) {listener.getLogger().println("[INFO] " + getDescriptor().getContent());}return true;}@Overridepublic DescriptorImpl getDescriptor() {return (DescriptorImpl) super.getDescriptor();}@Extensionpublic static final class DescriptorImpl extends BuildStepDescriptor {/* 系统配置里面该插件的全局配置属性,即global.jelly中的content属性值 */private String content;public String getContent() {return content;}public DescriptorImpl() {load();// 加载全局配置}@Overridepublic boolean configure(StaplerRequest req, net.sf.json.JSONObject json)
throws Descriptor.FormException {this.content = json.getString("content");save();// 将全局配置信息持久化到xmlreturn super.configure(req, json);}@Override@SuppressWarnings("rawtypes")public boolean isApplicable(Class aClass) {return true;}@Overridepublic String getDisplayName() {return "Hello World";// 插件显示名称}}}

首先创建一个类继承于Builder,代表使用这个插件是一个构建插件(如果继承于Scm,代表这个插件是一个源码插件,例如Git,Svn插件),然后实现Serializable接口(在进行文件操作时,需要序列化)。

在Jenkins的插件中,每一个插件类中都必须要有一个Descriptor内部静态类,它代表一个类的“描述者”,用于指明这是一个扩展点的实现,Jenkins是通过这个描述者才能知道我们自己写的插件。每一个“描述者”静态类都需要被@Extension注解,Jenkins内部会扫描@Extenstion注解来知道注册了有哪些插件。

在Desciptor类中有两个方法需要我们必须要进行重写,即

@Override
@SuppressWarnings("rawtypes")
public boolean isApplicable(Class aClass) {return true;
}

这个方法的返回值代表这个Builder在Project中是否可用,我们可以将我们的逻辑写在其中,例如判断一些参数,最后返回true或者false来决定这个Builder在此处是否可用;

@Override
public String getDisplayName() {return "Hello World";// 插件显示名称
}

这个方法返回的是一个String类型的值,这个名称会用在web界面上显示的名称。

154144_BTOj_2470917.png

如果我们在插件中需要获取一些系统设置参数,我们可以在Descriptor中获取一个参数对应Descriptor中的一个属性,其中的content属性是一个全局配置;

/* 系统配置里面该插件的全局配置属性,即global.jelly中的content属性值 */
private String content;public String getContent() {return content;
}public DescriptorImpl() {load();// 加载全局配置
}

然后可以在系统设置里面看到这个属性。

154240_GzLv_2470917.png

在Descirptor构造函数中使用load()进行加载全局配置,然后我们就可以在插件中获取到配置信息

@Override
public boolean configure(StaplerRequest req, net.sf.json.JSONObject json)
throws Descriptor.FormException {this.content = json.getString("content");save();// 将全局配置信息持久化到xmlreturn super.configure(req, json);
}

当在全局配置修改属性后,需要在configure()方法中调用save()将全局配置信息持久化到xml,我们可以在workspace的插件名.xml中看到持久化的数据。

在每个插件的perform()方法中,是perform真正开始执行的地方,我们如果要在插件中完成什么事,代码逻辑也是写在perform方法中,perform方法参数中build代表当前构建,workspace代表当前工作目录,通过workspace可以获取到当前工作目录的信息,并可以做些文件操作;launcher代表启动进程,可以通过launcher执行一些命令;listener代表一个监听器,可以将运行的内容信息通过listener输出到前台console output。

@Override
public boolean perform(AbstractBuild build, Launcher launcher, final BuildListener listener) throws IOException, InterruptedException {listener.getLogger().println("[INFO] isPrint: " + print);if (print) {listener.getLogger().println("[INFO] " + getDescriptor().getContent());}return true;
}

如上面的代码所示,在perform方法中我们通过listener打印了一行”[INFO] isPrint: “ + print,print是一个变量,这个变量的值从哪里来下面我会介绍一下给大家。

155656_axtt_2470917.png

在jenkins插件中,如果我们需要一些自定义的参数信息,如构建时执行一些命令,命令的内容是由用户输入,这个时候需要一个变量来记录用户输入的信息;所以在HelloWorkdBuilder中定义一个属性与用于输入的信息相对应,如上面的print属性

public class HelloWorldBuilder extends Builder implements Serializable {/** * Member Description*/private static final long serialVersionUID = 1L;/* job模板配置的属性值,即config.jelly中的print属性值 */private boolean print;// Fields in config.jelly must names in "DataBoundConstructor"@DataBoundConstructorpublic HelloWorldBuilder(boolean print) {this.print = print;}// We'll use this from the config.jelly.public boolean isPrint() {return print;}}

155046_FWao_2470917.png

这个属性的值是在job的配置过程中输入,由Jenkins从web前端界面传递过来的值,我们还需要在HelloWorldBuilder的构造方法中进行参数的注入。

类似于Spring的依赖注入,在这里Jenkins要求进行参数注入的构造方法需要用@DataBoundConstructor注解标注,以便Jenkins可以找到这个构造函数,并且调用这个构造函数,将web界面上配置的参数传递进HelloWorldBuilder,这样就可以在HelloWorldBuilder中使用这个属性了。

到此,这个插件的后台代码就已经搞定了,可以打包发布了。

执行命令打包:

mvn clean package -DskipTests

得到jenkins-plugin-hello-world.hpi,进行发布:

系统管理--》插件管理--》高级--》上传插件

161449_Z2O0_2470917.png

重启jenkins(可以参考https://my.oschina.net/lienson/blog/1514503),即可生效插件。

现在给大家讲讲怎么样编写这个前端配置的视图。

Jenkins中的视图

Jenkins 使用jelly来编写视图,Jelly 是一种基于 Java 技术和 XML 的脚本编制和处理引擎。Jelly 的特点是有许多基于 JSTL (JSP 标准标记库,JSP Standard Tag Library)、Ant、Velocity 及其它众多工具的可执行标记。Jelly 还支持 Jexl(Java 表达式语言,Java Expression Language),Jexl 是 JSTL 表达式语言的扩展版本。Jenkins的界面绘制就是通过Jelly实现的

在Jenkins 中的视图的类型有三种

  • global.jelly 全局的配置视图


xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">

  • config.jellyJob的配置视图


xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">

在定义一个属性时,使用标签代表这是一个属性,其中title是指在界面上显示的字段名,而field是指这个属性在HelloWorldBuilder中对应的属性名,jenkins通过这个名称来与HelloWorldBuilder中的属性相对应,从而使用@DataBoundConstructor标注的构造函数将这些变量注入到HelloWorldBuilder类中。

  • help-属性名.html 帮助视图 html片段

Help file for fields are discovered through a file name convention. This file ishelp for the "name" field. You can have arbitrary HTML here. You can writethis file as a Jelly script if you need a dynamic content (but if you do so, changethe extension to .jelly).

这是Jenkins 中的三种视图,上面也介绍了两个简单的控件textbox和checkbox的使用,更多的关于Jelly的视图使用可以查看jelly官网。

想要更详细了解Jelly用法,可以参考http://blog.csdn.net/kittyboy0001/article/details/18710161。

总结

在本文,主要介绍了Jenkins的简单使用,以及Jenkins的插件开发环境,以及Jenkins插件结构的一些介绍。本文主要还是做一个简单入门介绍,如果想要了解更多的关于Jenkins的东西,还是需要去看Jenkins的官方wiki, 上面有详细的关于每个扩展点已经Jenkins的api的使用介绍,同样,你也可以下载Jenkins的源码来查看内部的一些实现方式。

在Github Jenkinci也有很多的关于Jenkins插件的源码,我们可以通过源码了解一些扩展点是怎样使用,参照别人的源码来写出自己的插件。

参考

http://www.jianshu.com/p/8c05b6191d2f

 


转:https://my.oschina.net/lienson/blog/1531341



推荐阅读
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • 本文介绍了Linux系统中正则表达式的基础知识,包括正则表达式的简介、字符分类、普通字符和元字符的区别,以及在学习过程中需要注意的事项。同时提醒读者要注意正则表达式与通配符的区别,并给出了使用正则表达式时的一些建议。本文适合初学者了解Linux系统中的正则表达式,并提供了学习的参考资料。 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • mac php错误日志配置方法及错误级别修改
    本文介绍了在mac环境下配置php错误日志的方法,包括修改php.ini文件和httpd.conf文件的操作步骤。同时还介绍了如何修改错误级别,以及相应的错误级别参考链接。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了Linux Shell中括号和整数扩展的使用方法,包括命令组、命令替换、初始化数组以及算术表达式和逻辑判断的相关内容。括号中的命令将会在新开的子shell中顺序执行,括号中的变量不能被脚本余下的部分使用。命令替换可以用于将命令的标准输出作为另一个命令的输入。括号中的运算符和表达式符合C语言运算规则,可以用在整数扩展中进行算术计算和逻辑判断。 ... [详细]
author-avatar
笨笨的小白鼠
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有