Skip to content

Commit feaf21e

Browse files
janfaraciktimja
andauthored
Adjust for experimental Run UI (#755)
* Adjust for experimental Run UI * Fix card * Update widget.jelly * Update pom.xml * Fix detail bar spacing * Refine content * Improve card + i18n * Update Widget.java * Add run sub page for individual tests * Update history to align with run subpage * I18n last string * Fix sidepanel link --------- Co-authored-by: Tim Jacomb <[email protected]>
1 parent 29ce3e5 commit feaf21e

File tree

15 files changed

+402
-270
lines changed

15 files changed

+402
-270
lines changed

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>org.jenkins-ci.plugins</groupId>
66
<artifactId>plugin</artifactId>
7-
<version>5.27</version>
7+
<version>5.26</version>
88
<relativePath />
99
</parent>
1010

@@ -32,8 +32,8 @@
3232
<properties>
3333
<changelist>999999-SNAPSHOT</changelist>
3434
<gitHubRepo>jenkinsci/${project.artifactId}-plugin</gitHubRepo>
35-
<jenkins.baseline>2.504</jenkins.baseline>
36-
<jenkins.version>${jenkins.baseline}.3</jenkins.version>
35+
<jenkins.baseline>2.516</jenkins.baseline>
36+
<jenkins.version>2.533</jenkins.version>
3737
<no-test-jar>false</no-test-jar>
3838
<spotless.check.skip>false</spotless.check.skip>
3939
<ban-junit4-imports.skip>false</ban-junit4-imports.skip>

src/main/java/hudson/tasks/junit/CaseResult.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,9 +1099,9 @@ public boolean isRegression() {
10991099
@Restricted(NoExternalUse.class)
11001100
public String getIconFileName() {
11011101
return switch (getStatus()) {
1102-
case PASSED -> "symbol-checkmark-outline plugin-ionicons-api";
1103-
case SKIPPED -> "symbol-play-skip-forward-outline plugin-ionicons-api";
1104-
default -> "symbol-close-outline plugin-ionicons-api";
1102+
case PASSED -> "symbol-status-blue";
1103+
case SKIPPED -> "symbol-status-skipped plugin-junit";
1104+
default -> "symbol-status-red";
11051105
};
11061106
}
11071107
}

src/main/java/hudson/tasks/junit/TestResultAction.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,10 @@ public Object readResolve() {
415415
return this;
416416
}
417417

418+
public Widget getWidget() {
419+
return new Widget(getResult());
420+
}
421+
418422
private static final Logger logger = Logger.getLogger(TestResultAction.class.getName());
419423

420424
static final XStream XSTREAM = new XStream2();
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package hudson.tasks.junit;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
public class Widget {
7+
8+
private final String symbol;
9+
private final String symbolClass;
10+
private final List<String> lines = new ArrayList<>();
11+
12+
public Widget(TestResult result) {
13+
int failCount = result.getFailCount();
14+
boolean isFailed = failCount > 0;
15+
int totalCount = result.getTotalCount();
16+
17+
this.symbol = isFailed
18+
? "symbol-close-circle-outline plugin-ionicons-api"
19+
: "symbol-checkmark-done-outline plugin-ionicons-api";
20+
this.symbolClass = isFailed ? "jenkins-!-error-color" : "jenkins-!-success-color";
21+
22+
List<String> counts = new ArrayList<>();
23+
24+
if (isFailed) {
25+
lines.add(Messages.Widget_Failed(failCount));
26+
counts.add(Messages.Widget_Passed(result.getPassCount()));
27+
28+
long regressions = result.getSuites().stream()
29+
.flatMap(e -> e.getCases().stream())
30+
.filter(e -> {
31+
var previousResult = e.getPreviousResult();
32+
if (previousResult == null) {
33+
return false;
34+
}
35+
return e.isPassed();
36+
})
37+
.count();
38+
39+
if (regressions > 0) {
40+
lines.add(Messages.Widget_Regression(regressions));
41+
}
42+
43+
} else {
44+
lines.add(Messages.Widget_AllTestsPassing());
45+
}
46+
47+
if (result.getSkipCount() > 0) {
48+
counts.add(Messages.Widget_Skipped(result.getSkipCount()));
49+
}
50+
51+
counts.add(Messages.Widget_Total(totalCount));
52+
53+
lines.add(String.join(", ", counts));
54+
55+
lines.add(Messages.Widget_Took(result.getDurationString()));
56+
}
57+
58+
public String getSymbol() {
59+
return symbol;
60+
}
61+
62+
public String getSymbolClass() {
63+
return symbolClass;
64+
}
65+
66+
public List<String> getLines() {
67+
return lines;
68+
}
69+
}

src/main/java/hudson/tasks/test/AbstractTestResultAction.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@
5151
import java.util.concurrent.ConcurrentHashMap;
5252
import java.util.logging.Level;
5353
import java.util.logging.Logger;
54+
import jenkins.management.Badge;
5455
import jenkins.model.RunAction2;
56+
import jenkins.model.Tab;
5557
import jenkins.model.lazy.LazyBuildMixIn;
5658
import org.jfree.chart.ChartFactory;
5759
import org.jfree.chart.JFreeChart;
@@ -81,7 +83,7 @@
8183
* @author Kohsuke Kawaguchi
8284
*/
8385
@ExportedBean
84-
public abstract class AbstractTestResultAction<T extends AbstractTestResultAction>
86+
public abstract class AbstractTestResultAction<T extends AbstractTestResultAction> extends Tab
8587
implements HealthReportingAction, RunAction2 {
8688

8789
private static final Logger LOGGER = Logger.getLogger(AbstractTestResultAction.class.getName());
@@ -99,14 +101,17 @@ public abstract class AbstractTestResultAction<T extends AbstractTestResultActio
99101
private Map<String, String> descriptions = new ConcurrentHashMap<>();
100102

101103
/** @since 1.545 */
102-
protected AbstractTestResultAction() {}
104+
protected AbstractTestResultAction() {
105+
super(null);
106+
}
103107

104108
/**
105109
* @deprecated Use the default constructor and just call {@link Run#addAction} to associate the build with the action.
106110
* @since 1.2-beta-1
107111
*/
108112
@Deprecated
109113
protected AbstractTestResultAction(Run owner) {
114+
super(owner);
110115
onAttached(owner);
111116
}
112117

@@ -117,12 +122,14 @@ protected AbstractTestResultAction(AbstractBuild owner) {
117122

118123
@Override
119124
public void onAttached(Run<?, ?> r) {
125+
this.object = r;
120126
this.run = r;
121127
this.owner = r instanceof AbstractBuild ? (AbstractBuild<?, ?>) r : null;
122128
}
123129

124130
@Override
125131
public void onLoad(Run<?, ?> r) {
132+
this.object = r;
126133
this.run = r;
127134
this.owner = r instanceof AbstractBuild ? (AbstractBuild<?, ?>) r : null;
128135
}
@@ -180,6 +187,18 @@ public String getIconFileName() {
180187
return "symbol-flask-outline plugin-ionicons-api";
181188
}
182189

190+
@Override
191+
public Badge getBadge() {
192+
if (getFailCount() == 0) {
193+
return null;
194+
}
195+
196+
return new Badge(
197+
String.valueOf(getFailCount()),
198+
Messages.AbstractTestResultAction_Badge(getFailCount()),
199+
Badge.Severity.DANGER);
200+
}
201+
183202
@Override
184203
public HealthReport getBuildHealth() {
185204
final double scaleFactor = getHealthScaleFactor();

src/main/resources/hudson/tasks/junit/CaseResult/index.jelly

Lines changed: 80 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -23,89 +23,93 @@ THE SOFTWARE.
2323
-->
2424

2525
<?jelly escape-by-default='true'?>
26-
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:test="/lib/hudson/test">
27-
<l:layout title="${it.displayName} - ${it.run}" type="one-column" xmlns:p="/prism">
28-
<l:main-panel>
29-
<p:prism configuration="${it.prismConfiguration}" />
30-
<link rel="stylesheet" href="${resURL}/plugin/junit/styles.css" defer="true" />
31-
32-
<j:set var="st" value="${it.status}" />
33-
34-
<div class="jenkins-app-bar">
35-
<div class="jenkins-app-bar__content">
36-
<h1>
37-
<span class="jenkins-!-margin-right-2">
38-
${it.displayName}
39-
</span>
40-
<st:nbsp />
41-
<span class="jenkins-!-text-color-secondary" style="font-family: var(--font-family-mono)">
42-
${it.className}
43-
</span>
44-
</h1>
45-
</div>
46-
<div class="jenkins-app-bar__controls">
47-
<a href="history" class="jenkins-button">
48-
<l:icon src="symbol-bar-chart-outline plugin-ionicons-api" />
49-
${%History}
50-
</a>
51-
</div>
26+
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:test="/lib/hudson/test" xmlns:p="/prism">
27+
<j:set var="test" value="${it}" />
28+
<j:set var="it" value="${it.parentAction}" />
29+
30+
<l:run-subpage>
31+
<j:set var="it" value="${test}" />
32+
<p:prism configuration="${it.prismConfiguration}" />
33+
<link rel="stylesheet" href="${resURL}/plugin/junit/styles.css" defer="true" />
34+
35+
<j:set var="st" value="${it.status}" />
36+
37+
<div class="jenkins-app-bar jenkins-app-bar--with-icon">
38+
<div class="jenkins-app-bar__content">
39+
<l:icon src="${it.iconFileName}" />
40+
<h1>
41+
<span class="jenkins-!-margin-right-2">
42+
${it.displayName}
43+
</span>
44+
<st:nbsp />
45+
<span class="jenkins-!-text-color-secondary" style="font-family: var(--font-family-mono)">
46+
${it.className}
47+
</span>
48+
</h1>
5249
</div>
53-
<div class="jp-details">
54-
<div class="${it.status.cssClass}">
55-
<l:icon src="${it.iconFileName}" />
56-
${it.status.message}
57-
</div>
50+
<div class="jenkins-app-bar__controls">
51+
<div class="jenkins-details">
52+
<test:condition-tag test="${it}" />
53+
54+
<j:if test="${!it.passed}">
55+
<a href="${rootURL}/${it.run.url}" class="jenkins-details__item">
56+
<div class="jenkins-details__item__icon">
57+
<j:choose>
58+
<j:when test="${it.skipped}">
59+
<l:icon src="symbol-play-skip-forward-circle-outline plugin-ionicons-api" />
60+
</j:when>
61+
<j:otherwise>
62+
<l:icon src="symbol-close-circle-outline plugin-ionicons-api" />
63+
</j:otherwise>
64+
</j:choose>
65+
</div>
66+
67+
<j:choose>
68+
<j:when test="${it.skipped}">
69+
${%skippedFor(it.age)}
70+
</j:when>
71+
<j:otherwise>
72+
${%failingFor(it.age)}
73+
</j:otherwise>
74+
</j:choose>
75+
${%since.before}
76+
#${it.failedSince}
77+
${%since.after}
78+
</a>
79+
</j:if>
5880

59-
<test:condition-tag test="${it}" />
60-
61-
<j:if test="${!it.passed}">
62-
<a href="${rootURL}/${it.run.url}" class="jp-pill jp-pill--tertiary">
63-
<j:choose>
64-
<j:when test="${it.skipped}">
65-
<l:icon src="symbol-play-skip-forward-circle-outline plugin-ionicons-api" />
66-
</j:when>
67-
<j:otherwise>
68-
<l:icon src="symbol-close-circle-outline plugin-ionicons-api" />
69-
</j:otherwise>
70-
</j:choose>
71-
72-
<j:choose>
73-
<j:when test="${it.skipped}">
74-
${%skippedFor(it.age)}
75-
</j:when>
76-
<j:otherwise>
77-
${%failingFor(it.age)}
78-
</j:otherwise>
79-
</j:choose>
80-
${%since.before}
81-
#${it.failedSince}
82-
${%since.after}
83-
</a>
84-
</j:if>
81+
<div class="jenkins-details__item">
82+
<div class="jenkins-details__item__icon">
83+
<l:icon src="symbol-timer-outline plugin-ionicons-api" />
84+
</div>
85+
${%took(it.durationString)}
8586

86-
<div class="jp-pill jp-pill--tertiary">
87-
<l:icon src="symbol-timer-outline plugin-ionicons-api" />
88-
${%took(it.durationString)}
87+
<j:if test="${it.suiteResult != null &amp;&amp; it.className != it.suiteResult.name}">
88+
(from <st:out value="${it.suiteResult.name}"/>)
89+
</j:if>
90+
</div>
8991

90-
<j:if test="${it.suiteResult != null &amp;&amp; it.className != it.suiteResult.name}">
91-
(from <st:out value="${it.suiteResult.name}"/>)
92-
</j:if>
93-
</div>
92+
<a tooltip="${%History}"
93+
href="history"
94+
class="jenkins-button jenkins-details__button">
95+
<l:icon src="symbol-bar-chart-outline plugin-ionicons-api" />
96+
</a>
9497

95-
<test:edit-description-button permission="${it.run.UPDATE}" />
98+
<t:editDescriptionButton permission="${it.run.UPDATE}" compact="true" />
99+
</div>
96100
</div>
101+
</div>
97102

98-
<t:editableDescription permission="${it.run.UPDATE}" hideButton="true" />
103+
<t:editableDescription permission="${it.run.UPDATE}" hideButton="true" />
99104

100-
<table style="margin-top: 1em; margin-left:0em;">
101-
<j:forEach var="action" items="${it.testActions}">
102-
<st:include page="summary.jelly" from="${action}" optional="true" it="${action}" />
103-
</j:forEach>
104-
</table>
105+
<table>
106+
<j:forEach var="action" items="${it.testActions}">
107+
<st:include page="summary.jelly" from="${action}" optional="true" it="${action}" />
108+
</j:forEach>
109+
</table>
105110

106-
<div class="jp-code-list">
107-
<st:include page="test-output.jelly" />
108-
</div>
109-
</l:main-panel>
110-
</l:layout>
111+
<div class="jp-code-list">
112+
<st:include page="test-output.jelly" />
113+
</div>
114+
</l:run-subpage>
111115
</j:jelly>

0 commit comments

Comments
 (0)