jenkin插件的开发
背景
在迁移飞书的过程中,原先的jenkins钉钉机器人功能也就需要迁移,别看他们工作方式很像,但是API不同,无法复用原先的钉钉通知插件。
不一样体现在哪里呢,举一个最简单的文字消息的例子
1 | # 以下是两个平台的post请求的json body内容 |
解决方式
- 找下现成的轮子
- 搜了一下字节有自己的一个方案,研究下来要配合Lark的一个进行使用,那个在内测阶段,也找不到相应的群聊机器人
- 搜一下大家的解决方案
- 写一个python脚本然后加一个shell执行的
- 不行的话curl一下也行
- 不如自己写一个吧
Jenkins
Jenkins 是由 Java 语言开发的最流行的 CI/CD 引擎。
如果自建过jenkins的话,应该都知道插件的丰富和重要性,不少方便的功能都是插件实现的,能想到的基本上都有插件实现。
首先你可能想自己搭一个jenkins
docker-compose的方式启动为例,不是本文重点,没有搭好的jenkin也可以开发
- 可以参考这里https://www.jenkins.io/download/
- 简单的docker-compose.yml实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18version: '3.7'
services:
jenkins:
image: jenkins/jenkins:lts-jdk11
privileged: true
user: root
restart: always
environment:
- JAVA_OPTS=-Dsun.jnu.encoding=UTF-8 -Dfile.encoding=UTF-8
- JAVA_TOOL_OPTIONS=-Dsun.jnu.encoding=UTF-8 -Dfile.encoding=UTF-8
- LC_ALL=C.UTF-8
ports:
- 8083:8080
- 50003:50000
container_name: my-jenkins-3
volumes:
- ~/jenkins_data:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock - docker-compose up -d
- 更新方式
- 略
插件开发
准备工作
- 安装JAVA JDK
- 安装Maven
- 输入
mvn -v
确认准备工作OK
创建Helloworld插件来建立基础理解
运行
1 | mvn -U archetype:generate -Dfilter=io.jenkins.archetypes: |
1 | Choose archetype: |
按照提示依次选择hello-world-plugin, 最新版本, 输入插件id 回车到底。就创建好了hello目录。代码传到了这里
插件目录结构:
- pom.xml: maven使用这个文件来构建插件。这里声明了插件的版本以及依赖关系
- src/main/java:java源码。包括插件注册、jelly视图背后的数据绑定、业务逻辑
- src/main/resources:jelly视图文件,用于在web界面上显示
- src/main/webapp:静态的资源文件,例如图片和html文件,还能写js,暂时可以忽略
- src/test: 测试文件
我们结合实际效果,重点看下java源码和jelly视图文件。
运行调试插件
执行mvn clean && mvn hpi:run
看到Jenkins is fully up and running
代表本地已经启动了一个jenkins并且安装上了插件,可以访问http://127.0.0.1:8080/jenkins,进行效果查看![](./jenkin-plugin/local-jenkins.jpg)
helloword插件介入的是job的build流程,因此我们创建一个freestyle的job。在下图这个界面的Build栏目点击说,你好,世界
这里的对话框进行填写后,点击save
按钮进行保存。
至此,我们创建了一个Job,并且在这个job的构建(Build)部分,添加了一个插件功能。
我们跑一下这个Job,会发现输出多了我们设置的欢迎词
我们可以把插件分为两个功能部分
参数的编辑和存储,官方文档
- 视图:
src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder
目录。- 其中config.jelly是核心,定义了html表格以及用到的数据字段
- help-x.html和Messages.properties对应的是问号的内容和表格输入的校验文案
- 配合视图使用的java类
src/main/java/io/jenkins/plugins/sample/HelloWorldBuilder.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43// 视图关联部分代码节选
public class HelloWorldBuilder extends Builder implements SimpleBuildStep {
private final String name;
private boolean useFrench;
// 将job存储的值读进来
public HelloWorldBuilder(String name) {
this.name = name;
}
// jelly渲染获取到值的关键,对应field中的name字段
public String getName() {
return name;
}
// 布尔值jelly渲染获取到值的关键,对应field中的useFrench字段
public boolean isUseFrench() {
return useFrench;
}
// 将job存储的值读进来
public void setUseFrench(boolean useFrench) {
this.useFrench = useFrench;
}
public static final class DescriptorImpl extends BuildStepDescriptor<Builder> {
...
}
}
* 实际build过程中的业务
* helloword插件实现的是在构建的output中打印一段字符串,我们要做的是覆写`SimpleBuildStep`中的perform函数即可
```java
public void perform(Run<?, ?> run, FilePath workspace, EnvVars env, Launcher launcher, TaskListener listener) throws InterruptedException, IOException {
if (useFrench) {
listener.getLogger().println("Bonjour, " + name + "!");
} else {
listener.getLogger().println("Hello, " + name + "!");
}
}- 其中,listener是本次构建的运行监听器,调用它的logger可以输出内容到output
- 视图:
其他扩展点
- JobProperty
- Build Triggers
- Build
- Post-build
- RunListener
结合实际需求,参考类似扩展点的插件源码,实现自己的需求
回到我们原始的需求
参考现有的钉钉机器人,配置上主要扩展了两个点(全局配置,和JobProperty的配置),业务上扩展了RunListener。
钉钉机器人迭代的功能已经比较复杂,我们从简来实现第一版。即,仅支持配置webhooks,在JobProperty输入飞书机器人的webhooks地址列表,以";"
分隔。发送时间则默认开始和结束均发送。
仓库地址
我们仅需要配置一个字符串即可,因此jelly模板src/main/resources/io/jenkins/plugins/FeishuJobProperty/config.jelly
、以及src/main/java/io/jenkins/plugins/FeishuJobProperty.java
数据配置java都很简洁
业务实现部分,我们实现RunListener类并且复写掉onStarted以及onCompleted函数,在这两个函数里发送一个HTTP的POST请求到飞书webhooks地址即可
- 发送到飞书需要的信息用过onStarted传入的run都可以拿到(参考dingding机器人)
- 参照飞书的card规范美化消息,消息构建和发送封了一个FeishuService。
pom.xml
引入了okhttp以及fastjson,可能需要处理依赖冲突,最后把冲突的依赖都指定了版本
Job的配置方式
从飞书复制机器人地址
在job的配置中填写地址并保存
构建一次,飞书收到消息的实际效果
参考资料
插件的发布
打包自己用
- 打包
mvn clean && mvn package
- 在target目录下找到生成的hpi文件
- 到jenkins的全局系统管理 -> 插件管理 -> 上传插件选择hpi文件 -> 自动重启jenkins即可
发布到官方仓库
- 仓库上传到自己的github
- 在这里新建issue
- 后续的步骤持续更新中,目前github issue相关人员的回复是很快的,表示会深入看一下