持续集成 Hello,Jenkins Plugin

myersguo · 2017年02月21日 · 最后由 高浩 回复于 2017年04月18日 · 3180 次阅读
本帖已被设为精华帖!

一般公司内部的发布系统和 jenkins 的持续集成结合时,往往官方的插件不足以满足我们的需求。因此我们需要自己动手,写一个定制化的 jenkins 插件。

Hello,Jenkins plugin

在动手之前,一定要先走以下几步:

当你发现所有人的需求都和你不同时,你就可以开始动手 (copy and write) 了。

Let's Go

(前提是准备好 eclipse,mvn)

添加 jenkins 的 mvn 仓库

mvn 的安装目录下的 conf/settings.xml 添加如下配置

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">

 <!--<settings> -->
  <pluginGroups>
    <pluginGroup>org.jenkins-ci.tools</pluginGroup>
  </pluginGroups>

  <profiles>
    <!-- Give access to Jenkins plugins -->
    <profile>
      <id>jenkins</id>
      <activation>
        <activeByDefault>true</activeByDefault> <!-- change this to false, if you don't like to have it on per default -->
      </activation>
      <repositories>
        <repository>
          <id>repo.jenkins-ci.org</id>
          <url>https://repo.jenkins-ci.org/public/</url>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>repo.jenkins-ci.org</id>
          <url>https://repo.jenkins-ci.org/public/</url>
        </pluginRepository>
      </pluginRepositories>
    </profile>
  </profiles>
  <mirrors>
    <mirror>
      <id>repo.jenkins-ci.org</id>
      <url>https://repo.jenkins-ci.org/public/</url>
      <mirrorOf>m.g.o-public</mirrorOf>
    </mirror>
  </mirrors>
</settings>
mvn -U org.jenkins-ci.tools:maven-hpi-plugin:create   

jenkins

然后,你就看到 jenkins 的插件 Downloading....then 一步一步的填写相关配置,你已经创建好了 jenkins 插件的 helloworld 工程。

└─hello
    └─src
        └─main
            ├─java
            │  └─io
            │      └─github
            │          └─myersguo
            │              └─jenkins
            │                  └─hello
            └─resources
                └─io
                    └─github
                        └─myersguo
                            └─jenkins
                                └─hello
                                    └─HelloWorldBuilder

编译打包:mvn install

将在 target 目录下生成 hello.hpi(jenkins 插件,hello.jar 的封装包)

打开 jenkins 进行安装,然后建一个 job,执行以下就能看到熟悉的 hello,world 了。

jenkins plugin

jenkins plugin

定制你的插件

上面利用maven-hpi-plugin自动创建了一个 jenkins 插件工程。我们写自己的插件就从上面的工程按照约定编写相应的工程即可。约定是什么呢?

  • resources: jelly/groovy 视图
  • main: 插件源码逻辑

插件视图设置

config.jelly配置插件的变量参数;

global.jelly配置插件的全局参数(系统设置参数);

插件代码逻辑

详情了解 jenkins 的架构可以阅读官方文档:jenkins 基于 stapler 构建了基于 url 的 MVC 框架。我们只需要按照 jenkins 插件规范来写插件即可,这里修改默认生成的构建类,进行设置:

构建的插件都要继承自Builder类,我们以创建文件为例写一个插件:

通过注解 DataBoundConstructor 和DataBoundSetter将 config.jelly 的配置传递到插件对象中。

代码示例

public class ConfigUpdate extends Builder {

    public String filePath = "";
    public String fileContent = "";
    public String fileOption = "overWrite";
    //config.jelly中的配置是数据来源
    @DataBoundConstructor
    public  ConfigUpdate(String filePath, String fileContent, String fileOption) {
        this.filePath = filePath;
        this.fileContent = fileContent;
        this.fileOption = fileOption;
    }
    //settter & getter
    @DataBoundSetter
    public void setFilePath(String outputFile) {
        this.filePath = outputFile;
    }
    @DataBoundSetter
    public void setFileContent(String fileContent){this.fileContent = fileContent;}

    @Override
    public boolean perform(AbstractBuild<?,?> build, Launcher launcher, BuildListener listener)
            throws InterruptedException,IOException {
        //插件业务逻辑,这里省略
        return true;
    }


    @Extension
    public static final class DescriptorImpl extends BuildStepDescriptor<Builder> {

        public DescriptorImpl() {
            load();
        }

        //构建检查
        public FormValidation doCheckFilePath(@QueryParameter String value)
                throws IOException, ServletException {
            if (value.length() == 0)
                return FormValidation.error("请设置文件路径");

            return FormValidation.ok();
        }

        public FormValidation doCheckFileContent(@QueryParameter String value)
                throws IOException, ServletException {
            if (value.length() == 0)
                return FormValidation.error("请输入文件内容");

            return FormValidation.ok();
        }

    }
}


这样,我们copy and write,jenkins 的 mvn 插件给我把代码脚手架安装好。我们就按照步骤更改,就能写出定制化的插件了。

(完)

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 15 条回复 时间 点赞
思寒_seveniruby 将本帖设为了精华贴 02月22日 01:28

加精理由: 弥补了 jenkins 插件开发知识

3楼 已删除

有个问题,filePath 变量,如何接收 jenkins 的全局变量,是有什么特别设置吗?

高浩 回复

jenkins 的变量接收。我用到的有两种。

  1. job 的变量参数。即每个任务的输入参数。
  2. 插件的参数配置。即 jenkins 全局设置中的插件配置中设置所有的任务都需要的变量输入。这个在插件描述设置中进行设置。
//插件描述配置
    @Extension
    public static final class DescriptorImpl extends BuildStepDescriptor<Builder> {
       private String globalConfig;//全局参数
       @Override
        public boolean configure(StaplerRequest req, net.sf.json.JSONObject formData) throws FormException {
            globalConfig= formData.getString("globalConfig");
            save();
            return super.configure(req, formData);
        }

        public String getGlobalConfig() {
            return globalConfig;
        }
    }
myersguo 回复

1、job 的变量参数。即每个任务的输入参数。
上面这句入参,也是用回复中的代码吗?🌴

高浩 回复

上面的代码是全局的 globalconfig 的配置,不是每个 job 的配置。每个 job 的配置就是帖子里面的 builder 的配置:

public String fileContent = "";
    public String fileOption = "overWrite";
    //config.jelly中的配置是数据来源
    @DataBoundConstructor
    public  ConfigUpdate(String filePath, String fileContent, String fileOption) {
        this.filePath = filePath;
        this.fileContent = fileContent;
        this.fileOption = fileOption;
    }
    //settter & getter
    @DataBoundSetter
    public void setFilePath(String outputFile) {
        this.filePath = outputFile;
    }
    @DataBoundSetter
    public void setFileContent(String fileContent){this.fileContent = fileContent;}

感谢。估计是,jenkins 自动下载的 demo,它的 name 字段是 final,导致无法传变量。。我再看看,貌似看错了……

myersguo 回复


还是 ${abc}。我继续看看是哪里的问题

高浩 回复

如果方便,你可以贴出部分代码看看。

private String name;

// Fields in config.jelly must match the parameter names in the "DataBoundConstructor"
@DataBoundConstructor
public HelloWorldBuilder(String name) {
    this.name = name;
}

/**
 * We'll use this from the {@code config.jelly}.
 */
@DataBoundSetter
public void setName(String name) {
    this.name = name;
}

默认的工程,只改了这个地方·· ····🌽 。其他什么也没做。······

高浩 回复

如果只是改了这个地方就不会出现问题,你输出的 ${abc} 难道是你的输入?

myersguo 回复

配置 job 的时候,我填的这个变量。执行 job 的时候,给这个变量赋值。abc 是命名的变量。

先用了一个比较笨的临时解决办法:正则匹配,出现 ${}或者 ##,便去变量中找到对应的值;否则,按照常量处理。

用 hudson.EnvVars 的 expand(String s) 方法,解决问题。
Expands the variables in the given string by using environment variables represented in 'this'.

高浩 回复

这个问题怎么解决的?可以详细说一下吗

高浩 Jenkins Plugin 获取变量的问题。 中提及了此贴 04月18日 09:09
鲨鱼辣椒 回复

https://testerhome.com/topics/8311
刚才赶紧补了一下原委。你看是否清楚···

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册