引子:Jenkins 是目前阶段各大公司运用持续集成的主要轮子,而 Jenkins 能否发挥如此神威的主要原因即在于其众多的 Plugins 可以快速实现定制化需求。笔者因工作需要,体验了一把从零入门 Jenkins Plugin 开发。现把经验总结形成本文。
0x00 弄清 Jenkins 的主要概念先来看看 Jenkins 自己搭建的 CI 环境:Jenkins on Jenkins ,再结合下面这张官网给出的解释持续交付工作流程的示意图,简单学习 & 增加感性认识。
IBM 给出资料指出 Jenkins 在实现上有三个重要概念:
Stapler
Stapler 可以自动为应用程序对象绑定 URL,并创建直观的 URL 层次结构。而Jenkins 的类对象和 URL 绑定就是通过 Stapler 来实现的,通过该技术我们可以快速访问对应的Job及其相应资源。
持久化
Jenkins 使用文件来存储数据(所有数据都存储在$JENKINS_HOME)。
插件
Jenkins 的对象模型是可扩展的,通过 Jenkins 提供的可扩展点,我们可以开发插件扩展 Jenkins 的功能。
所有的 Plugin 都是在 Jenkins Master 上运行的。
0x01 选择 Jenkins 的扩展功能接口Jenkins 拥有极多的插件,而这些插件的开发都是基于 Jenkins 的扩展功能接口(Jenkins Extension Points)实现的。为了尽可能的实现定制化,Jenkins 的提供的扩展功能接口极多,详情可见 Jenkins Extension Points。
但这并不意味着我们需要一一掌握所有的扩展功能接口,Jenkins 官方提供的 资料 指出:
通常,一次构建过程包括如下几个步骤:
1.SCM checkout:检出源码,用于指定构建的目标。
2.Pre-build steps:预编译。
3.Build wrapper set up:构建环境准备。
4.Builder runs:执行构建的核心过程,例如调用Ant,Make等。
5.Recorder runs:记录构建过程中的输出,例如测试结果等。
6.Notifier runs:根据结果发送通知。
而这其中,除了 Pre-build 仅仅是 huson.tasks 的一个 Interface以外。其余五个扩展功能接口就是我们需要关注的重点:
hudson.scm.SCM
hudson.tasks.BuildWrapper
hudson.tasks.Builder
hudson.tasks.Recorder
hudson.tasks.Notifier
当然,如果想实现其他更复杂的功能,可以直接参考 官方文档 以及 。
0x02 搭建 Jenkins 开发环境 创建插件工程目录按照 Jenkins 插件开发的要求配置完 maven 的 settings.xml 配置文件之后,执行以下命令:
mvn -U org.jenkins-ci.tools:maven-hpi-plugin:create -DgroupId={your.gound.id} -DartifactId={your.plugin.id}其中,your.groud.id 和 your.plugin.id 填你插件的具体对应的值。命令执行之后,该目录下会产生一个名称是 {your.plugin.id} 的 HelloWorld 插件工程目录。
调试插件由于我们的 Plugin 的相关配置已由 Maven 工程的 pom.xml 定义好了,所以我们的仅需执行如下命令即可进行调试:
mvn hpi:run这句简单的命令就已经包含了诸如启动 Jetty 服务器,将 Jenkins 作为一个 Web 服务增加至上诉服务器以及在 Jenkins 中安装我们刚写生成的 HelloWorld 插件等一系列任务。
一旦上述过程成功执行,我们就可以可以在浏览器中通过下面的 URL 访问我们刚刚搭建好的 Jenkins 的主页:
http://localhost:8080这时我们就可以检查我们编写的插件是否满足我们的设计需要了。
发布及安装插件Jenkins 的插件通过 hpi 文件格式发布,所以在发布前,需要通过如下命令进行打包:
mvn package命令执行完成之后,即可在target目录下的生成插件的 hpi 文件和 jar 文件。
然后,我们无论是选择将 hpi 文件拷贝到 Jenkins Home 路径下的 plugin 目录中,或者选择通过 Jenkins 插件管理上传安装该 hpi 文件,均可完成插件的安装。
0x03 梳理 Jenkins Plugin 工程结构虽然 Jenkins 也支持Groovy 进行UI 开发,Jenkins 主要是用 Jelly 来进行 UI 管理。而 Jelly UI 技术的主要原理是通过服务端的渲染引擎将 Jelly 定义好的 XML 文件渲染成客户端需要的 HTML,Javascript 和 Ajax 等。
初步入门 Jenkins Plugin 的人(例如笔者自己)往往最困惑的一点就是如何理清 Jenkins Plugin 的工程结构以及 Plugin 的Jelly到底该怎么写。
通过上面的 mvn 指令我们生存的工程目录具有如下的布局结构:
pom.xml - Maven POM 文件,用于配置插件的设定
src/main/java - 插件的 Java 源文件
src/main/resources - 插件的 Jelly 视图文件
src/main/webapp - 插件的静态资源,如图片或 HTLM 等
0x04 Jelly UI 入门弄清楚了工程结构,剩下的事情就是到底怎么用 jelly 来写插件的 UI 了。而这无非也就是需要弄明白三件事情:
如何为指定对象创建一个 Jelly UI 页面;
如何读取 Jelly 中的用户输入;
如何操控 Jelly 反馈信息。
如何为指定对象创建一个 Jelly UI 页面前面说到,工程的目录结构中:
src/main/java - 插件的 Java 源文件
src/main/resources - 插件的 Jelly 视图文件
而 Jenkins 如何将两者之前建立起对应关系的呢?简单来说根据路径结构的一致性来建立关系。
假设你建立了一个java类,路径为
src/main/java/org/sample/HelloWorldBuilder.java则增加Jelly文件需要在resources文件夹中建立与类同名的目录:
src/main/resources/org/sample/HelloWorldBuilder/需要说明的是,Jenkins 通过固定的命名方式来确定页面文件属于局部配置还是全局配置:config.jelly 为局部配置;global.jelly 为全局配置。