Jenkins插件开发


一、环境依赖

JDK版本要求在1.6以上,Maven官方要求版本在3以上,此处本人使用的是JDK1.8 maven3.5.2

 然后呢就是你maven的 setting.xml(此setting文件直接放在了C:\Users\xie_7\.m2下)文件要变成这样:

<?xml version="1.0" encoding="UTF-8"?>
 
<settings>
<!-- 指定本地仓库的存放地址,可选 -->
<localRepository>E:\Jenkins\jar</localRepository>
 <!-- 下面的东西都不用管知道不,只需要copy就ok -->
  <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>http://repo.jenkins-ci.org/public/</url>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>repo.jenkins-ci.org</id>
          <url>http://repo.jenkins-ci.org/public/</url>
        </pluginRepository>
      </pluginRepositories>
    </profile>
  </profiles>
  <mirrors>
    <mirror>
      <id>repo.jenkins-ci.org</id>
      <url>http://repo.jenkins-ci.org/public/</url>
      <mirrorOf>m.g.o-public</mirrorOf>
    </mirror>
  </mirrors>
</settings>

二、插件开发

1.创建 插件程序

    好了,关于Jenkins的使用怎么就不去做过多解释了,网上多得是,此处阅读推荐:

    https://blog.csdn.net/shuizhihun07/article/details/80168076

    执行如下命令:

mvn -s E:\apache-maven-3.5.3\setting.xml -Uorg.jenkins-ci.tools:maven-hpi-plugin:create

然后会根据上文指定的setting.xml文件,下载到本地仓库中,下载完成后会提示如下信息

 

 

 然后cd到指定的文件夹下,执行如下命令:

mvn -s E:\apache-maven-3.5.3\settings-jenkins.xml archetype:generate -DgroupId=com.ydzbinfo -DartifactId=sendActiveMessage -DarchetypeArtifactId=maven-archetype-webapp -DarchetypeCatalog=internal

就会在相应文件夹下面创建项目

但是没有模板,只是一个空项目

但是如果不写-DarchetypeCatalog=internal参数,那么就会卡住,如下:

 

 

 下载archetype-catalog.xml文件,根据以下说明,

 

archetypeCatalog用来指定maven-archetype-plugin读取archetype-catalog.xml文件的位置:
 
internal——maven-archetype-plugin内置的

local——本地的,位置为~/.m2/archetype-catalog.xml

remote——指向Maven中央仓库的Catalog

 

将该文件copy到本地仓库的org\apache\maven\archetype\archetype-catalog\3.2.0文件下,

然后配置-DarchetypeCatalog=internal,但是依然无效,还是报如下信息:

 

 

 不知道哪里有问题,最后将archetype-catalog.xml文件copy到本地仓库的根文件夹下,然后设置参数-DarchetypeCatalog=local,一个带有模板的项目终于创建好了

 

 

 完整命令如下:

mvn -s E:\apache-maven-3.5.3\settings-jenkins.xml archetype:generate -Dfilter=io.jenkins.archetypes: -DarchetypeCatalog=local

执行结果如下:

 

 选择第2个hello-world-plugin模板,然后maven自动创建项目,整个项目的结构大致如下:

 

 注意HelloWorldBuilder.java类,就要对应一个resource中的HelloWorldBuilder文件夹

 

 

 

 

2.开发 插件程序

插件的钩子应该是可以根据继承的抽象类(抽象类继承的接口)的不同,确定插件运行的不同步骤

这里按照教程,在build阶段发送一个构建项目是否成功的通知,具体代码如下:

import cn.hutool.http.HttpUtil;
import hudson.Launcher;
import hudson.Extension;
import hudson.FilePath;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Notifier;
import hudson.util.FormValidation;
import hudson.model.AbstractProject;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.tasks.Builder;
import hudson.tasks.BuildStepDescriptor;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;

import javax.servlet.ServletException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import jenkins.tasks.SimpleBuildStep;
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundSetter;


public class HelloWorldBuilder extends Builder implements SimpleBuildStep {


    private String receivers="";
    private String amServiceUrl="";
    private String projectName = "";
    private Boolean noPojectNotify=false;//没有构建结果
    private Boolean successNotify=false; //成功
    private Boolean failureNotify=false; //失败
    private Boolean abortedNotify=false;//中断
    private Boolean unstableNotify=false;//不稳定

    public String getProjectName() {
        return projectName;
    }
    @DataBoundSetter
    public void setProjectName(String projectName) {
        this.projectName = projectName;
    }

    public String getAmServiceUrl() {
        return amServiceUrl;
    }
    @DataBoundSetter
    public void setAmServiceUrl(String amServiceUrl) {
        this.amServiceUrl = amServiceUrl;
    }

    public String getReceivers() {
        return receivers;
    }
    @DataBoundSetter
    public void setReceivers(String receivers) {
        this.receivers = receivers;
    }

    public Boolean getNoPojectNotify() {
        return noPojectNotify;
    }
    @DataBoundSetter
    public void setNoPojectNotify(Boolean noPojectNotify) {
        this.noPojectNotify = noPojectNotify;
    }

    public Boolean getSuccessNotify() {
        return successNotify;
    }
    @DataBoundSetter
    public void setSuccessNotify(Boolean successNotify) {
        this.successNotify = successNotify;
    }

    public Boolean getFailureNotify() {
        return failureNotify;
    }
    @DataBoundSetter
    public void setFailureNotify(Boolean failureNotify) {
        this.failureNotify = failureNotify;
    }

    public Boolean getAbortedNotify() {
        return abortedNotify;
    }
    @DataBoundSetter
    public void setAbortedNotify(Boolean abortedNotify) {
        this.abortedNotify = abortedNotify;
    }

    public Boolean getUnstableNotify() {
        return unstableNotify;
    }
    @DataBoundSetter
    public void setUnstableNotify(Boolean unstableNotify) {
        this.unstableNotify = unstableNotify;
    }
    @DataBoundConstructor
    public HelloWorldBuilder(String projectName,String receivers,String amServiceUrl) {
        this.projectName=projectName;
        this.amServiceUrl=amServiceUrl;
        this.receivers=receivers;
    }





    /*perform 真正开始执行的地方 你所有构建时的任务都将在此内完成
     * 在此之内你可以执行 任意想执行的业务操作,Web Service等
     */
    @Override
    public void perform(Run<?, ?> build, FilePath workspace, Launcher launcher, TaskListener listener) throws InterruptedException, IOException {
        String string ="";
        String displayName = build.getDisplayName();
        Boolean isNotify=false;

        //获取构建结果
        if(build.getResult() == null){
            string="no project";
        }
        else{
            string= build.getResult().toString();
        }

        int number = build.getNumber();
        String resuit = null;
        if(string.equals("no project")){
            resuit="无构建结果";
            isNotify = this.noPojectNotify;
        }
        if(string.equals("SUCCESS")){
            resuit="构建结果:成功";
            isNotify = this.successNotify;
        }else if(string.equals("FAILURE")){
            resuit="构建结果:失败";
            isNotify = this.failureNotify;
        }else if(string.equals("UNSTABLE")){
            resuit="构建结果:不稳定";
            isNotify = this.unstableNotify;
        }else if(string.equals("ABORTED")){
            resuit="构建结果:中断构建";
            isNotify = this.abortedNotify;
        }

        String url = build.getUrl();
        String content = displayName + projectName+"任务"+resuit;
        Map map = new HashMap();
        map.put("subject","集成编译平台编译通知");
        map.put("messageBody",content);
        map.put("recivers",receivers);
        if(isNotify) {
            String post = HttpUtil.post(amServiceUrl, map);
            listener.getLogger().println("result, " + post + "!");
        }
        else
        {
            listener.getLogger().println(isNotify);
        }

    }

    @Override
    public BuildStepMonitor getRequiredMonitorService() {
        return BuildStepMonitor.NONE;
    }

    @Symbol("greet")
    @Extension //通过此注解 告诉系统该内部类是作为BuildStepDescriptor的扩展出现
    public static final class DescriptorImpl extends BuildStepDescriptor<Builder> {

        /**
         * 表示对字段"name"做检查,"name"被填写时将会被调用,它的内部通过抽象父类Descriptor执行方法getCheckMethod(String fieldName) ,内部通过反射找到参数名称对应方法。
         * @param value 传入参数"value"表示字段"name"传入的值
         * @param useFrench 而后的参数useFrench是传入的同名字段的值
         * @throws IOException
         * @throws ServletException
         */
        public FormValidation doCheckName(@QueryParameter String value, @QueryParameter boolean useFrench)
                throws IOException, ServletException {
            if (value.length() == 0) {
                return FormValidation.error("value.length() == 0");
            }
            if (value.length() < 4) {
                return FormValidation.warning("value.length() < 4");
            }
            if (!useFrench && value.matches(".*[éáàç].*")) {
                return FormValidation.warning("else");
            }
            return FormValidation.ok();
        }

        @Override
        public boolean isApplicable(Class<? extends AbstractProject> aClass) {
            return true;
        }

        //这个步骤的名称
        @Override
        public String getDisplayName() {
            return "SendActiveMessage";
        }

    }

}
View Code

 

config.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:entry title="任务名称" field="projectName">
        <f:textbox />
    </f:entry>
    <f:entry title="接收人(多个接收人用分号隔开)" field="receivers">
         <f:textbox />
     </f:entry>
     <f:entry title="am服务地址" field="amServiceUrl">
         <f:textbox default="http://172.20.104.227/sendAmMessage/CICDSendActiveMessage.ashx"/>
      </f:entry>
    <f:advanced>
    <f:entry title="无构建结果通知" field="noPojectNotify">
                  <f:checkbox checked="true"/>
             </f:entry>
       <f:entry title="失败通知" field="failureNotify">
                     <f:checkbox checked="true"/>
                </f:entry>

              <f:entry title="中断通知" field="abortedNotify">
                    <f:checkbox checked="true"/>
               </f:entry>

              <f:entry title="不稳定通知" field="unstableNotify">
                    <f:checkbox checked="true"/>
               </f:entry>

              <f:entry title="成功通知" field="successNotify">
                    <f:checkbox />
               </f:entry>


    </f:advanced>
</j:jelly>

 

然后maven clean package 打包,会在target文件夹下生成一个后缀为.hpi的文件,然后在jenkins的插件管理,采用离线上传的方式

 

 

 

 最后,在需要配置的项目中选择该插件:

 

 

 

参考文章:

Maven创建项目时出现Generating project in Interactive mode就一直卡住的解决方案

最最最全的Jenkins插件开发教程

【Jenkins】Jenkins插件开发

免费的maven的archetype-catalog.xml文件下载

archetypeCatalog参数的配置

Jenkins使用教程

 Jenkins企业微信通知开发

jenkins参数化构建过程(添加多选框)

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM