jenkins插件开发

https://jenkins.io/doc/developer/

1. 向导

  jenkins是一个强大的插件系统,开发者使用插件,几乎可以影响到所有的jenkins操作。这个章节演示了简单的插件功能。

1.1 准备插件的开发环境

  安装JDK环境,安装maven,保证mvn路径被添加到path变量。

1.2 创建插件

  打开命令行,进入我们希望的目录中,然后执行

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

  运行结果

…
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:hello-world-plugin (Skeleton of a Jenkins plugin with a POM and an example build step.)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): : 3 
Choose io.jenkins.archetypes:hello-world-plugin version:
1: 1.1
2: 1.2
3: 1.3
Choose a number: 3: 3 
[INFO] Using property: groupId = unused
Define value for property artifactId: demo 
Define value for property version 1.0-SNAPSHOT: : 
[INFO] Using property: package = io.jenkins.plugins.sample
Confirm properties configuration:
groupId: unused
artifactId: demo
version: 1.0-SNAPSHOT
package: io.jenkins.plugins.sample
 Y: : y 

  以上标出了关键的地方:

  1. 选择hello-word-plugin作为我们的插件结构
  2. 选择1.3最新版本
  3. artifactid是强制要求的,而且在jenkins中运行时要求唯一,我们设置为demo。
  4. 默认是 1.0-SNAPSHOT作为开发的版本号。(maven中的版本号区别可以查看: 这里
  5. 最后最列举出来的信息进行确认Y

  以上会创建一个目录,名字与artifactid的值一致(这里的值是demo),而且里面有一些基本的可运行的插件结构。执行以下指令来校验这个插件源码是否可以运行:

$ mv demo demo-plugin
$ cd demo-plugin
$ mvn verify

  这里第一步就是重命名这个文件夹,接着verify会下载一系列依赖,然后进入生命周期,包括FindBugs静态分析和测试,直到显示如下信息:

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 06:11 min
[INFO] Finished at: 2017-03-02T14:14:34+01:00
[INFO] Final Memory: 73M/872M
[INFO] ------------------------------------------------------------------------

1.3 构建和运行插件

  maven的HPI插件用来构建和打包jenkins插件,这个插件提供了一个简单的方式来运行插件:

mvn hpi:run

  以上指令会运行一个jenkins实例(这个jenkins实例的数据保存在插件目录的work目录下),在 http://localhost:8080/jenkins/,然后自动打开一个控制台(这个控制台对应jenkins实例),控制台显示

INFO: Jenkins is fully up and running

  接着我们打开一个浏览器访问http://localhost:8080/jenkins/,在jenkins中创建一个自由风格的项目,在构建设置中,启用我们的插件“Say Hello Word”,在出现的选项中随便输入一个问候语“Hello Jenkins!”,然后保存,进行项目构建,打开这次构建的控制台,可以看到我们之前输入的值,被输出到控制台上了:

Started by user anonymous
Building in workspace /Users/mrjenkins/demo/work/workspace/testjob
Hello, Jenkins! 
Finished: SUCCESS

1.4 扩展插件

  这次通过以下特征来扩展插件:

  1. 用合适的数据结构来保存我们的问候语,而不是仅仅在构建控制台中输出
  2. 添加一个新的页面来显示我们用过的问候语

 1.4.1 记录问候语

  首先,在HelloWorldBuilder所在的包中创建一个类HelloWorldAction:

package io.jenkins.plugins.sample;
import hudson.model.Action;
public class HelloWorldAction implements Action {
    @Override
    public String getIconFileName() {
        return null;
    }
    @Override
    public String getDisplayName() {
        return null;
    }
    @Override
    public String getUrlName() {
        return null;
    }
}

  Action都是jenkins的基础构建扩展单位,这些单位可以访问并且保存许多对象,而且还可以把这些对象显示到界面上。

  我们往这个Action类中添加我们希望保存的数据(私有字段和对应的geter、setter):

(...)
public class HelloWorldAction implements Action {
    private String name;
    public HelloWorldAction(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    (...)

  现在,需要我们在构建的时候,生成这个类的实例,在HelloWorldBuilder类的perform方法中,添加如下一行标注的代码:

(...)
    @Override
    public void perform(Run<?, ?> run, FilePath workspace, Launcher launcher, TaskListener listener) throws InterruptedException, IOException {
        run.addAction(new HelloWorldAction(name)); 
        if (useFrench) {
            listener.getLogger().println("Bonjour, " + name + "!");
        } else {
            listener.getLogger().println("Hello, " + name + "!");
        }
    }
(...)

  保存后,mvn hpi:run来运行插件。之后每次进行构建,上面的Action都会被应用。可以通过查看build.xml来确认,这个文件在这里work/jobs/JOBNAME/builds/BUILDNUMBER/。文件大致如下:

<build>
  <actions>
    <hudson.model.CauseAction> 
      <causes>
        <hudson.model.Cause_-UserIdCause/>
      </causes>
    </hudson.model.CauseAction>
    <io.jenkins.plugins.sample.HelloWorldAction plugin="demo@1.0-SNAPSHOT"> 
      <name>Jenkins</name> 
    </io.jenkins.plugins.sample.HelloWorldAction>
  </actions>
  (...)
</build>

  对于以上三个标注的地方:

  1. 代表了构建的原因(如果触发这次构建)也被作为action来保存了,这里指出了是匿名用户触发的构建
  2. 这是我们新建的Action
  3. 这个name值就是我们在构建配置中设置的值

1.4.2 添加个页面来显示数据

  首先,回到HelloWorldAction中修改如下函数的返回值:

    @Override
    public String getIconFileName() {
        return "document.png"; 
    }

    @Override
    public String getDisplayName() {
        return "Greeting"; 
    }

    @Override
    public String getUrlName() {
        return "greeting"; 
    }

  分别代表了多出的侧边栏的图标、标题,以及地址(http://JENKINS/job/JOBNAME/BUILDNUMBER/greeting/)。

  接着,以上地址的页面需要被配置。在jenkins中创建视图,通过Jelly来实现。

  在src/main/resources/io/jenkins/plugins/sample/中创建一个目录,名为HelloWorldAction。这个目录对应我们的HelloWorldAction类,代表这个目录中的资源给对应的类来使用。目录中有如下资源:

  1. config.jelly:代表构建配置中的表单界面
  2. config*.properties:contain the localizations for the build step configuration
  3. help*.html:provide the localized inline help for the configuration

  在以上目录(src/main/resources/io/jenkins/plugins/sample/HelloWorldAction/)中创建一个 index.jelly,这个界面会显示在http://JENKINS/job/JOBNAME/BUILDNUMBER/greeting/中。index.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:main-panel> 
            <h1> 
                Name: ${it.name} 
            </h1>
        </l:main-panel>
    </l:layout>
</j:jelly>

  对于以上四个标注的地方:

  1. layout标签是jenkins提供的一个基础界面容器,包含了header、footer、主内容区域,侧边栏等
  2. main-panel标签中的内容代表了容器中的主内容
  3. jelly中可以使用任意html标签
  4. 这是一个JEXL表达式,it代表了这个视图所属的Java对象(类似于this),在这个例子中就是指向了HelloWorldAction实例,it.name等价于调用了这个属性的getter,也就是调用了getName方法

  做好以上配置后,当我们访问http://JENKINS/job/JOBNAME/BUILDNUMBER/greeting/时,jelly以及里面的name数据就显示出来了

 1.4.3 为页面添加侧边栏

  以上的显示的界面中没有侧边工具栏,这里我们要做的就是把侧边工具栏显示出来。要实现这个效果,

  1. 在Action中获取到这次构建的引用
  2. 从这个引用中获取到工具栏fragment
  3. 将这个fragment引用到我们的界面中

  实现第一步,让HelloWorldAction来实现RunAction2这个接口,里面有两个方法:

  • onAttached(Run):called when the run is first attached to a build
  • onLoad(Run):called when the action and run are loaded from disk
(...)
import hudson.model.Run;
import jenkins.model.RunAction2;
public class HelloWorldAction implements RunAction2 { 
    private transient Run run; 
    @Override
    public void onAttached(Run<?, ?> run) {
        this.run = run; 
    }
    @Override
    public void onLoad(Run<?, ?> run) {
        this.run = run; 
    }
    public Run getRun() { 
        return run;
    }
(...)

  对于以上标注的两个个地方:

  1. 被这个关键字修饰的run,不会随着这个action序列化到硬盘上
  2. 使我们获取到的run,可以用在jelly视图中

   然后在jelly中引入run提供的侧边工具栏:

(...)
    <l:layout title="Greeting">
        <l:side-panel> 
            <st:include page="sidepanel.jelly" it="${it.run}" optional="true" /> 
        </l:side-panel>
        <l:main-panel>
          (...)
        </l:main-panel>
    </l:layout>
(...)

  类似于main-panel,side-panel代表了侧标栏。接着include标签,可以从这个标签的it属性所指向的对象中,引入page所指向的视图,效果就是从run中引入了sidepanel.jelly视图。然后将这个标签设置为可选的,这样一来,当sidepanel.jelly不存在时也不会报错了

  以上配置后,http://JENKINS/job/JOBNAME/BUILDNUMBER/greeting/就有侧边栏了。

 

posted @ 2018-04-06 10:40  HelloHello233  阅读(3314)  评论(1编辑  收藏  举报