Jelly基础

参考:https://wiki.jenkins-ci.org/display/JENKINS/Basic+guide+to+Jelly+usage+in+Jenkins

UI Samples Plugin

这个插件就是用来展示如何使用基于Stapler, Jelly, Groovy等技术的Jenkins UI 控件的。安装这个插件对学习Jenkins插件开发非常有用。

创建*.jelly文件

一个基本的jenkins插件结构包括以下几个部分:

  • pom.xml
  • src/main/java
  • src/main/resources
  • src/main/webapp

假如已经写好一个类  src/main/java/org/myorganization/MyAction.java,要为这个类定义一个Jelly文件。

  1. 在resources目录中创建一个与类名一一对应的目录:  src/main/resources/org/myorganization/MyAction
  2. 在这个目录中添加.jelly文件(不同的文件名会有不同的作用),如index.jelly。
  3. 然后就是编辑这个文件

预定义对象

一个目录下的所有Jelly文件都跟和该目录一一对应的某个类直接关联。这个对应的类对象会绑定到jelly文件中名字为 it 的变量上,jelly文件中可以通过it变量调用类中的方法,调用代码要用一对大括号包裹,前括号前加$。形式为:${insert code here}

例如在MyAction.java中定义了如下的方法

public String getMyString() {
return "Hello Jenkins!";
}

在jelly文件中调用这个方法的示例

<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">
${it.myString}
</j:jelly>

方法名开头的get被自动去掉了,剩余部分首字母变成小写。建议使用java约定的命名方式(如getter方法都是get开头的CamelCase形式)确保Jelly能够找到正确的方法。

Jenkins中预定义对象主要有

it

  与jelly文件直接关联的类实例

instance

  当前正在被配置的对象(在配置页面中的一个区域内),例如BuildStep。如果不是重新配置而是刚添加了一个新的实例的话这个变量为null。

app

  Jenkins(或Hudson)实例

descriptor

与instance对象所属类对应的Descriptor对象

h

hudson.Functions对象的实例,提供了很多非常有用的方法。

预定义URL变量

rootURL

Jenkins实例的URL

resURL

JavaScript, HTML等静态webapp资源(cf.  Jenkins.RESOURCE_PATH)

imagesURL

图标等图像资源路径 ,实际就是resURL/images

应尽可能使用resURL而不是rootURL,因为resURL允许浏览器缓存,可以提高响应速度减轻服务器压力。

只要在l:layout或l:ajax块内,这些URL就已经定义好了,也就是说在任何的Jenkins页面里都可以使用(如果页面是通过ajax加载的,需要添加l:ajax标签)。

Note that until 1.505 rootURL will be empty in the typical case of Jenkins running in development mode with no context path (http://localhost:8080/); it is used for creating server-absolute paths such as /some/path for direct links. As of 1.505 it will be /jenkins in test mode, to help remind you to use it! In the rare case that you need to pass a complete URL to an external service for some reason, use app.rootUrl instead (which takes into account “Jenkins URL” from the system /configure screen). Hyperlinks in HTML has a fuller treatment of this topic.

大多数情况下,jelly文件修改后不需要重启Jenkins服务就能看到效果。修改文件然后重新请求页面,修改后的jelly文件就会被加载了。

带Descriptors的对象(如Publisher)

  1. 定义一个不可变的类将所有的配置选项作为构造器的参数。然后给这个构造器加上@DataBoundConstructor注解,Jenkins通过这个注解就能知道如何实例化这个类的对象。
  2. 为配置选项字段添加getter方法,或者将配置选项字段改为public final。Jelly脚本中就可以读取这些字段值到配置页面中。
  3. 编写Jelly片段文件(一般会叫config.jelly,可以查看基类的javadoc文档看看可以使用哪些jelly文件名字),在jelly文件中展示所有的配置选项。最基本的形式如下(jelly元素的field属性即是属性的名字,也是构造器参数的名字,这个例子中jelly文件对应的类需要提供getPort方法或public port字段)。
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<f:entry title="${%Port}" field="port">
<f:textbox />
</f:entry>
<f:entry title="${%Host}" field="host">
<f:textbox />
</f:entry>
</j:jelly>

${%...}为国际化标记(https://wiki.jenkins-ci.org/display/JENKINS/Internationalization)。

Help文件

插件可以使用src/main/resources/path/to/plugin/PluginName目录中的help-FIELD.htmlhelp-FIELD.jelly文件。Jenkins会在对应的Filed元素后添加一个问号图标,点击图标就会将帮助文件在配置页面中内联的渲染出来。help.htmlhelp.jelly会作为插件顶级的帮助文件。

表单验证

在descriptor类中添加的doCheckFIELD方法,会被用于表单验证逻辑。示例如下:

public FormValidation doCheckPort(@QueryParameter String value) {
if(looksOk(value)) return FormValidation.ok();
else return FormValidation.error("There's a problem here");
}

这个方法中可以有多个指定了具体Filed的@QueryParameter("FIELD")注解参数,同时获得多个参数值。可以表单field之间相互依赖关系的验证。更详细的内容可以查询stapler的文档。

默认值

可以使用页面元素的default属性为表单域设置默认值。即可以用字面值,也可以编程式的方式计算默认值(使用jelly预定义的变量,调用这些对象的方法)。示例如下:

<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<f:entry title="${%Port}" field="port">
<f:textbox default="80" />
</f:entry>
<f:entry title="${%Host}" field="host">
<f:textbox default="${descriptor.defaultHost()}/>
</f:entry>
</j:jelly>

无Descriptor的对象(如ComputerListener)

参考插件:https://github.com/jenkinsci/sidebar-link-plugin

如果插件用了无Descriptor的对象,如ComputerListener。可以按下面的步骤,在配置页面中增加一个插件类(Plugin的子类)可读取的文本框。

  1. 重写 plugin类的configure(StaplerRequest req, JSONObject formData)方法。这个方法会在用户点击配置页面的保存按钮是被调用。
  2. 在configure方法里,调用formData的提取数据方法获取配置值,如optInt("port",3141),将获取的数据保存在Plugin类的成员字段中。
  3. 在configure方法里,调用save()方法,将plugin类的可序列化字段持久化存储。
  4. 在plugin类的start方法中,调用load(),插件启动时重新加载持久化存储的数据。
  5. 在与plugin类对应的位置(src/main/resources/path/to/plugin/className/config.jelly)创建config.jelly文件,编写配置页面视图。在插件类的config.jelly中,用变量it代替变量instance,it.port可以引用当前使用的port参数值。help属性使用创建插件时pom.xml中指定的artifactId引用插件的资源。
    <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="My Plugin">
    <f:entry title="${%Port}" help="/plugin/ARTIFACT_ID_GOES_HERE/help-projectConfig.html">
    <f:textbox name="port" value="${it.port}"/>
    </f:entry>
    </f:section>
    </j:jelly>
  6. 在src/main/webapp中创建help文件help-projectConfig.html。
  7. 正常启动Jenkins(mvn hpi:run),查看效果。

HTML中的超链接

https://wiki.jenkins-ci.org/display/JENKINS/Hyperlinks+in+HTML

规则1:超链接不要使用绝对URL

  HTML中的超链接应该使用相对URL(如../foo/bar,  build/5/changes)或应用相对URL(以/开头,如/job/foo/5, /manage)。但是前面不要用绝对路径(如http://jenkins/foo/1)。让浏览器将相对路径绝对化。

  这条规则的原因是,经过反向代理等过程后,web应用无法知道客户端用来访问服务器的URL。但是反向代理都会保证URL中的路径部分(context path+path info)是原封不动的,使用应用内部的相对路径不会有任何影响。

  在JavaEE中,URL的路径部分可分为两段,先是context path,后面跟着Path Info。例如http://server.example.com/jenkins/job/foo/5,/jenkins为context path,/job/foo/5为path info。Jenkins开发者可以控制后者。

  • getUrl()方法可以在整个Jenkins中返回域对象的path info部分,如Buiild.getUrl()返回job/foo/32/(开头没有/,结尾的/不同版本并不一致)。
  • getAbsoluteUrl()在整个Jenkins中返回域对象的绝对路径。不要用这个方法渲染超链接。
  • 在Groovy/Jelly/JavaScript中,rootURL变量代表了context path。生成相对的超链接格式为:<a href="${rootURL}/${it.url}">...</a> (in Jelly) 或 a(href:"${rootURL}/${my.url}", ...) (for Groovy)

规则2:使用静态资源前缀URL访问静态资源

  图片,JavaScript脚本,样式表等静态资源在Jenkins运行中不会变化,应该使用静态资源前缀的URL(/static/XXXXX)访问,如/static/907dbcb0/plugin/foobar/abc.png。XXXXX部分是Jenkins为运行中的Jenkins Session持续期而生成的随机字符串。请求的路由与不带前缀的相同,但是带了前缀后头信息中会设置很长的过期时间,让浏览器使用缓存。随机数字是为了防止plugins/core更新后浏览器使用旧数据。

在Java中: Functions.getResourcePath()作为URL的前缀。在Jelly中使用resURL变量。

Functions.getResourcePath()+"/plugin/git/icons/git-32x32.png";

<img src="${resURL}/plugin/translation/flags.png" />

规则3:为email,IM等生成绝对路径

如果以HTTP响应以为的方式提供服务数据,需要生成绝对路径。可用Jenkins.getInstance().getRootUrl()方法,将返回管理员配置的绝对路径。这是在Jenkins实例中准确获取绝对路径的唯一方法。

规则4:ConsoleNote必须为Path-Info

通过HyperlinkNote向控制台输出中嵌入超链接时,使用/开头的URL创建便携的超链接(如果URL以/开头,就会相对于context path处理)。这样就算控制台note创建以后,Jenkins URL变了,超链接依然能正确渲染。

void foo(TaskListener listener) {
listener.getLogger().println(
HyperlinkNote.encodeTo("/configure","Please configure your Jenkins"));
}

在Jenkins轻易地创建指向不同对象的超链接,可以查阅ModelHyperlinkNote类(http://javadoc.jenkins-ci.org/?hudson/console/ModelHyperlinkNote.html)。

反向代理和Https

如果反向代理终止了HTTPS,Jenkins无法利用HttpServletRequest#isSecure()检查传输是否安全。Jenkins.isRootUrlSecure()可以检查管理员配置的Jenkins URL是否是Https。

其他与路径有关的主题

https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+says+my+reverse+proxy+setup+is+broken

https://wiki.jenkins-ci.org/display/JENKINS/Running+Jenkins+behind+Apache

https://wiki.jenkins-ci.org/display/JENKINS/Running+Jenkins+behind+Nginx

国际化

https://wiki.jenkins-ci.org/display/JENKINS/Internationalization

properties文件默认编码为ISO-8859-1。静态资源文件编码为UTF-8。

Messages类

  Jenkins使用Localizer(https://java.net/projects/localizer/)生成Messages类,能够以类型安全的方式访问Message资源。src/main/resources/**/Messages.properties匹配的所以文件都会生成一个对应的Messages类。如过IDE找不到这些类,需要手动将target/generated-sources/localizer目录加入源码的根目录。返回用于显示的字符串的代码(如Descriptor.getDisplayName())可以使用Messages类获取本地化的消息。在运行时,适当的locale会被自动选择。

  典型的工作流如下:

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

  如果消息中包含单引号('),需要再用一个单引号昨晚转义('')。如果想使用英文撇号(’),可以用unicode字符 U+2019,在properties文件中写成\u2019。

在Jelly文件中标记消息

 ${%xxxx} 标记指示stapler查找本地化资源, 如果没有找到对应资源,就原样输出xxxx。

<h1>${%Output}</h1>

带参数消息

要渲染出的结果:

 <p>Click <a href="${obj.someMethod(a,b,c)}" >here</a></p>

foo.properties文件中内容为:

click.here.link = Click <a href="{0}" >here</a>

jelly中消息引用标记:

<p>${%click.here.link(obj.someMethod(a,b,c))}</p>

因为参数使用了的括号()包裹,所以普通文本中不能包含括号。

<h1>${%Path to file (.ipa or .apk)}</h1>     解析会出错

这种情况下可以通过拆分文本,将括号排除在{% }标记外部

<h1>${%Path to file} (${%.ipa or .apk})</h1>    

多个参数

多个参数之间用 , 分隔(类似方法调用)。在properties文件中按参数位置引用 {0}为第一个参数,{1}为第二个参数......(按MessageFormat解析,参考:http://docs.oracle.com/javase/6/docs/api/java/text/MessageFormat.html

<p>${h.ifThenElse(x,"no error","error")}</p>

参数中再标记消息,不需要大括号{}包裹

<p>${h.ifThenElse(x,"%no error","%error")}</p>

help.html和help-FILED.html文件的本地化

默认help.html为English。然后再为xx语言创建help_xx.html文件即可。

翻译

Translation Tool :命令行资源文件翻译工具(https://wiki.jenkins-ci.org/display/JENKINS/Translation+Tool)

Translation Assistance Plugin :Adds a dialog box in Jenkins to translate and send missing keys.

Stapler plugin for IntelliJ IDEA: 利用反射提取java代码中的资源到properties文件(mvn compile编译之前会显示错误)。

NetBeans plugin for Stapler

要翻译的内容

  • Messages.properties
  • jelly文件。可以先调用mvn stapler:i18n -Dlocal=fr,生成一个骨架文件*_fr.properties,所以条目值都为空。如果文件已经存在则添加之前不存在的新条目。留空的条目会回退到默认的locale。
  • 静态HTML资源。foo_xx.html

翻译完成度报告

http://www.simonwiest.de/glottr/report/

Jenkins中Jelly基础、超链接、国际化的更多相关文章

  1. Jenkins中Jelly邮件模板的配置

    [链接]Jenkins中Jelly邮件模板的配置http://blog.csdn.net/hwhua1986/article/details/47975237

  2. Jenkins中集成Gcov代码覆盖率报告

    最近终于把gcov代码覆盖报告集成到jenkins中了,总算是完成工作,写篇博客总结下. 我循序渐进地用了三个工具:gcov, lcov, gcovr 这三个工具原理(其实gcovr依赖于GNU的gc ...

  3. 新建项目到Jenkins中

    在以Jenkins为镜像创建Docker容器时,我们在jenkins的dockerfile文件中写明了要安装Docker Compose,目的也是在Jenkins容器中借助Docker Compose ...

  4. Jenkins中的邮件配置

    摘自http://blog.csdn.net/fullbug/article/details/53024562 Jenkins是一个很受欢迎的CI持续集成工具,能够实现项目的自动构建.打包.测试.发布 ...

  5. jenkins中Email Extersion Plugin插件使用说明点

    在jenkins中使用第3方邮件插件Email Extersion Plugin时,根据网上教程,发现每次都没有生成模板 再次查看,发现 $HOME_jenkins下没有templeate文件夹,查阅 ...

  6. HTML&CSS基础-超链接

    HTML&CSS基础-超链接 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.如下图所示,有三个网页 <!DOCTYPE html> <!--Docty ...

  7. Jenkins中构建Testcomplete项目的方法介绍

    Jenkins的部署在上一篇随笔中已经和大家介绍了,下面我们介绍一下再Jenkins中构建testcomplete项目.我这里使用的是Testcomplete11,下面详细介绍一下构建步骤. 1.Je ...

  8. 在Jenkins中获取GitHub对应Repository的Resource Code

    1):Install Jenkins 请看如下链接: https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins 2):Install ...

  9. [.net 面向对象编程基础] (3) 基础中的基础——数据类型

    [.net 面向对象编程基础] (3) 基础中的基础——数据类型 关于数据类型,这是基础中的基础. 基础..基础..基础.基本功必须要扎实. 首先,从使用电脑开始,再到编程,电脑要存储数据,就要按类型 ...

随机推荐

  1. js-错误处理与调试,JSON

    错误处理与调试: 1.try-catch try{ window.someNoneXistentFunction(); }catch(error){ alert(error.message) } 2. ...

  2. 【转】ContextLoaderListener 和 DispatcherServlet

    转载地址: http://www.guoweiwei.com/archives/797 DispatcherServlet介绍 DispatcherServlet是Spring前端控制器的实现,提供S ...

  3. 将公司的主要项目从eclipse迁移到android studio for mac环境(1)

    上星期,我决定要解决这个问题.理由如下: 3个月之前,我已经投入一段时间要做好这个迁移工作,直到最后,我发现能够安装了,但是运行不了,这个过程也看不到bugly上传,在找不到原因的情况下,我放弃了. ...

  4. WPF Datagrid multiple selecteditems in MVVM

    I can assure you: SelectedItems is indeed bindable as a XAML CommandParameter After a lot of digging ...

  5. How to retrieve instance parameters from an uninstantiated (uninserted) family

    The trick to be able to read the default values for instance parameters is to get to the FamilyManag ...

  6. Android GPS 取经纬度

    // 获取位置管理服务 private LocationManager locationManager;3 String mProviderName = ""; private v ...

  7. Codeforces Round #248 (Div. 2) A. Kitahara Haruki's Gift

    解决思路是统计100的个数为cnt1,200的个数为cnt2 则 cnt1    cnt2 奇数      奇数 奇数      偶数 偶数      奇数 偶数     偶数 当cnt1为奇数时一定 ...

  8. 彻底弄明白之数据结构中的KMP算法

    如何加速朴素查找算法? KMP,当然还有其他算法,后续介绍.      Knuth–Morris–Pratt string search algorithm Start at LHS of strin ...

  9. 【bzoj1367】[Baltic2004]sequence

    2016-05-31 17:31:26 题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1367 题解:http://www.cnblogs.co ...

  10. python select

    server #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ @author: zengchunyun " ...