Jenkins插件开发hellworld

    xiaoxiao2021-03-25  120

    jenkins本身提供了一套插件的管理机制,这些插件允许可插拨形式存在。jenkins插件虽然能提供很多种插件,但还是不能满足我们持续集成的需要,所以需要定制一些插件来支撑整个持续集成平台的运行。 Jenkins运行周期: 1.checkout -check out出源码 2.Pre-build - 预编译 3.Build wrapper-准备构建的环境,设置环境变量等 4.Builder runs -执行构建,比如调用calling Ant, Make 等等 5.Recording - 记录输出,如测试结果 6.Notification - 通知成员 Jenkins提供的扩展点: 为了支撑插件能在各个生命周期中运行,jenkins提供了各种扩展点,我们主类必须要extends一个扩展点;针对现状,基本上只需要使用Notifier,与builder这两个扩展点;详细如下: 1.Builder:这个扩展点支撑的是构建这个阶段需要做的事情,包括prebuild postbuid、构建环境等步骤,例如我们更换slave机器的hosts插件 2.Notifier:包括通知、消息通知等情况,我们的sendnapolimessage是基于这种扩展点来开发的 具体扩展点说明请参考:Extension+points 插件开始手册:Plugin+tutorial 下面说一下开发流程: 开发环境需要安装maven和jdk环境。

    1.maven配置

    配置maven的settings.xml配置文件

    <settings> <pluginGroups> <pluginGroup>org.jenkins-ci.tools</pluginGroup> </pluginGroups> <mirrors> <mirror> <id>repo.jenkins-ci.org</id> <url>http://repo.jenkins-ci.org/public/</url> <mirrorOf>m.g.o-public</mirrorOf> </mirror> </mirrors> <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> </settings>

    2.创建插件maven项目

    运行命令:mvn -cpu hpi:create 该操作需要你输入一些参数,比如说groupid=cn.slimsmart.jenkins.plugin,artifactid=helloword。之后会创建一个新的插件模板便于开发者之后的开发工作。 创建完成使用mvn clean package试试是否可以打包完成。 注:我遇见javadoc: 错误 - java.lang.IllegalArgumentException错误,原因是在解析环境变量classpath时使用了%JAVA_HOME%导致,修改classpath不适用变量就解决了。 创建的项目结构如下:

    pom.xml:Maven的构建配置文件 src/main/java:Java源文件目录 src/main/resources:插件Jelly/Grovy视图 src/main/webapps:插件的静态资源如images和html文件

    生成的代码中包含一个HelloWorldBuilder模板。当用户配置项目并启用此构建器时{@link DescriptorImpl#newInstance(StaplerRequest)}会被调用创建一个{@link HelloWorldBuilder} 实例创建实例通过使用持久化到项目配置XML XStream,所以这样可以使用实例字段(如{@link #name})记住配置。执行构建时,{@link #perform}方法将被调用。

    3.调试运行

    增加远程调试

    #window set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n #linux #export MAVEN_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n" mvn hpi:run -Djetty.port=8090 -Dhpi.prefix=/jenkins #hpi.prefix设置context path

    可以在一运行的jenkins的web界面中由Manage Jenkins>Manage Plugins>Advanced上传插件。 设置及构建运行

    4.实例代码

    package cn.slimsmart.jenkins.plugin.helloword; import hudson.Launcher; import hudson.Extension; import hudson.FilePath; 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 jenkins.tasks.SimpleBuildStep; import net.sf.json.JSONObject; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.QueryParameter; import javax.servlet.ServletException; import java.io.IOException; /** * <p> * 当用户配置项目并启用此构建器时{@link DescriptorImpl#newInstance(StaplerRequest)}会被调用创建一个{@link HelloWorldBuilder} 实例 * 创建实例通过使用持久化到项目配置XML XStream,所以这样可以使用实例字段(如{@link #name})记住配置。 * 执行构建时,{@link #perform}方法将被调用。 * </p> */ public class HelloWorldBuilder extends Builder implements SimpleBuildStep { private final String name; // config.jelly中的textbox字段必须与“DataBoundConstructor”中的参数名匹配 @DataBoundConstructor public HelloWorldBuilder(String name) { this.name = name; } /** * 我们将在{@code config.jelly}中使用它。 */ public String getName() { return name; } /** * 执行构建时,perform方法将被调用 * Build参数是描述了当前任务的一次构建,通过它可以访问到一些比较重要的模型对象如:project当前项目的对象、workspace构建的工作空间、Result当前构建步骤的结果。 * Launcher参数用于启动构建。 * BuildListener该接口用于检查构建过程的状态(开始、失败、成功..),通过它可以在构建过程中发送一些控制台信息给jenkins。 * perform方法的返回值告诉jenkins当前步骤是否成功,如果失败了jenkins将放弃后续的步骤。 */ @Override public void perform(Run<?,?> build, FilePath workspace, Launcher launcher, TaskListener listener) { // This is where you 'build' the project. // Since this is a dummy, we just say 'hello world' and call that a build. // This also shows how you can consult the global configuration of the builder if (getDescriptor().getUseFrench()) listener.getLogger().println("Bonjour, "+name+"!"); else{ listener.getLogger().println("Hello, "+name+"!"); } listener.getLogger().println("workspace="+workspace); listener.getLogger().println("number="+build.getNumber()); listener.getLogger().println("url="+build.getUrl()); } // Overridden for better type safety. // If your plugin doesn't really define any property on Descriptor, // you don't have to do this. //插件描述类 @Override public DescriptorImpl getDescriptor() { return (DescriptorImpl)super.getDescriptor(); } /** * Descriptor for {@link HelloWorldBuilder}. Used as a singleton. * The class is marked as public so that it can be accessed from views. * * <p> * See {@code src/main/resources/hudson/plugins/hello_world/HelloWorldBuilder/*.jelly} * for the actual HTML fragment for the configuration screen. * 用于配置屏幕的实际HTML片段 */ @Extension // This indicates to Jenkins that this is an implementation of an extension point. public static final class DescriptorImpl extends BuildStepDescriptor<Builder> { /** * 要保留全局配置信息,只需将其存储在一个字段中并调用save * 如果您不希望字段持久化,请使用{@code transient}。 * global.jelly中checkbox的useFrench一至,全局配置 */ private boolean useFrench; /** * In order为了加载持久化的全局配置,你必须在构造函数中调用load() */ public DescriptorImpl() { load(); } /** * Performs on-the-fly validation of the form field 'name'. * 执行表单字段“名称”的即时验证。 * @param value * This parameter receives the value that the user has typed. * @return * Indicates the outcome of the validation. This is sent to the browser. * <p> * Note that returning {@link FormValidation#error(String)} does not * prevent the form from being saved. It just means that a message * will be displayed to the user. */ public FormValidation doCheckName(@QueryParameter String value) throws IOException, ServletException { if (value.length() == 0) return FormValidation.error("Please set a name"); if (value.length() < 4) return FormValidation.warning("Isn't the name too short?"); return FormValidation.ok(); } // 表示此构建器是否可用于各种项目类型 public boolean isApplicable(Class<? extends AbstractProject> aClass) { // Indicates that this builder can be used with all kinds of project types return true; } /** * This human readable name is used in the configuration screen. */ public String getDisplayName() { return "Say hello world"; } @Override public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { // To persist global configuration information, // set that to properties and call save(). useFrench = formData.getBoolean("useFrench"); // ^Can also use req.bindJSON(this, formData); // (easier when there are many fields; need set* methods for this, like setUseFrench) save(); return super.configure(req,formData); } /** * This method returns true if the global configuration says we should speak French. * * The method name is bit awkward because global.jelly calls this method to determine * the initial state of the checkbox by the naming convention. */ public boolean getUseFrench() { return useFrench; } } }

    该实例使用了jenkins的Builder作为扩展点,实现了BuildStep,通过内部类DescripotorImpl添加@Extension声明,告诉系统该内部类是作为BuildStepDescriptor的扩展出现。 这里基本完成了扩展点的后台代码部分,但是扩展过程中还需要对前端页面进行扩张,这时就需要建立一个pcakage放置该扩展类对应的视图。Jenkins使用了Jelly页面渲染技术,这是一个基于XML的服务端页面渲染引擎,其将基于Jelly的xml标签转换为对应的Html标签并输出到客户端。模型对象的信息通过Jexl表达式被传递到页面上(相当于Jsp的JSTL)。jelly文件以.jelly为后缀,在hudson中使用类全名的形式来查找模型类对应的jelly页面文件,如名为src/main/java/cn/slimsmart/jenkins/plugin/helloword/HelloWorldBuilder.java的类,其对应的页面文件应该存在于src/main/resources/cn/slimsmart/jenkins/plugin/helloword/HelloWorldBuilder目录的下。 视图有三种: 1.全局配置(global.jelly->系统管理-系统设置) 2.Job配置(config.jelly->每个Job而言需要的配置信息) 3.还有就是使用帮助(help-字段名).html 关于jelly学习参考:Basic+guide+to+Jelly+usage+in+Jenkins 参考文章: 1.jenkins插件开发 2.浅析 Jenkins 插件开发 3.Jenkins插件开发入门

    转载请注明原文地址: https://ju.6miu.com/read-21671.html

    最新回复(0)