来到新公司不久,主管安排一个jenkins 插件开发的小需求给我,让我练练手,之前从未接触过相关内容,一切从0开始,做了一个月,基本完成需求上的功能,期间遇到不少困难,记录做以总结。
现阶段网上相关的指导还是比较匮乏,我个人觉得比较好的方法是:参考已有插件的源码!

需求大致是这样的:
点击进入某次历史编译,将本次上传至Artifactory的文件copy 到Artifactory中的release目录下,目的是可以选择性的选择某次编译生成的文件copy到release目录下供测试的同事进行测试。

1、 开发环境的搭建
包括本地JDK、maven、eclipse等,参考链接:
https://jenkins.io/doc/developer/tutorial/prepare/
其中遇到的问题有:

  • 公司的网络需要代理访问外网:(没有外网访问问题的可以忽略)
    https://blog.csdn.net/u010531676/article/details/54343845
    maven/conf/setting.xml中添加:

          <proxies><proxy><active>true</active><protocol>https</protocol><username>username</username><password>password</password><host>company host</host><port>888</port><nonProxyHosts>www.google.com|*.somewhere.com</nonProxyHosts></proxy></proxies> 

2、 创建一个空的plugin工程,调试以及生成插件

先是根据官方文档创建了一个空的工程,当时很费解,为什么我的工程里面没有HelloWorldBuilder.java文件?网上一些教程里面都是创建后就有这个文件的,因为是小白,这个东西当时纠结了好几个小时,后面尝试后才知道官方文档给出的是:

mvn archetype:generate -Dfilter=io.jenkins.archetypes:empty-plugin

默认为空的工程
可以使用:

mvn -U archetype:generate -Dfilter=io.jenkins.archetypes:

然后选择是空的工程还是hello_world工程,新手建议先通过hello_world工程了解工程结构,真正写项目建议基于empty-plugin。

Choose archetype:
1: remote -> io.jenkins.archetypes:empty-plugin (Skeleton of a Jenkins plugin with a POM and an empty source tree.)
2: remote -> io.jenkins.archetypes:global-configuration-plugin (Skeleton of a Jenkins plugin with a POM and an example piece of global configuration.)
3: remote -> io.jenkins.archetypes:global-shared-library (Uses the Jenkins Pipeline Unit mock library to test the usage of a Global Shared Library)
4: remote -> io.jenkins.archetypes:hello-world-plugin (Skeleton of a Jenkins plugin with a POM and an example build step.)
5: remote -> io.jenkins.archetypes:scripted-pipeline (Uses the Jenkins Pipeline Unit mock library to test the logic inside a Pipeline script.)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): : 4

调试插件:mvn hpi:run 访问http://localhost:8080/jenkins 可查看插件效果
生成插件:mvn package 插件为hpi格式,会保存在target/目录下,也可以手动安装hpi文件查看插件效果

参考链接:
https://wiki.jenkins.io/display/JENKINS/Plugin+tutorial
https://jenkins.io/doc/developer/tutorial/create/

3、 jenkins plugin 目录结构
这块网上的说明相对还是比较多的,引用网上给出的:

  • pom.xml - Maven POM 文件,用于配置插件的设定,包括插件所依赖的架包、JDK版本、插件名称和描述等。
  • src/main/java - 插件的 Java 源文件
  • src/main/resources - 插件的 Jelly 视图文件
  • src/main/webapp - 插件的静态资源,如图片或 HTLM 等,本次项目中没有使用到。

4、Plugin UI之configure/General中添加参数视图

jenkins插件的UI(界面)是通过与java文件一一对应的jelly文件去体现的,举个例子:
在官方给的helloworld工程中:

src/main/java/org/sample/HelloWorldBuilder.java
src/main/resources/org/sample/HelloWorldBuilder/config.jelly
两者是一一对应的,其中config.jelly用于工程相关参数配置,如果换成global.jelly则用于全局参数配置

一个jenkins build 的过程一般包括:

  • Source Code Management
  • Build Triggers
  • Build Environment
  • Build
  • Build Environment

pipeline job往往以上过程全部在pipeline code中去实现,本次需求是要求在pipeline运行结束后执行copy操作,继承类似Builder,Recorder等构建中的扩展类是不能满足需求的。
后来把目标放在了jenkins的configure中的General 上,其中的选项可以和构建中无关。通过已有插件的源码,找到了JobProperty 类。效果如下:

java部分代码部分如下:

package io.jenkins.plugins.sample;import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;import hudson.Extension;
import hudson.model.Job;
import hudson.model.JobProperty;
import hudson.model.JobPropertyDescriptor;
import net.sf.json.JSONObject;public class MyJobProperty extends JobProperty<Job<?, ?>> {private final String yourname;@DataBoundConstructor    //构造函数需要添加DataBoundConstructor标记public MyJobProperty(String yourname) {this.yourname = yourname;}public String getYourname() {//和jelly中的field="yourname"相关联return yourname;}@Extension   //扩展标记public static final class DescriptorImpl extends JobPropertyDescriptor { //Descriptor 及其各种延伸的Descriptor ,例如:JobPropertyDescriptor,BuildStepDescriptor等,//往往继承该类需要加上@Extension 用来告诉jenkins是JobPropertyDescriptor的扩展,需要创建对应的instance对象,已经对参数的校验。@Overridepublic JobProperty<?> newInstance(StaplerRequest req, JSONObject formData) throws FormException {//满足某种条件后创建MyJobProperty 对象MyJobProperty jp = req.bindJSON(MyJobProperty.class, formData.getJSONObject("myjobproperty"));if (jp == null) {return null;}return jp;}@Overridepublic boolean isApplicable(Class<? extends Job> jobType) {//是否对所有项目类型可用return super.isApplicable(jobType);}@Overridepublic String getDisplayName() {//本例中并未用到,在例如Builder类型的插件,添加构建过程的名称return "MyJobProperty";}}
}

jelly部分代码如下:

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form"><f:optionalBlock name="myjobproperty" title="click and input your name" checked="${!empty(instance)}"><f:entry title="your name " field="yourname"><f:textbox /></f:entry></f:optionalBlock>
</j:jelly>

5、Plugin UI之主面板和侧边栏部分
Action类可以在jenkins中的主面板中添加视图效果,其中的重写方法为侧边栏图标、名称、以及url名称

@Override
public String getIconFileName() {return  "document.png";
}@Override
public String getDisplayName() {return "MyJobProperty";
}@Override
public String getUrlName() {return "myjobproperty";
}
这里需要注意的是getUrlName() 返回值不能有空格,我在插件调试过程中出现了侧边栏不能点击的问题,就是因为返回值中有空格导致的。

jenkins本身提供了很多Action接口,例如:BuildBadgeAction(可以在build history中添加文字或者图片标签),RootAction(入口为jenkins的根目录)等,可以根据自己的需要实现对应的接口。

Action与build相关联一般有两种方式:
首先需要在action中的构造函数中添加Run/AbstractBuild/WorkflowRun作为传入参数,然后使用下列方法使二者关联。
第一种:addAction()

示例1:@Overridepublic boolean prebuild(AbstractBuild<?,?> build, BuildListener listener) {build.addAction(new MyBuildAction(build));return true;}

第二种:ActionFactory类
在MyAction类中添加内部类MyActionFactory

示例2:@Extensionpublic static class MyActionFactory extends TransientActionFactory<WorkflowRun> {//本次需求中是要兼容pipeline类型,使用了WorkflowRun@Overridepublic Class<WorkflowRun> type() {return WorkflowRun.class;}@Overridepublic Collection<? extends Action> createFor(WorkflowRun target) {MyJobProperty prop = target.getParent().getProperty(MyJobProperty.class);if (prop == null || target.getResult() != Result.SUCCESS) {return Collections.emptySet();} else {return Collections.singleton(new MyAction(prop, target));}}}示例1和示例2不是同一个例子,本次项目使用的是示例2中方式,项目中用到了类似MyJobProperty 中的方法和参数,所以将MyJobProperty 作为了传入参数,具体需要根据需求定义参数。

具体界面还是使用jelly文件去实现,这里需要注意的是:
如果Action中有按钮点击事件,该如何实现?

jelly代码://action中的值需要和java代码一一对应,action="submit"则java中为doSubmit方法<f:form action="submit" method="POST"><f:bottomButtonBar><f:submit value="click"/></f:bottomButtonBar></f:form>java代码部分:
@RequirePOST
public void doSubmit(StaplerRequest req, StaplerResponse rsp) throws Exception {JSONObject form = req.getSubmittedForm();name = Util.fixEmpty(form.getString("name")); // 取feild中的值
}

如果要在编译历史中加入标记,该如何处理?

自定义Action类实现BuildBadgeAction,在对应的resource目录下新增badge.jelly文件MyAction.java code:
public class MyAction implements BuildBadgeAction {****
}badge.jelly code:
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<j:if test="${it.isclick}">       <--! it.xxx 表示MyAction类中的getXxx()或者isXxx()方法的返回值 --><a href="www.baidu.com">Baidu</a>
</j:if>
</j:jelly>

至此,界面的效果差不多是这样:
pipeline job在configure/General选择MyJobProperty,填好相关参数后保存退出,在build history中选择某次编译成功的条目,进入后可以看到侧边栏图标,点击侧边栏图标可以显示Action主界面,点击自定义按钮后执行业务逻辑,同时该build history中该次条目上添加标记。

6、其他注意点
1)点击按钮后刷新页面

     run.replaceAction(this);rsp.sendRedirect("");

2)字符串如果有跨行,如何在jenkins主界面能跨行显示
在jelly文件中如果使用 <h1 />或者 <p />等标签,在jenkins上不能正常显示跨行,需要使用<pre />标签

    <pre >'''nihaohello'''</pre >

3)Action显示系统侧边栏

     MyAction.java code:public Run getOwner() {return run;}index.jelly code:<st:include page="sidepanel.jelly" it="${it.owner}"/>

4)configure/General中参数选中后不能保存,退出再进去后需要重新填写
原因:jelly文件中的feild名称和java文件中不匹配导致

5)侧边栏图标没有点击效果
原因:getUrlName的返回值不能有空格

6)pom.xml文件如何添加需要依赖项?
如果需要依赖A,并且有A的源码,可以先查看A的pom.xml文件,依次找到groupId,artifactId,version,然后在自己的pom.xml文件的dependencies标签中添加。

<dependencies> <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.5</version></dependency>
</dependencies>

7)如何下载已有插件源码?
Jenkins-插件管理-搜索需要的插件-点击插件名-点击github

8)jelly文件中一些关键字的含义

  • app Jekins实例
  • instance 正在被配置的对象
  • descriptor 对应于instance的Descriptor对象
  • h hudson.Functions的实例,一个全局的工具类,提供静态工具方法
  • it 当前UI所属的模型对象

9)Node下workspace 获取,FilePath类型,没有上下文的情况下,即非构建中。

FilePath path = FilePathUtils.find(String nodename, String workspace);

7、Jenkins插件各个类或接口的含义
1)EnvironmentContributor
用来提供环境变量,重写buildEnvironmentFor函数,job可以获取JobProperty
例如:pipeline中echo ${MY_ENV} 会得到"I am local.prop"

@Extension
public class MyEnvVarsContributor extends EnvironmentContributor {@Overridepublic void buildEnvironmentFor(Job j, EnvVars envs, TaskListener listener)throws IOException, InterruptedException {MyJobProperty jb = (MyJobProperty) j.getProperty(MyJobProperty.class);if (jb != null) {envs.put("MY_ENV", "I am local.prop");}super.buildEnvironmentFor(j, envs, listener);}}

2)JobProperty
配置中General部分,也可以用来设置参数
常见获取方式:
MyJobProperty prop = run.getParent().getProperty(MyJobProperty.class);

3)BuildBadgeAction
实现该接口的类配合badge.jelly文件可以在build history中显示标签

4)Descriptor
Descriptor 及其各种延伸的Descriptor ,例如:JobPropertyDescriptor,BuildStepDescriptor等
往往继承该类需要加上@Extension 用来告诉jenkins是JobPropertyDescriptor的扩展,需要创建对应的instance对象。
Descriptor 种类:https://javadoc.jenkins.io/hudson/model/Descriptor.html

5)AbstractStepDescriptorImpl
AbstractStepDescriptorImpl 是pipeline step的扩展,可以定义一个插件的function名称,例如:
继承之后重写以下两个方法:

     @Overridepublic String getFunctionName() {//方法名,可以在pipeline语句中调用,其中的参数是//继承AbstractStepImpl类的构造方法中传入。return "publishHTML";}@Overridepublic String getDisplayName() {return "Publish HTML reports";}

6)Execution
例如:AbstractSynchronousNonBlockingStepExecution。继承后会重写run方法,里面是pipeline 中调用方法的具体内容。继承AbstractStepDescriptorImpl 的类会在其构造函数中调用关联Execution ,并调用run方法。例如:

public DescriptorImpl() {super(PublishHTMLStepExecution.class);
}

7)EnvVars(待补充)
8)ActionFactory(待补充)
9)Context(待补充)

Jenkins 插件开发记录相关推荐

  1. chrome插件开发记录(1)——解决问题“清单文件缺失或不可读”

    chrome插件开发记录(1)--解决问题"清单文件缺失或不可读" 参考文章: (1)chrome插件开发记录(1)--解决问题"清单文件缺失或不可读" (2) ...

  2. Jenkins插件开发(四)-- 插件发布

    上一篇blog介绍了插件开发中要注意的一些问题, 我们再来介绍插件开发完成后,如何上传到jenkins的插件中心(这里假设你的代码是放在github上的,使用svn或其他版本管理工具的请参考其他文章) ...

  3. jenkins 安装记录

    jenkins 安装记录 jenkins的安装有很多种方式,这里采用tomcat的war包形式.在基础centos 7.9下进行安装. 1.操作系统 首先,查看centos系统版本: [root@iZ ...

  4. CI持续集成系统环境---部署Jenkins完整记录

    最近在看CI/CD集成的相关部分,发现几篇好文,转载分享一波. 来源网络:[原创]CI持续集成系统环境---部署Jenkins完整记录 - 散尽浮华 - 博客园 Jenkins通过脚本任务触发,实现代 ...

  5. jenkins配置记录(2)--代码发布流程

    在我们的日常运维工作中,使用jenkins来完成业务代码发版上线是至关重要的一环. 前面已经提到在jenkins上添加用户权限的操作,今天重点说下如何在jenkins下构建项目工程进行代码发布? 在此 ...

  6. jenkins配置记录(1)--添加用户权限

    前一阵子在线上部署了一套jenkins环境,作为线上代码发布平台使用. 部署记录:http://www.cnblogs.com/kevingrace/p/5651427.html 下面重点记录下jen ...

  7. jenkins插件开发

    Tomcat服务器下Jenkins插件开发过程 一.环境准备 首先需要安装的几个应用:jdk,maven,tomcat,git(配好环境变量). 然后下载一个Jenkins.war文件,把这个文件放到 ...

  8. Xposed插件开发---记录文件操作

    0x00 前言 因为工作上的原因需要分析某个软件将网络下载的文件解压到那个路径,通过比对文件夹大小很难定位到具体位置,所以考虑使用xposed插件来做,因为没有现成的,所以只能自己动手来做一个了 需要 ...

  9. jenkins搭建记录

    jenkins简介 jenkins是一个可持续集成的开发工具,在自动化构建过程中可以给我们省下非常多的时间.所以,目前在我们的项目中需先对android项目和ios项目构建自动打包,后续可能服务端也会 ...

最新文章

  1. 图片优化_Web 性能优化: 图片优化让网站大小减少 62%
  2. 计算机网络 --- 数据链路层aloha协议
  3. 虚拟跳线软件干什么用的_跳线的作用
  4. 1725.可以形成最大正方形的矩阵数目
  5. mysql拆分盘数据库_数据库拆分
  6. 没有servlet接口_Java——Servlet
  7. HTML1.0 - html 环境搭建 开发工具
  8. 硬件笔记1:80508550三极管对管驱动电机电路(已经实测可用)
  9. Linux系统手机投屏实现电脑控制手机(Windows)
  10. OpenGL学习书籍推荐
  11. 如何用PS把照片变成红/白/蓝底
  12. Python 3,4行代码实现去除图片背景色,从此告别PS!!
  13. vmvare打开虚拟机时报错:vmx文件已损坏
  14. 游戏爱好者如何选购计算机,通俗易懂,游戏本该怎么挑
  15. Consistent 与 Mirrored 视角
  16. 关于XUL上的textbox中的persist属性使用
  17. 数据库中索引的填充因子
  18. 思考-ML如何产生效益,前景问题
  19. Stand-Alone Self-Attention in Vision Models阅读笔记
  20. 我失业了?| ChatGPT生信分析初体验

热门文章

  1. 线程同步,为什么要引入线程同步?
  2. latex积分号、求和、极限符号大小,上下标位置控制,行内公式显示行间公式效果
  3. transition、trasform和translate
  4. java连不上sqlserver_java和SQL连接不上——解决步骤
  5. 授权(authorization)的设计思路
  6. 命名实体识别(二)——基于条件随机场的命名实体识别
  7. Hive面试题精选-2021
  8. 路由器web向导页面
  9. 网络设计与网络设备配置,网络设计需要哪些设备
  10. 使用python进行相关性分析并绘制散点图