今天介绍一个插件 build-name-setter-plugin

美化 构建 name 和 description 的

默认的 样式 只显示 成 #1, #2, #3 这样的。 我们可以通过 jenkin上的变量 等值 设置到 构建名称上,
例如把参数设置上去,触发人设置上去,能一眼看出来这次构建是干什么的,用了哪些参数等等。

alt tag

例如现这样,设置了这个job 在哪个 节点上执行的,构建类型,新片平台,分支名,触发人 等信息。

1
2
#13034[another-docker-05][TriggerDailyBuild][sm8550][sm8550_s_master][mage]

用法

自由风格中的使用

1
2
3
4
5
6
构建环境 下面 勾选 Set Build Name and Description 那个就行。

然后填上
Build Name处填写 ${GERRIT_CHANGE_SUBJECT}"
Build Description 处填写 Executed @ ${NODE_NAME}

alt tag

这个支持的 参数 挺多的, 例如 环境变量的, job参数的,这是比较常见的。

${BUILD_NUMBER}
${BUILD_STATUS}

${ENV,var="VARIABLENAME"} 展开一个 环境变量的,job参数的

还支持一些特殊的 变量的

${BUILD_LOG_EXCERPT}  从构建日志  解析一段 excerpt 文本的
${BUILD_LOG} 显示构建日志 结尾的一段文本的,也是利用正则匹配的, 没用过


${GROOVY,script = "code"} 执行一段groovy代码的

${PROPFILE,file="FILENAME",property="PROPERTYNAME"}  从文件中 读取一段文本的
${FILE,path="PATH"} 从文件中 读取一段文本的

${XML,file="FILE",xpath="XPATH"}  从xml文件读取 一个 xpath 下的文本的

${TOKEN:offset:length}   还支持 类似 bash 里面的 按长度 切片 一个字符串的
${TOKEN#pattern}  类似 bash 中的
${TOKEN%pattern}  类似 bash 中的

这些用法 都来自 token-macro 插件 https://github.com/jenkinsci/token-macro-plugin

流水线中的用法

1
2
3
4
5

buildName "${GERRIT_CHANGE_SUBJECT}"

buildDescription "Executed @ ${NODE_NAME}"

问题延伸

之前一直在使用 BuildUserVars 和 BuildNameDescriptionSetter 这2个插件, 
通过 BuildUserVars 能够获取到是哪个人触发了构建.这个插件会设置个类似的环境变量 BUILD_USER. 
然后 通过 BuildNameDescriptionSetter 插件 把这个环境变量 BUILD_USER 设置到 构建的 name 上.
方便一眼看出来构建历史中哪个构建是哪个人触发的/或者哪个构建是定时器触发的等等.

jenkins插件学习之BuildUserVars和BuildNameDescriptionSetter插件执行顺序

BuildNameDescriptionSetter 插件有个 " Set build name before build starts	" 
和 " Set build name after build ends	" 选项
发现 只有在  " Set build name after build ends	" 的时候 才能获取到 BUILD_USER 这个变量. 为什么这样的???

通过研究发现 是 因为 BuildUserVars 在 BuildNameDescriptionSetter 之后执行了.

执行顺序 类似 下面这样

①先 BuildNameDescriptionSetter的  " Set build name before build starts	"
②然后是 BuildUserVars 插件设置用户相关的环境变量
③最后 BuildNameDescriptionSetter的  " Set build name after build ends	"

在job的配置界面 “Build Environment” 地方也可以看到 BuildNameDescriptionSetter 插件 在 BuildUserVars 插件上面的.

为什么这么个排序呢?

通过搜索发现 插件 Extension 的排序是 有个 ordinal 值提供排序的. 值越大 越靠前.
默认这2个插件的这个值都是0.  都是0的话 就会按照 插件的 displayName 排序了.


修改的话 可以 把 BuildUserVars 插件的 ordinal 值 设置 大于0.  
第二种修改方法 就是 修改 displayName,让排序 换一下位置.

修改 ordinal 值 设置 大于0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Extension(ordinal = 1) //  ordinal 值 设置 大于0
public static class DescriptorImpl extends BuildWrapperDescriptor {


@Override
public boolean isApplicable(AbstractProject<?, ?> item) {
return true;
}

@Override
public String getDisplayName() {
return EXTENSION_DISPLAY_NAME;
}
}

private static final String EXTENSION_DISPLAY_NAME = "Set jenkins user build variables";

调试 跟踪 分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* Returns all the registered {@link BuildWrapper} descriptors.
*/
// for compatibility we can't use BuildWrapperDescriptor
public static DescriptorExtensionList<BuildWrapper,Descriptor<BuildWrapper>> all() {
// use getDescriptorList and not getExtensionList to pick up legacy instances
return Jenkins.getInstance().<BuildWrapper,Descriptor<BuildWrapper>>getDescriptorList(BuildWrapper.class);
}

public DescriptorExtensionList<T,D> getDescriptorList(Class<T> type) { //type = BuildWrapper.class hudson.tasks.BuildWrapper
return descriptorLists.computeIfAbsent(type, key -> DescriptorExtensionList.createDescriptorList(this, key));
//descriptorLists 中有key对应的值直接就获取到了. 如果没用通过 DescriptorExtensionList.createDescriptorList(this, key) 新建了.

}

descriptorLists

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
descriptorLists 这个里面初始了很多的DescriptorExtensionList, 而我们要找的是 {Class@10416} "class hudson.tasks.BuildWrapper" -> {DescriptorExtensionList@13112}  size = 2 这个对应的.
descriptorLists = {ConcurrentHashMap@13015} size = 14
{Class@10349} "class hudson.views.ListViewColumn" -> {DescriptorExtensionList@13102} size = 8
{Class@8034} "class jenkins.model.GlobalConfiguration" -> {DescriptorExtensionList@13103} size = 22
{Class@10272} "class hudson.model.JobProperty" -> {DescriptorExtensionList@13104} size = 3
{Class@10289} "class hudson.scm.SCM" -> {DescriptorExtensionList@13105} size = 1
{Class@8453} "class hudson.model.PageDecorator" -> {DescriptorExtensionList@13106} size = 8
{Class@10312} "class hudson.tasks.Publisher" -> {Publisher$DescriptorExtensionListImpl@13107} size = 6
{Class@10253} "class hudson.model.ParameterDefinition" -> {DescriptorExtensionList@13108} size = 7
{Class@8698} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@13109} size = 6
{Class@10370} "class jenkins.scm.SCMCheckoutStrategy" -> {DescriptorExtensionList@13110} size = 1
{Class@7731} "class hudson.triggers.Trigger" -> {DescriptorExtensionList@13111} size = 4
{Class@10416} "class hudson.tasks.BuildWrapper" -> {DescriptorExtensionList@13112} size = 2
{Class@8443} "interface hudson.model.TopLevelItem" -> {DescriptorExtensionList@13113} size = 3
{Class@10323} "class jenkins.model.BuildDiscarder" -> {DescriptorExtensionList@13114} size = 1
{Class@10317} "class hudson.tasks.Builder" -> {DescriptorExtensionList@13115} size = 6

1
2
3
4
5
6
7
8
9
10
11
12
13
public static DescriptorExtensionList<T,D> createDescriptorList(Jenkins jenkins, Class<T> describableType) {
if (describableType == (Class) Publisher.class) {
return (DescriptorExtensionList) new Publisher.DescriptorExtensionListImpl(jenkins);
}
return new DescriptorExtensionList<>(jenkins, describableType);
}


@Deprecated 这个方法已经不用了. 传入的参数是hudson 实例而已. 我们看到里面也是强制的把 hudson 转换为 jenkins 实例了.public class Hudson extends Jenkins
public static DescriptorExtensionList<T,D> createDescriptorList(Hudson hudson, Class<T> describableType) {
return (DescriptorExtensionList)createDescriptorList((Jenkins)hudson,describableType);
}

通过在 return descriptorLists.computeIfAbsent(type, key -> DescriptorExtensionList.createDescriptorList(this, key)); 加上断点 调试发现 如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
懒加载啊!

首先重启 debug. 也就是重启了jenkins.
descriptorLists = {ConcurrentHashMap@10542} size = 0 第1次 实例化这个 class hudson.node_monitors.NodeMonitor

descriptorLists = {ConcurrentHashMap@10541} size = 1 第2次. 准备实例化这个 class jenkins.model.GlobalConfiguration
{Class@8698} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@10741} size = 6
到这个时候 jenkins 已经启动起来了. 后续 点击了job的话还会继续实例化 下面的.

descriptorLists = {ConcurrentHashMap@10541} size = 2 第3次 class hudson.model.PageDecorator
{Class@8034} "class jenkins.model.GlobalConfiguration" -> {DescriptorExtensionList@11557} size = 22
{Class@8698} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@10741} size = 6

descriptorLists = {ConcurrentHashMap@10541} size = 3
{Class@8034} "class jenkins.model.GlobalConfiguration" -> {DescriptorExtensionList@11557} size = 22
{Class@8698} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@10741} size = 6
{Class@8454} "class hudson.model.PageDecorator" -> {DescriptorExtensionList@11911} size = 8

descriptorLists = {ConcurrentHashMap@10541} size = 3 第4次 class jenkins.model.GlobalConfiguration
{Class@8034} "class jenkins.model.GlobalConfiguration" -> {DescriptorExtensionList@11557} size = 22
{Class@8698} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@10741} size = 6
{Class@8454} "class hudson.model.PageDecorator" -> {DescriptorExtensionList@11911} size = 8
到这时 是 点击 job 后 又加载的几个实例.

descriptorLists = {ConcurrentHashMap@10541} size = 4 第5次 interface hudson.model.TopLevelItem
{Class@8034} "class jenkins.model.GlobalConfiguration" -> {DescriptorExtensionList@11557} size = 22
{Class@8698} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@10741} size = 6
{Class@8440} "interface hudson.model.TopLevelItem" -> {DescriptorExtensionList@12854} size = 3
{Class@8454} "class hudson.model.PageDecorator" -> {DescriptorExtensionList@11911} size = 8

懒加载啊!
descriptorLists = {ConcurrentHashMap@10542} size = 5 第6次 class jenkins.model.BuildDiscarder
{Class@10273} "class hudson.model.JobProperty" -> {DescriptorExtensionList@12571} size = 3
{Class@8699} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@11527} size = 6
{Class@8455} "class hudson.model.PageDecorator" -> {DescriptorExtensionList@11546} size = 8
{Class@8441} "interface hudson.model.TopLevelItem" -> {DescriptorExtensionList@12401} size = 3
{Class@8035} "class jenkins.model.GlobalConfiguration" -> {DescriptorExtensionList@11528} size = 22

又增加了一个.class jenkins.model.BuildDiscarder!!!
descriptorLists = {ConcurrentHashMap@10542} size = 6
{Class@10273} "class hudson.model.JobProperty" -> {DescriptorExtensionList@12571} size = 3
{Class@8699} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@11527} size = 6
{Class@10324} "class jenkins.model.BuildDiscarder" -> {DescriptorExtensionList@12637} size = 1
{Class@8455} "class hudson.model.PageDecorator" -> {DescriptorExtensionList@11546} size = 8
{Class@8441} "interface hudson.model.TopLevelItem" -> {DescriptorExtensionList@12401} size = 3
{Class@8035} "class jenkins.model.GlobalConfiguration" -> {DescriptorExtensionList@11528} size = 22

又增加了一个.class hudson.model.ParameterDefinition!!! 参数阶段
descriptorLists = {ConcurrentHashMap@10542} size = 7
{Class@10273} "class hudson.model.JobProperty" -> {DescriptorExtensionList@12571} size = 3
{Class@8699} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@11527} size = 6
{Class@10324} "class jenkins.model.BuildDiscarder" -> {DescriptorExtensionList@12637} size = 1
{Class@8455} "class hudson.model.PageDecorator" -> {DescriptorExtensionList@11546} size = 8
{Class@8441} "interface hudson.model.TopLevelItem" -> {DescriptorExtensionList@12401} size = 3
{Class@10251} "class hudson.model.ParameterDefinition" -> {DescriptorExtensionList@12672} size = 7
{Class@8035} "class jenkins.model.GlobalConfiguration" -> {DescriptorExtensionList@11528} size = 22

又增加了一个.class hudson.scm.SCM!!
descriptorLists = {ConcurrentHashMap@10542} size = 8
{Class@10273} "class hudson.model.JobProperty" -> {DescriptorExtensionList@12571} size = 3
{Class@8699} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@11527} size = 6
{Class@10324} "class jenkins.model.BuildDiscarder" -> {DescriptorExtensionList@12637} size = 1
{Class@8455} "class hudson.model.PageDecorator" -> {DescriptorExtensionList@11546} size = 8
{Class@8441} "interface hudson.model.TopLevelItem" -> {DescriptorExtensionList@12401} size = 3
{Class@10251} "class hudson.model.ParameterDefinition" -> {DescriptorExtensionList@12672} size = 7
{Class@10290} "class hudson.scm.SCM" -> {DescriptorExtensionList@12696} size = 1
{Class@8035} "class jenkins.model.GlobalConfiguration" -> {DescriptorExtensionList@11528} size = 22

又增加了一个.class jenkins.scm.SCMCheckoutStrategy!!!! 这个基本上就是 job 配置 页面 从上到下 各个阶段的配置了. 代码检出阶段.
descriptorLists = {ConcurrentHashMap@10542} size = 9
{Class@10273} "class hudson.model.JobProperty" -> {DescriptorExtensionList@12571} size = 3
{Class@8699} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@11527} size = 6
{Class@10324} "class jenkins.model.BuildDiscarder" -> {DescriptorExtensionList@12637} size = 1
{Class@10371} "class jenkins.scm.SCMCheckoutStrategy" -> {DescriptorExtensionList@12722} size = 1
{Class@8455} "class hudson.model.PageDecorator" -> {DescriptorExtensionList@11546} size = 8
{Class@8441} "interface hudson.model.TopLevelItem" -> {DescriptorExtensionList@12401} size = 3
{Class@10251} "class hudson.model.ParameterDefinition" -> {DescriptorExtensionList@12672} size = 7
{Class@10290} "class hudson.scm.SCM" -> {DescriptorExtensionList@12696} size = 1
{Class@8035} "class jenkins.model.GlobalConfiguration" -> {DescriptorExtensionList@11528} size = 22

又增加了一个class hudson.triggers.Trigger!!!这个基本上就是 job 配置 页面 从上到下 各个阶段的配置了. 触发阶段了.
descriptorLists = {ConcurrentHashMap@10542} size = 10
{Class@10273} "class hudson.model.JobProperty" -> {DescriptorExtensionList@12571} size = 3
{Class@8699} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@11527} size = 6
{Class@10324} "class jenkins.model.BuildDiscarder" -> {DescriptorExtensionList@12637} size = 1
{Class@10371} "class jenkins.scm.SCMCheckoutStrategy" -> {DescriptorExtensionList@12722} size = 1
{Class@8455} "class hudson.model.PageDecorator" -> {DescriptorExtensionList@11546} size = 8
{Class@8441} "interface hudson.model.TopLevelItem" -> {DescriptorExtensionList@12401} size = 3
{Class@10251} "class hudson.model.ParameterDefinition" -> {DescriptorExtensionList@12672} size = 7
{Class@7733} "class hudson.triggers.Trigger" -> {DescriptorExtensionList@12770} size = 4
{Class@10290} "class hudson.scm.SCM" -> {DescriptorExtensionList@12696} size = 1
{Class@8035} "class jenkins.model.GlobalConfiguration" -> {DescriptorExtensionList@11528} size = 22



又增加了一个class hudson.tasks.BuildWrapper, !!!! BuildWrapper 阶段了.构建环境设置.那一块了.
descriptorLists = {ConcurrentHashMap@10542} size = 11
{Class@10417} "class hudson.tasks.BuildWrapper" -> {DescriptorExtensionList@12804} size = 2
{Class@10273} "class hudson.model.JobProperty" -> {DescriptorExtensionList@12571} size = 3
{Class@8699} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@11527} size = 6
{Class@10324} "class jenkins.model.BuildDiscarder" -> {DescriptorExtensionList@12637} size = 1
{Class@10371} "class jenkins.scm.SCMCheckoutStrategy" -> {DescriptorExtensionList@12722} size = 1
{Class@8455} "class hudson.model.PageDecorator" -> {DescriptorExtensionList@11546} size = 8
{Class@8441} "interface hudson.model.TopLevelItem" -> {DescriptorExtensionList@12401} size = 3
{Class@10251} "class hudson.model.ParameterDefinition" -> {DescriptorExtensionList@12672} size = 7
{Class@7733} "class hudson.triggers.Trigger" -> {DescriptorExtensionList@12770} size = 4
{Class@10290} "class hudson.scm.SCM" -> {DescriptorExtensionList@12696} size = 1
{Class@8035} "class jenkins.model.GlobalConfiguration" -> {DescriptorExtensionList@11528} size = 22

又增加了一个 class hudson.tasks.Builder !!! 构建阶段
descriptorLists = {ConcurrentHashMap@10542} size = 12
{Class@10417} "class hudson.tasks.BuildWrapper" -> {DescriptorExtensionList@12804} size = 2
{Class@10324} "class jenkins.model.BuildDiscarder" -> {DescriptorExtensionList@12637} size = 1
{Class@10318} "class hudson.tasks.Builder" -> {DescriptorExtensionList@12845} size = 6
{Class@7733} "class hudson.triggers.Trigger" -> {DescriptorExtensionList@12770} size = 4
{Class@8035} "class jenkins.model.GlobalConfiguration" -> {DescriptorExtensionList@11528} size = 22
{Class@10273} "class hudson.model.JobProperty" -> {DescriptorExtensionList@12571} size = 3
{Class@8699} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@11527} size = 6
{Class@10371} "class jenkins.scm.SCMCheckoutStrategy" -> {DescriptorExtensionList@12722} size = 1
{Class@8455} "class hudson.model.PageDecorator" -> {DescriptorExtensionList@11546} size = 8
{Class@10251} "class hudson.model.ParameterDefinition" -> {DescriptorExtensionList@12672} size = 7
{Class@8441} "interface hudson.model.TopLevelItem" -> {DescriptorExtensionList@12401} size = 3
{Class@10290} "class hudson.scm.SCM" -> {DescriptorExtensionList@12696} size = 1

又增加了一个class hudson.tasks.Publisher
descriptorLists = {ConcurrentHashMap@10542} size = 13
{Class@10417} "class hudson.tasks.BuildWrapper" -> {DescriptorExtensionList@12804} size = 2
{Class@10324} "class jenkins.model.BuildDiscarder" -> {DescriptorExtensionList@12637} size = 1
{Class@10318} "class hudson.tasks.Builder" -> {DescriptorExtensionList@12845} size = 6
{Class@7733} "class hudson.triggers.Trigger" -> {DescriptorExtensionList@12770} size = 4
{Class@8035} "class jenkins.model.GlobalConfiguration" -> {DescriptorExtensionList@11528} size = 22
{Class@10313} "class hudson.tasks.Publisher" -> {Publisher$DescriptorExtensionListImpl@13032} size = 6
{Class@10273} "class hudson.model.JobProperty" -> {DescriptorExtensionList@12571} size = 3
{Class@8699} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@11527} size = 6
{Class@10371} "class jenkins.scm.SCMCheckoutStrategy" -> {DescriptorExtensionList@12722} size = 1
{Class@8455} "class hudson.model.PageDecorator" -> {DescriptorExtensionList@11546} size = 8
{Class@10251} "class hudson.model.ParameterDefinition" -> {DescriptorExtensionList@12672} size = 7
{Class@8441} "interface hudson.model.TopLevelItem" -> {DescriptorExtensionList@12401} size = 3
{Class@10290} "class hudson.scm.SCM" -> {DescriptorExtensionList@12696} size = 1



descriptorLists = {ConcurrentHashMap@10542} size = 14
{Class@10417} "class hudson.tasks.BuildWrapper" -> {DescriptorExtensionList@12804} size = 2
{Class@10324} "class jenkins.model.BuildDiscarder" -> {DescriptorExtensionList@12637} size = 1
{Class@10318} "class hudson.tasks.Builder" -> {DescriptorExtensionList@12845} size = 6
{Class@7733} "class hudson.triggers.Trigger" -> {DescriptorExtensionList@12770} size = 4
{Class@8035} "class jenkins.model.GlobalConfiguration" -> {DescriptorExtensionList@11528} size = 22
{Class@10313} "class hudson.tasks.Publisher" -> {Publisher$DescriptorExtensionListImpl@13032} size = 6
{Class@10273} "class hudson.model.JobProperty" -> {DescriptorExtensionList@12571} size = 3
{Class@8699} "class hudson.node_monitors.NodeMonitor" -> {DescriptorExtensionList@11527} size = 6
{Class@10371} "class jenkins.scm.SCMCheckoutStrategy" -> {DescriptorExtensionList@12722} size = 1
{Class@8455} "class hudson.model.PageDecorator" -> {DescriptorExtensionList@11546} size = 8
{Class@10251} "class hudson.model.ParameterDefinition" -> {DescriptorExtensionList@12672} size = 7
{Class@8441} "interface hudson.model.TopLevelItem" -> {DescriptorExtensionList@12401} size = 3
{Class@10350} "class hudson.views.ListViewColumn" -> {DescriptorExtensionList@13278} size = 8
{Class@10290} "class hudson.scm.SCM" -> {DescriptorExtensionList@12696} size = 1

在 Project 类中的 submit()方法中会调用到 BuildWrappers.getFor(this) 方法. submit()方法 方法就是点了job配置里面的save按钮触发的.

1
2
3
4
5
6
7
8
9
10
11
12
public abstract class Project<P extends Project<P,B>,B extends Build<P,B>>
extends AbstractProject<P,B> implements SCMTriggerItem, Saveable, ProjectWithMaven, BuildableItemWithBuildWrappers {
@Override
protected void submit( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException, FormException {
super.submit(req,rsp);

JSONObject json = req.getSubmittedForm();

getBuildWrappersList().rebuild(req,json, BuildWrappers.getFor(this));
getBuildersList().rebuildHetero(req,json, Builder.all(), "builder");
getPublishersList().rebuildHetero(req, json, Publisher.all(), "publisher");
}

BuildWrappers 中的 getFor 方法, 这里会遍历 所有的 BuildWrapperDescriptor 子类的 。
BuildWrapper.all() 获取所有的 Descriptor 类型。然后还会 判断 isApplicable 返回值是否true,是TRUE表示启动这个类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

public class BuildWrappers {
/**
* List up all {@link BuildWrapperDescriptor}s that are applicable for the given project.
*
* @return
* The signature doesn't use {@link BuildWrapperDescriptor} to maintain compatibility
* with {@link BuildWrapper} implementations before 1.150.
*/
public static List<Descriptor<BuildWrapper>> getFor(AbstractProject<?, ?> project) {
List<Descriptor<BuildWrapper>> result = new ArrayList<>();
Descriptor pd = Jenkins.getInstance().getDescriptor((Class)project.getClass());

for (Descriptor<BuildWrapper> w : BuildWrapper.all()) {
if (pd instanceof AbstractProjectDescriptor && !((AbstractProjectDescriptor)pd).isApplicable(w))
continue;
if (w instanceof BuildWrapperDescriptor) {
BuildWrapperDescriptor bwd = (BuildWrapperDescriptor) w;
if(bwd.isApplicable(project))
result.add(bwd);
} else {
// old BuildWrapper that doesn't implement BuildWrapperDescriptor
result.add(w);
}
}
return result;
}
}

通过 调用 BuildWrappers 中的 getFor()方法.
调用到 for (Descriptor w : BuildWrapper.all()) { 时候会 执行到 public @Nonnull Iterator iterator() { 里面

1
2
3
4
5
6
7
8
9
@Override
public @Nonnull Iterator<T> iterator() {
// we need to intercept mutation, so for now don't allow Iterator.remove
return new AdaptedIterator<ExtensionComponent<T>,T>(Iterators.readOnly(ensureLoaded().iterator())) {
protected T adapt(ExtensionComponent<T> item) {
return item.getInstance();
}
};
}

然后iterator() 方法里面会调用 ensureLoaded() 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    private List<ExtensionComponent<T>> ensureLoaded() {
if(extensions!=null)
return extensions; // already loaded
if (jenkins.getInitLevel().compareTo(InitMilestone.PLUGINS_PREPARED)<0)
return legacyInstances; // can't perform the auto discovery until all plugins are loaded, so just make the legacy instances visible

synchronized (getLoadLock()) {
if(extensions==null) {
List<ExtensionComponent<T>> r = load();
r.addAll(legacyInstances);
extensions = sort(r);
}
return extensions;
}
}
```

最后 ensureLoaded() 里面会对 List 进行 排序.
```java
/**
* If the {@link ExtensionList} implementation requires sorting extensions,
* override this method to do so.
*
* <p>
* The implementation should copy a list, do a sort, and return the new instance.
*/
protected List<ExtensionComponent<T>> sort(List<ExtensionComponent<T>> r) {
r = new ArrayList<>(r);
Collections.sort(r);
return r;
}

排序的时候会调用到 ExtensionComponent 里面的 compareTo(ExtensionComponent that) 方法.

DescriptorExtensionList 中有存放的 ExtensionComponent 的一个集合. 然后 ExtensionComponent 中会有个 compareTo 比较顺序的方法.
然后比较出来的顺序就是 BuildWrapper 类型插件 的执行的先后顺序.
如果设置了 ordinal 值. 值越大 越先执行的(也就是job设置界面里面越靠上)没有设置ordinal就比较 displayname. 按照字符串比较的.
如果比较displayname失败会比较getClass().getName(),也是按照字符串比较。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

this = {DescriptorExtensionList@12209} size = 2
0 = {BuildNameSetter$DescriptorImpl@12212}
1 = {BuildUser$DescriptorImpl@12213}

/**
* Sort {@link ExtensionComponent}s in the descending order of {@link #ordinal()}.
*/
public int compareTo(ExtensionComponent<T> that) {
double a = this.ordinal();
double b = that.ordinal();
if (a>b) return -1;
if (a<b) return 1;

// make the order bit more deterministic among extensions of the same ordinal
if (this.instance instanceof Descriptor && that.instance instanceof Descriptor) {
try {
return Util.fixNull(((Descriptor)this.instance).getDisplayName()).compareTo(Util.fixNull(((Descriptor)that.instance).getDisplayName()));
} catch (RuntimeException | LinkageError x) {
LOG.log(Level.WARNING, null, x);
}
}
return this.instance.getClass().getName().compareTo(that.instance.getClass().getName());
}


修改

这里我采用了修改build-user-vars-plugin插件的display的方法,本来就觉得他设置的displayname看着不爽。

1
2
3
private static final String EXTENSION_DISPLAY_NAME = "Set jenkins user build variables";
private static final String EXTENSION_DISPLAY_NAME = "Set Build User Variables";

其他参考

可以参考 https://github.com/mamh-java/build-user-vars-plugin