Skip to content

Commit 96c4778

Browse files
Support new experimental build and job page (#344)
* Support new experimental build and job page * Add tests * Fix duplicate summary in legacy tab * Fix tab * Add factory test * Fix jelly file formatting * Add UI tests
1 parent 6a2a4b7 commit 96c4778

20 files changed

Lines changed: 884 additions & 174 deletions

File tree

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* The MIT License
3+
*
4+
* Copyright (c) 2026, Badge Plugin Authors
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
package com.jenkinsci.plugins.badge.detail;
25+
26+
import com.jenkinsci.plugins.badge.action.BadgeAction;
27+
import edu.umd.cs.findbugs.annotations.NonNull;
28+
import hudson.Extension;
29+
import hudson.ExtensionList;
30+
import hudson.model.Run;
31+
import java.util.List;
32+
import jenkins.model.details.Detail;
33+
import jenkins.model.details.DetailFactory;
34+
import jenkins.model.details.DetailGroup;
35+
36+
public class BadgeDetail extends Detail {
37+
38+
private final List<BadgeAction> actions;
39+
40+
public BadgeDetail(Run<?, ?> run) {
41+
super(run);
42+
actions = run.getActions(BadgeAction.class);
43+
}
44+
45+
@NonNull
46+
public List<BadgeAction> getActions() {
47+
return actions;
48+
}
49+
50+
@Override
51+
public DetailGroup getGroup() {
52+
return BadgeDetailGroup.get();
53+
}
54+
55+
@Extension(ordinal = -1)
56+
public static class BadgeDetailGroup extends DetailGroup {
57+
58+
public static BadgeDetailGroup get() {
59+
return ExtensionList.lookupSingleton(BadgeDetailGroup.class);
60+
}
61+
}
62+
63+
@Extension
64+
@SuppressWarnings("unused")
65+
public static class BadgeDetailFactory extends DetailFactory<Run> {
66+
67+
@Override
68+
public Class<Run> type() {
69+
return Run.class;
70+
}
71+
72+
@NonNull
73+
@Override
74+
public List<? extends Detail> createFor(@NonNull Run target) {
75+
return List.of(new BadgeDetail(target));
76+
}
77+
}
78+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* The MIT License
3+
*
4+
* Copyright (c) 2026, Badge Plugin Authors
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
package com.jenkinsci.plugins.badge.tab;
25+
26+
import com.jenkinsci.plugins.badge.action.BadgeSummaryAction;
27+
import edu.umd.cs.findbugs.annotations.NonNull;
28+
import hudson.Extension;
29+
import hudson.model.Run;
30+
import java.util.Collection;
31+
import java.util.Collections;
32+
import java.util.List;
33+
import jenkins.model.Tab;
34+
import jenkins.model.TransientActionFactory;
35+
36+
public class SummaryTab extends Tab {
37+
38+
private final List<BadgeSummaryAction> actions;
39+
40+
public SummaryTab(Run<?, ?> run) {
41+
super(run);
42+
actions = run.getActions().stream()
43+
.filter(BadgeSummaryAction.class::isInstance)
44+
.map(BadgeSummaryAction.class::cast)
45+
.toList();
46+
}
47+
48+
@NonNull
49+
public List<BadgeSummaryAction> getActions() {
50+
return actions;
51+
}
52+
53+
@Override
54+
public String getIconFileName() {
55+
return "symbol-list";
56+
}
57+
58+
@Override
59+
public String getDisplayName() {
60+
return "Summary";
61+
}
62+
63+
@Override
64+
public String getUrlName() {
65+
return "summary";
66+
}
67+
68+
@Extension
69+
@SuppressWarnings("unused")
70+
public static class SummaryTabFactory extends TransientActionFactory<Run> {
71+
72+
@Override
73+
public Class<Run> type() {
74+
return Run.class;
75+
}
76+
77+
@NonNull
78+
@Override
79+
public Collection<SummaryTab> createFor(@NonNull Run target) {
80+
return Collections.singleton(new SummaryTab(target));
81+
}
82+
}
83+
}

src/main/resources/com/jenkinsci/plugins/badge/action/BadgeAction/badge.jelly

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -25,46 +25,48 @@ THE SOFTWARE.
2525

2626
<?jelly escape-by-default='false'?>
2727
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout">
28-
<j:choose>
29-
<!-- icon -->
30-
<j:when test="${not empty it.icon}">
31-
<j:choose>
32-
<!-- icon with link -->
33-
<j:when test="${not empty it.link}">
34-
<span>
35-
<a href="${it.link}" target="${it.target}" class="${it.cssClass}" style="${it.style}">
36-
<l:icon class="icon-sm" style="width: 16px; height: 16px;" src="${it.icon}" alt="${it.text}" htmlTooltip="${it.text}"/>
37-
</a>
38-
</span>
39-
</j:when>
40-
<!-- icon without link -->
41-
<j:otherwise>
42-
<span id="icon-only-badge" class="${it.cssClass}" style="${it.style}" data-text="${it.text}">
43-
<l:icon class="icon-sm" style="width: 16px; height: 16px;" src="${it.icon}" alt="${it.text}" htmlTooltip="${it.text}"/>
44-
</span>
45-
</j:otherwise>
46-
</j:choose>
28+
<j:choose>
29+
<!-- icon -->
30+
<j:when test="${not empty it.icon}">
31+
<j:choose>
32+
<!-- icon with link -->
33+
<j:when test="${not empty it.link}">
34+
<span>
35+
<a href="${it.link}" target="${it.target}" class="${it.cssClass}" style="${it.style}">
36+
<l:icon class="icon-sm" style="width: 16px; height: 16px;" src="${it.icon}" alt="${it.text}"
37+
htmlTooltip="${it.text}"/>
38+
</a>
39+
</span>
4740
</j:when>
41+
<!-- icon without link -->
4842
<j:otherwise>
49-
<!-- text -->
50-
<j:if test="${not empty it.text}">
51-
<j:choose>
52-
<!-- text with link -->
53-
<j:when test="${not empty it.link}">
54-
<span>
55-
<a href="${it.link}" target="${it.target}" class="${it.cssClass}" style="${it.style}">
56-
${it.text}
57-
</a>
58-
</span>
59-
</j:when>
60-
<!-- text without link -->
61-
<j:otherwise>
62-
<span id="text-only-badge" class="${it.cssClass}" style="${it.style}" data-text="${it.text}">
63-
${it.text}
64-
</span>
65-
</j:otherwise>
66-
</j:choose>
67-
</j:if>
43+
<span id="icon-only-badge" class="${it.cssClass}" style="${it.style}" data-text="${it.text}">
44+
<l:icon class="icon-sm" style="width: 16px; height: 16px;" src="${it.icon}" alt="${it.text}"
45+
htmlTooltip="${it.text}"/>
46+
</span>
6847
</j:otherwise>
69-
</j:choose>
48+
</j:choose>
49+
</j:when>
50+
<j:otherwise>
51+
<!-- text -->
52+
<j:if test="${not empty it.text}">
53+
<j:choose>
54+
<!-- text with link -->
55+
<j:when test="${not empty it.link}">
56+
<span>
57+
<a href="${it.link}" target="${it.target}" class="${it.cssClass}" style="${it.style}">
58+
${it.text}
59+
</a>
60+
</span>
61+
</j:when>
62+
<!-- text without link -->
63+
<j:otherwise>
64+
<span id="text-only-badge" class="${it.cssClass}" style="${it.style}" data-text="${it.text}">
65+
${it.text}
66+
</span>
67+
</j:otherwise>
68+
</j:choose>
69+
</j:if>
70+
</j:otherwise>
71+
</j:choose>
7072
</j:jelly>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
The MIT License
4+
5+
Copyright (c) 2026, Badge Plugin Authors
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in
15+
all copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
THE SOFTWARE.
24+
-->
25+
26+
<?jelly escape-by-default='false'?>
27+
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout">
28+
<tr class="app-summary">
29+
<td>
30+
<j:choose>
31+
<!-- with icon -->
32+
<j:when test="${not empty it.icon}">
33+
<l:icon src="${it.icon}"/>
34+
</j:when>
35+
<!-- without icon -->
36+
<j:otherwise>
37+
<l:icon src="/images/16x16/empty.png"/>
38+
</j:otherwise>
39+
</j:choose>
40+
</td>
41+
<td style="vertical-align:middle">
42+
<j:choose>
43+
<!-- text with link -->
44+
<j:when test="${not empty it.link}">
45+
<a href="${it.link}" target="${it.target}" class="${it.cssClass}" style="${it.style}">
46+
<span>
47+
${it.text}
48+
</span>
49+
</a>
50+
</j:when>
51+
<!-- text without link -->
52+
<j:otherwise>
53+
<span class="${it.cssClass}" style="${it.style}">
54+
${it.text}
55+
</span>
56+
</j:otherwise>
57+
</j:choose>
58+
</td>
59+
</tr>
60+
</j:jelly>

src/main/resources/com/jenkinsci/plugins/badge/action/BadgeSummaryAction/summary.jelly

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -23,38 +23,11 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2323
THE SOFTWARE.
2424
-->
2525

26-
<?jelly escape-by-default='false'?>
27-
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout">
28-
<tr class="app-summary">
29-
<td>
30-
<j:choose>
31-
<!-- with icon -->
32-
<j:when test="${not empty it.icon}">
33-
<l:icon src="${it.icon}"/>
34-
</j:when>
35-
<!-- without icon -->
36-
<j:otherwise>
37-
<l:icon src="/images/16x16/empty.png"/>
38-
</j:otherwise>
39-
</j:choose>
40-
</td>
41-
<td style="vertical-align:middle">
42-
<j:choose>
43-
<!-- text with link -->
44-
<j:when test="${not empty it.link}">
45-
<a href="${it.link}" target="${it.target}" class="${it.cssClass}" style="${it.style}">
46-
<span>
47-
${it.text}
48-
</span>
49-
</a>
50-
</j:when>
51-
<!-- text without link -->
52-
<j:otherwise>
53-
<span class="${it.cssClass}" style="${it.style}">
54-
${it.text}
55-
</span>
56-
</j:otherwise>
57-
</j:choose>
58-
</td>
59-
</tr>
26+
<?jelly escape-by-default='true'?>
27+
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout">
28+
<l:userExperimentalFlag var="newBuildPage"
29+
flagClassName="jenkins.model.experimentalflags.NewBuildPageUserExperimentalFlag"/>
30+
<j:if test="${!newBuildPage}">
31+
<st:include page="summary-entry.jelly" optional="true"/>
32+
</j:if>
6033
</j:jelly>

src/main/resources/com/jenkinsci/plugins/badge/decorator/BadgePageDecorator/header.jelly

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@ THE SOFTWARE.
2525

2626
<?jelly escape-by-default='false'?>
2727
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler">
28-
<st:adjunct includes="com.jenkinsci.plugins.badge.assets"/>
29-
<st:adjunct includes="com.jenkinsci.plugins.badge.copy"/>
28+
<st:adjunct includes="com.jenkinsci.plugins.badge.assets"/>
29+
<st:adjunct includes="com.jenkinsci.plugins.badge.copy"/>
3030
</j:jelly>

0 commit comments

Comments
 (0)