实战Jenkins插件开发 - Telegram通知插件

2019-08-05  本文已影响0人  zwffff

介绍

Jenkins的很多功能都是借助它的插件机制来实现的,它本身提供的功能是很少的。开发Jenkins插件是基于扩展点(ExtensionPoint)来完成的,它是Jenkins系统的某个方面的接口或抽象类,这些接口定义了需要实现的方法,而Jenkins插件需要实现这些方法。更多扩展点的详细信息,可以参考官方ExtensionPoint文档,通过这些扩展点我们可以写插件来实现自己的需求。
下面是一些常用的扩展点:

环境搭建

Jenkins是基于Java语言开发的,因此它的插件也应该基于Java来进行开发。它需要安装Java开发环境和Maven,至于如何搭建Java和Maven开发环境,网上有很多教程,这里不做介绍。

安装完成后,修改maven用户目录下的settings.xml文件(如果用户目录没有settings.xml文件,则从maven安装目录下的conf目录复制到用户目录,maven安装目录下的settings.xml是全局配置,针对所有用户,不建议更改

用户目录下settings.xml文件位置:

修改为以下内容:

<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>

创建插件

  1. 在需要创建插件的目录打开cmd窗口,运行一下命令
mvn -U archetype:generate -Dfilter="io.jenkins.archetypes:"

这个命令将允许你生成与Jenkins相关的多个项目原型之一,这里我们使用empty原型1.5版,因此选择如下:

$ mvn -U archetype:generate -Dfilter="io.jenkins.archetypes:"
…
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): : 1 
Choose io.jenkins.archetypes:hello-world-plugin version:
1: 1.0
2: 1.1
3: 1.2
4: 1.3
5: 1.4
6: 1.5
Choose a number: 6: 6 
…
[INFO] Using property: groupId = unused 
Define value for property 'artifactId': TelegramNotification
Define value for property 'version' 1.0-SNAPSHOT: : 1.0
[INFO] Using property: package = io.jenkins.plugins.sample
Confirm properties configuration:
groupId: unused
artifactId: TelegramNotification
version: 1.0
package: io.jenkins.plugins.sample
 Y: : y 
  1. 让我们确保可以构建插件,执行以下命令进行验证
    mvn verify
    验证结果如下,则说明验证通过。
    验证通过

如果使用的是其他原型的话,在测试用例这一步可能会失败,则可以考虑在pom.xml中增加以下配置忽略测试用例

<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <testFailureIgnore>true</testFailureIgnore>
                </configuration>
            </plugin>

编写插件

  1. 创建一个TelegramPublisher实现Notifier类
public class TelegramPublisher extends Notifier {
}

在Jenkins的插件中,每一个插件类中都必须要有一个Descriptor内部静态类,它代表一个类的描述者,用于指明这个一个扩展点的实现,Jenkins是通过这个描述者才能知道我们自己写的插件。这个静态类需要被@Extension注解,Jenkins内部会扫描@Extension注解来知道注册了哪些插件。

public class TelegramPublisher extends Notifier {

    @Symbol("Telegram")
    @Extension
    public static final class DescriptorImpl extends BuildStepDescriptor<Publisher> {

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

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

在Descriptor类中有两个方法一定需要我们进行重写

  1. 全局配置定义
    插件如果需要在全局配置中进行配置的话,我们需要在Descriptor中定义一个属性。这里我们需要把Telegram Bot Token和Telegram Bot Name保存到全局配置中,则可以在这里进行定义。
//全局配置中,进行Telegram Bot Name设置,必须与global.jelly中的field字段相同
        private String botUserName;
        //全局配置中,进行Telegram Bot Token设置,必须与global.jelly中的field字段相同
        private String botToken;

        public String getBotUserName() {
            return botUserName;
        }

        public String getBotToken() {
            return botToken;
        }
public DescriptorImpl() {
            load();
        }
@Override
        public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
            botUserName = json.getString("botUserName"); //获取Telegram Bot Name配置
            botToken = json.getString("botToken");  //获取Telegram Bot Token配置
            save(); //将全局配置信息持久化到xml中
            return super.configure(req, json);
        }
<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:section title="Darren Telegram Bot">
    <f:entry title="Telegram Bot name" field="botUserName"
      description="Paste your bot name">
      <f:textbox />
    </f:entry>
    <f:entry title="Telegram Bot token" field="botToken"
          description="Paste your bot token">
          <f:textbox />
     </f:entry>
  </f:section>
</j:jelly>

注意:这里的field字段必须与Descriptor里面的属性保持一致,才能绑定上。

使用mvn hpi:run查看运行效果

全局配置

在Manage Jenkins -> Configure System里面,我们已经看到了相关设置了。

  1. 项目配置定义
    项目的相关配置,则是定义在插件类本身中,这里就是我们的TelegramPublisher类,其视图则是定义在config.jelly中,规则和global.jelly一样。
@Override
    public DescriptorImpl getDescriptor() {
        return (DescriptorImpl) super.getDescriptor();
    }
// 项目配置,Telegram消息接收者
    private final String receivers;
    // 项目配置,额外消息
    private final String messageTemplate;
    // 项目配置,消息发送条件,构建成功是否发送消息
    private final Boolean condition;

    @DataBoundConstructor
    public TelegramPublisher(String receivers, String messageTemplate, Boolean condition) {
        this.receivers = receivers;
        this.messageTemplate = messageTemplate;
        this.condition = condition;
    }

    public String getMessageTemplate() {
        return messageTemplate;
    }

    public String getReceivers() {
        return receivers;
    }

    public Boolean getCondition() {
        return condition;
    }

这三个属性的值是项目配置过程中输入,由Jenkins从Web前端界面传递过来,通过在TelegramPublisher构造函数中进行参数的注入。这个类似于Spring的依赖注入,需要用@DataBoundConstructor注解标注。

<?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="Extra Message" field="messageTemplate" description="The extra message">
            <f:textbox />
        </f:entry>
        <f:entry title="Notification Users" field="receivers" description="The users want to receive message,split by #">
                <f:textbox />
        </f:entry>
        <f:entry title="Send if success?" field="condition" description="Sends the notification if the build succeed">
                <f:checkbox />
        </f:entry>
</j:jelly>

运行效果图如下:


项目配置
@Override
    public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
        listener.getLogger().println("[INFO] test message" + getDescriptor().getBotUserName());
        return true;
    }

触发一次构建输出日志如下:


构建日志

Jenkins视图

Jenkins使用jelly来编写视图,Jelly是一种基于Java技术和XML的脚本编制和处理引擎。在Jenkins中的视图类型有三种

这就是Jenkins中的三种视图,更多关于Jelly的视图控件可以查看Jenkins控件

另外

  1. Jenkins插件管理页面中,关于插件介绍的内容在index.jelly视图中进行更改
  2. 插件名称在pom.xml中更改name元素即可
插件介绍
插件名称

配置文件与多语言国际化

典型的工作流如下:

  1. 确定需要本地化的Messages
  2. 将消息写入Messages.properties文件,即可以为每个package编写一个,也可以整个module或者plugin只用一个
  3. 运行mvn compile生成Messages.java
  4. 更新代码,使用最新生成的消息格式方法读取

代码中则可以通过如下的方式进行引用

@Override
        public String getDisplayName() {
            return Messages.TelegramPublisher_DescriptorImpl_DisplayName();
        }
2.png

国际化更多内容,请查看Jenkins官方文档

参数检查

Jenkins中进行字段检验,是通过创建doCheck字段名称()这样的方法来处理的,value参数,则代表该字段的值。

///校验botUserName参数
        public FormValidation doCheckBotUserName(@QueryParameter String value) {
            if (value.length() == 0)
                return FormValidation.error(Messages.TelegramPublisher_DescriptorImpl_errors_missingBotUserName());

            return FormValidation.ok();
        }

        ///校验botToken参数
        public FormValidation doCheckBotToken(@QueryParameter String value) {
            if (value.length() == 0)
                return FormValidation.error(Messages.TelegramPublisher_DescriptorImpl_errors_missingBotToken());

            return FormValidation.ok();
        }

这样的话,当我们在全局配置中,未填写botUserName和botToken就会收到相应提示了。


1.png

打包上传

使用指令mvn package进行打包,完成后会在target目录下生成hpi文件。

有两种方式上传插件到Jenkins

  1. 将hpi文件放到Jenkins下的plugins目录下
  2. 通过Jenkins的插件管理中心,进行手动上传hpi文件,具体操作步骤如下图所示:


    插件上传

本文对应的源代码,请移步Jenkins Telegram通知插件

上一篇 下一篇

猜你喜欢

热点阅读