Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade trends and detail views to Bootstrap 5 #272

Merged
merged 20 commits into from
May 2, 2022
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<revision>1.50</revision>
<changelist>-SNAPSHOT</changelist>
<gitHubRepo>jenkinsci/${project.artifactId}-plugin</gitHubRepo>
<jenkins.version>2.222.4</jenkins.version>
<jenkins.version>2.249.1</jenkins.version>
<java.level>8</java.level>
<no-test-jar>false</no-test-jar>
</properties>
Expand Down Expand Up @@ -48,6 +48,7 @@
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>echarts-api</artifactId>
<version>5.1.2-2</version>
</dependency>
<dependency>
<groupId>io.jenkins.plugins</groupId>
Expand Down Expand Up @@ -75,7 +76,8 @@
</dependency>
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>bootstrap4-api</artifactId>
<artifactId>bootstrap5-api</artifactId>
<version>5.0.1-2</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
Expand All @@ -98,6 +100,12 @@
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>matrix-project</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>junit</artifactId>
<groupId>org.jenkins-ci.plugins</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
Expand Down Expand Up @@ -196,6 +204,26 @@
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>font-awesome-api</artifactId>
<version>5.15.3-3</version>
</dependency>
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>jquery3-api</artifactId>
<version>3.6.0-1</version>
</dependency>
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>plugin-util-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>jackson2-api</artifactId>
<version>2.12.3</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
33 changes: 19 additions & 14 deletions src/main/java/hudson/tasks/junit/History.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@
import edu.hm.hafner.echarts.ChartModelConfiguration;
import edu.hm.hafner.echarts.JacksonFacade;
import edu.hm.hafner.echarts.LinesChartModel;

import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.bind.JavaScriptMethod;
import hudson.tasks.test.TestObject;
import hudson.tasks.test.TestObjectIterable;
import hudson.tasks.test.TestResultDurationChart;
import hudson.tasks.test.TestResultTrendChart;

import io.jenkins.plugins.junit.storage.TestResultImpl;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.bind.JavaScriptMethod;

/**
* History of {@link hudson.tasks.test.TestObject} over time.
Expand All @@ -43,9 +45,10 @@
@Restricted(NoExternalUse.class)
public class History {
private static final JacksonFacade JACKSON_FACADE = new JacksonFacade();
private static final String EMPTY_CONFIGURATION = "{}";
private final TestObject testObject;

public History(TestObject testObject) {
public History(final TestObject testObject) {
this.testObject = testObject;
}

Expand All @@ -68,44 +71,46 @@ public boolean historyAvailable() {

@JavaScriptMethod
@SuppressWarnings("unused") // Called by jelly view
public String getTestResultTrend() {
return JACKSON_FACADE.toJson(createTestResultTrend());
public String getTestResultTrend(final String configuration) {
return JACKSON_FACADE.toJson(createTestResultTrend(ChartModelConfiguration.fromJson(configuration)));
}

private LinesChartModel createTestResultTrend() {
private LinesChartModel createTestResultTrend(
final ChartModelConfiguration chartModelConfiguration) {
if (testObject instanceof hudson.tasks.junit.TestResult) {
TestResultImpl pluggableStorage = ((hudson.tasks.junit.TestResult) testObject).getPluggableStorage();
if (pluggableStorage != null) {
return new TestResultTrendChart().create(pluggableStorage.getTrendTestResultSummary());
}
}

return new TestResultTrendChart().createFromTestObject(createBuildHistory(testObject), new ChartModelConfiguration());
return new TestResultTrendChart().createFromTestObject(createBuildHistory(testObject), chartModelConfiguration);
}

@JavaScriptMethod
@SuppressWarnings("unused") // Called by jelly view
public String getTestDurationTrend() {
return JACKSON_FACADE.toJson(createTestDurationResultTrend());
public String getTestDurationTrend(final String configuration) {
return JACKSON_FACADE.toJson(createTestDurationResultTrend(ChartModelConfiguration.fromJson(configuration)));
}

private LinesChartModel createTestDurationResultTrend() {
private LinesChartModel createTestDurationResultTrend(
final ChartModelConfiguration chartModelConfiguration) {
if (testObject instanceof hudson.tasks.junit.TestResult) {
TestResultImpl pluggableStorage = ((hudson.tasks.junit.TestResult) testObject).getPluggableStorage();
if (pluggableStorage != null) {
return new TestResultDurationChart().create(pluggableStorage.getTestDurationResultSummary());
}
}

return new TestResultDurationChart().create(createBuildHistory(testObject), new ChartModelConfiguration());
return new TestResultDurationChart().create(createBuildHistory(testObject), chartModelConfiguration);
}

private TestObjectIterable createBuildHistory(TestObject testObject) {
private TestObjectIterable createBuildHistory(final TestObject testObject) {
return new TestObjectIterable(testObject);
}

@SuppressWarnings("unused") // Called by jelly view
public static int asInt(String s, int defaultValue) {
public static int asInt(final String s, final int defaultValue) {
if (s == null) return defaultValue;
try {
return Integer.parseInt(s);
Expand Down
25 changes: 10 additions & 15 deletions src/main/java/hudson/tasks/test/TestResultDurationChart.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
package hudson.tasks.test;

import java.util.List;

import edu.hm.hafner.echarts.ChartModelConfiguration;
import edu.hm.hafner.echarts.LineSeries;
import edu.hm.hafner.echarts.LinesChartModel;
import edu.hm.hafner.echarts.LinesDataSet;
import edu.hm.hafner.echarts.Palette;

import hudson.tasks.junit.TestDurationResultSummary;
import hudson.tasks.junit.TrendTestResultSummary;
import java.util.List;

import static hudson.tasks.test.TestDurationTrendSeriesBuilder.SECONDS;
import static hudson.tasks.test.TestResultTrendSeriesBuilder.FAILED_KEY;
import static hudson.tasks.test.TestResultTrendSeriesBuilder.PASSED_KEY;
import static hudson.tasks.test.TestResultTrendSeriesBuilder.SKIPPED_KEY;
import static hudson.tasks.test.TestDurationTrendSeriesBuilder.*;

public class TestResultDurationChart {
public LinesChartModel create(List<TestDurationResultSummary> results) {

public LinesChartModel create(final List<TestDurationResultSummary> results) {
LinesDataSet dataset = new LinesDataSet();
results.forEach(result -> dataset.add(result.getDisplayName(), result.toMap(), result.getBuildNumber()));

return getLinesChartModel(dataset);
}

Expand All @@ -31,16 +29,13 @@ public LinesChartModel create(final Iterable results,
return getLinesChartModel(dataSet);
}

private LinesChartModel getLinesChartModel(LinesDataSet dataSet) {
LinesChartModel model = new LinesChartModel();
model.setDomainAxisLabels(dataSet.getDomainAxisLabels());
model.setBuildNumbers(dataSet.getBuildNumbers());

private LinesChartModel getLinesChartModel(final LinesDataSet dataSet) {
LinesChartModel model = new LinesChartModel(dataSet);
LineSeries duration = new LineSeries(SECONDS, Palette.GREEN.getNormal(),
LineSeries.StackedMode.STACKED, LineSeries.FilledMode.FILLED);
duration.addAll(dataSet.getSeries(SECONDS));
model.addSeries(duration);

return model;
}
}
69 changes: 41 additions & 28 deletions src/main/java/hudson/tasks/test/TestResultProjectAction.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
/*
* The MIT License
*
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Expand All @@ -23,29 +23,32 @@
*/
package hudson.tasks.test;

import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

import edu.hm.hafner.echarts.ChartModelConfiguration;
import edu.hm.hafner.echarts.JacksonFacade;
import edu.hm.hafner.echarts.LinesChartModel;
import edu.umd.cs.findbugs.annotations.CheckForNull;

import org.kohsuke.stapler.Ancestor;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.bind.JavaScriptMethod;
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.model.Job;
import hudson.model.Run;
import hudson.tasks.junit.JUnitResultArchiver;

import io.jenkins.plugins.echarts.AsyncConfigurableTrendChart;
import io.jenkins.plugins.echarts.AsyncTrendChart;
import io.jenkins.plugins.junit.storage.FileJunitTestResultStorage;
import io.jenkins.plugins.junit.storage.TestResultImpl;
import io.jenkins.plugins.junit.storage.JunitTestResultStorage;
import io.jenkins.plugins.echarts.AsyncTrendChart;
import org.kohsuke.stapler.Ancestor;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import org.kohsuke.stapler.bind.JavaScriptMethod;
import io.jenkins.plugins.junit.storage.TestResultImpl;

/**
* Project action object from test reporter, such as {@link JUnitResultArchiver},
Expand All @@ -56,7 +59,7 @@
*
* @author Kohsuke Kawaguchi
*/
public class TestResultProjectAction implements Action, AsyncTrendChart {
public class TestResultProjectAction implements Action, AsyncTrendChart, AsyncConfigurableTrendChart {
/**
* Project that owns this action.
* @since 1.2-beta-1
Expand All @@ -69,13 +72,13 @@ public class TestResultProjectAction implements Action, AsyncTrendChart {
/**
* @since 1.2-beta-1
*/
public TestResultProjectAction(Job<?,?> job) {
public TestResultProjectAction(final Job<?,?> job) {
this.job = job;
project = job instanceof AbstractProject ? (AbstractProject) job : null;
}

@Deprecated
public TestResultProjectAction(AbstractProject<?,?> project) {
public TestResultProjectAction(final AbstractProject<?,?> project) {
this((Job) project);
}

Expand Down Expand Up @@ -111,7 +114,12 @@ public AbstractTestResultAction getLastTestResultAction() {
return null;
}

@Deprecated
protected LinesChartModel createChartModel() {
return createChartModel(new ChartModelConfiguration());
}

private LinesChartModel createChartModel(final ChartModelConfiguration configuration) {
Run<?, ?> lastCompletedBuild = job.getLastCompletedBuild();

JunitTestResultStorage storage = JunitTestResultStorage.find();
Expand All @@ -124,11 +132,11 @@ protected LinesChartModel createChartModel() {
if (buildHistory == null) {
return new LinesChartModel();
}
return new TestResultTrendChart().create(buildHistory, new ChartModelConfiguration());
return new TestResultTrendChart().create(buildHistory, configuration);
}

@CheckForNull
private TestResultActionIterable createBuildHistory(Run<?, ?> lastCompletedBuild) {
private TestResultActionIterable createBuildHistory(final Run<?, ?> lastCompletedBuild) {
// some plugins that depend on junit seem to attach the action even though there's no run
// e.g. xUnit and cucumber
if (lastCompletedBuild == null) {
Expand All @@ -150,11 +158,11 @@ private TestResultActionIterable createBuildHistory(Run<?, ?> lastCompletedBuild

/**
* Display the test result trend.
*
*
* @deprecated Replaced by echarts in TODO
*/
@Deprecated
public void doTrend( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
public void doTrend( final StaplerRequest req, final StaplerResponse rsp ) throws IOException, ServletException {
AbstractTestResultAction a = getLastTestResultAction();
if(a!=null)
a.doGraph(req,rsp);
Expand All @@ -168,7 +176,7 @@ public void doTrend( StaplerRequest req, StaplerResponse rsp ) throws IOExceptio
* @deprecated Replaced by echarts in TODO
*/
@Deprecated
public void doTrendMap( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
public void doTrendMap( final StaplerRequest req, final StaplerResponse rsp ) throws IOException, ServletException {
AbstractTestResultAction a = getLastTestResultAction();
if(a!=null)
a.doGraphMap(req,rsp);
Expand All @@ -179,7 +187,7 @@ public void doTrendMap( StaplerRequest req, StaplerResponse rsp ) throws IOExcep
/**
* Changes the test result report display mode.
*/
public void doFlipTrend( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
public void doFlipTrend( final StaplerRequest req, final StaplerResponse rsp ) throws IOException, ServletException {
boolean failureOnly = false;

// check the current preference value
Expand All @@ -197,7 +205,7 @@ public void doFlipTrend( StaplerRequest req, StaplerResponse rsp ) throws IOExce
// set the updated value
Cookie cookie = new Cookie(FAILURE_ONLY_COOKIE,String.valueOf(failureOnly));
List<Ancestor> anc = req.getAncestors();
Ancestor a = (Ancestor) anc.get(anc.size()-2);
Ancestor a = anc.get(anc.size()-2);
cookie.setPath(a.getUrl()); // just for this project
cookie.setMaxAge(60*60*24*365); // 1 year
rsp.addCookie(cookie);
Expand All @@ -208,12 +216,17 @@ public void doFlipTrend( StaplerRequest req, StaplerResponse rsp ) throws IOExce

private static final String FAILURE_ONLY_COOKIE = "TestResultAction_failureOnly";

@JavaScriptMethod
@Override
@Override @Deprecated
public String getBuildTrendModel() {
return new JacksonFacade().toJson(createChartModel());
}

@JavaScriptMethod
@Override
public String getConfigurableBuildTrendModel(final String configuration) {
return new JacksonFacade().toJson(createChartModel(ChartModelConfiguration.fromJson(configuration)));
}

@Override
public boolean isTrendVisible() {
return true;
Expand Down
Loading