From 2ee7a06ee634722573616421366427504d8c8733 Mon Sep 17 00:00:00 2001 From: Ulli Hafner Date: Fri, 21 May 2021 16:33:06 +0200 Subject: [PATCH 01/18] Upgrade trends and detail views to Bootstrap5. Additionally, trend charts are now configurable due to an upgrade to the echarts plugin. --- pom.xml | 21 +++++- src/main/java/hudson/tasks/junit/History.java | 45 ++++++++---- .../tasks/test/TestResultProjectAction.java | 69 +++++++++++-------- .../hudson/tasks/junit/History/index.jelly | 20 +++--- .../TestResultProjectAction/floatingBox.jelly | 6 +- src/main/webapp/history/history.css | 8 --- src/main/webapp/history/history.js | 25 +++++-- 7 files changed, 123 insertions(+), 71 deletions(-) delete mode 100644 src/main/webapp/history/history.css diff --git a/pom.xml b/pom.xml index eae3d5062..9bec96acd 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ 1.50 -SNAPSHOT jenkinsci/${project.artifactId}-plugin - 2.222.4 + 2.249.1 8 false @@ -48,6 +48,7 @@ io.jenkins.plugins echarts-api + 5.1.0-3-rc442.19377bcf1d00 io.jenkins.plugins @@ -75,7 +76,8 @@ io.jenkins.plugins - bootstrap4-api + bootstrap5-api + 5.0.1-1 org.jenkins-ci.plugins.workflow @@ -196,6 +198,21 @@ import pom + + io.jenkins.plugins + font-awesome-api + 5.15.3-2 + + + io.jenkins.plugins + jquery3-api + 3.6.0-1 + + + io.jenkins.plugins + plugin-util-api + 2.2.0 + diff --git a/src/main/java/hudson/tasks/junit/History.java b/src/main/java/hudson/tasks/junit/History.java index b9da9b36c..13fa6a295 100644 --- a/src/main/java/hudson/tasks/junit/History.java +++ b/src/main/java/hudson/tasks/junit/History.java @@ -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. @@ -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; } @@ -66,13 +69,20 @@ public boolean historyAvailable() { return testObject.getRun().getParent().getBuilds().size() > 1; } - @JavaScriptMethod + @Deprecated @SuppressWarnings("unused") // Called by jelly view public String getTestResultTrend() { - return JACKSON_FACADE.toJson(createTestResultTrend()); + return getTestResultTrend(EMPTY_CONFIGURATION); } - private LinesChartModel createTestResultTrend() { + @JavaScriptMethod + @SuppressWarnings("unused") // Called by jelly view + public String getTestResultTrend(final String configuration) { + return JACKSON_FACADE.toJson(createTestResultTrend(ChartModelConfiguration.fromJson(configuration))); + } + + private LinesChartModel createTestResultTrend( + final ChartModelConfiguration chartModelConfiguration) { if (testObject instanceof hudson.tasks.junit.TestResult) { TestResultImpl pluggableStorage = ((hudson.tasks.junit.TestResult) testObject).getPluggableStorage(); if (pluggableStorage != null) { @@ -80,16 +90,23 @@ private LinesChartModel createTestResultTrend() { } } - return new TestResultTrendChart().createFromTestObject(createBuildHistory(testObject), new ChartModelConfiguration()); + return new TestResultTrendChart().createFromTestObject(createBuildHistory(testObject), chartModelConfiguration); } - @JavaScriptMethod + @Deprecated @SuppressWarnings("unused") // Called by jelly view public String getTestDurationTrend() { - return JACKSON_FACADE.toJson(createTestDurationResultTrend()); + return getTestDurationTrend(EMPTY_CONFIGURATION); + } + + @JavaScriptMethod + @SuppressWarnings("unused") // Called by jelly view + 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) { @@ -97,15 +114,15 @@ private LinesChartModel createTestDurationResultTrend() { } } - 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); diff --git a/src/main/java/hudson/tasks/test/TestResultProjectAction.java b/src/main/java/hudson/tasks/test/TestResultProjectAction.java index 0d1f2736a..6af0c6065 100644 --- a/src/main/java/hudson/tasks/test/TestResultProjectAction.java +++ b/src/main/java/hudson/tasks/test/TestResultProjectAction.java @@ -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 @@ -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}, @@ -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 @@ -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); } @@ -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(); @@ -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) { @@ -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); @@ -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); @@ -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 @@ -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 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); @@ -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; diff --git a/src/main/resources/hudson/tasks/junit/History/index.jelly b/src/main/resources/hudson/tasks/junit/History/index.jelly index 5c1d915a2..235810f08 100644 --- a/src/main/resources/hudson/tasks/junit/History/index.jelly +++ b/src/main/resources/hudson/tasks/junit/History/index.jelly @@ -24,20 +24,22 @@ THE SOFTWARE. - + - + + + -