From 481bd3537b97490d9e8bb4c897c543de03bbb945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tommy=20Tynj=C3=A4?= Date: Thu, 22 Nov 2018 07:24:16 +0100 Subject: [PATCH] JENKINS-53868 Ability to show date and time as absolute values in pipeline views * Added as a configurable option * Refactored: Moved common functionality to core package --- .../se/diabol/jenkins/core/PipelineView.java | 81 +++++++++++++++++++ .../TimestampFormat.java} | 19 +++-- .../pipeline/DeliveryPipelineView.java | 20 ++++- .../diabol/jenkins/pipeline/PipelineApi.java | 6 +- .../jenkins/pipeline/domain/Pipeline.java | 6 +- .../pipeline/domain/status/SimpleStatus.java | 4 +- .../jenkins/pipeline/util/PipelineUtils.java | 8 -- .../workflow/WorkflowPipelineView.java | 23 +++++- .../jenkins/workflow/model/Pipeline.java | 4 +- .../configure-entries.jelly | 4 + .../help-showAbsoluteDateTime.html | 3 + .../configure-entries.jelly | 3 + .../help-showAbsoluteDateTime.html | 3 + src/main/webapp/pipe.js | 17 ++-- .../pipeline/DeliveryPipelineViewTest.java | 1 + .../pipeline/util/PipelineUtilsTest.java | 1 + 16 files changed, 164 insertions(+), 39 deletions(-) create mode 100644 src/main/java/se/diabol/jenkins/core/PipelineView.java rename src/main/java/se/diabol/jenkins/{pipeline/PipelineView.java => core/TimestampFormat.java} (59%) create mode 100644 src/main/resources/se/diabol/jenkins/pipeline/DeliveryPipelineView/help-showAbsoluteDateTime.html create mode 100644 src/main/resources/se/diabol/jenkins/workflow/WorkflowPipelineView/help-showAbsoluteDateTime.html diff --git a/src/main/java/se/diabol/jenkins/core/PipelineView.java b/src/main/java/se/diabol/jenkins/core/PipelineView.java new file mode 100644 index 000000000..423112aa5 --- /dev/null +++ b/src/main/java/se/diabol/jenkins/core/PipelineView.java @@ -0,0 +1,81 @@ +/* +This file is part of Delivery Pipeline Plugin. + +Delivery Pipeline Plugin is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Delivery Pipeline Plugin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Delivery Pipeline Plugin. +If not, see . +*/ +package se.diabol.jenkins.core; + +import org.acegisecurity.AuthenticationException; +import se.diabol.jenkins.pipeline.trigger.TriggerException; + +import java.util.List; + +/** + * Interface defining common methods for delivery pipeline views. + * Note that Jenkins does NOT support the following: + * + */ +public interface PipelineView { + + void triggerManual(String projectName, String upstreamName, String buildId) + throws TriggerException, AuthenticationException; + + void triggerRebuild(String projectName, String buildId); + + void abortBuild(String projectName, String buildId) throws TriggerException, AuthenticationException; + + /** + * Whether to allow a new pipeline to be started from the pipeline view. + * Expected to be annotated with @Exported for consumption from the view page. + * + * @return whether to allow a new pipeline to be started from the pipeline view. + */ + boolean isAllowPipelineStart(); + + /** + * Whether to allow running pipelines to be aborted from the pipeline view. + * Expected to be annotated with @Exported for consumption from the view page. + * + * @return whether to allow pipelines to be aborted from the pipeline view. + */ + boolean isAllowAbort(); + + /** + * A date time string representing when the pipeline view was last updated. + * Expected to be annotated with @Exported for consumption from the view page. + * + * @return a string representation on when the pipeline view was last updated. + */ + String getLastUpdated(); + + /** + * Exposes any error that is currently associated with the pipeline view. + * + * @return the error currently associated with this pipeline view. + */ + String getError(); + + /** + * Resolve the pipelines associated with this view. + * Expected to be annotated with @Exported for consumption from the view page. + * + * @return a list of components associated with this pipeline view. + */ + List getPipelines(); +} diff --git a/src/main/java/se/diabol/jenkins/pipeline/PipelineView.java b/src/main/java/se/diabol/jenkins/core/TimestampFormat.java similarity index 59% rename from src/main/java/se/diabol/jenkins/pipeline/PipelineView.java rename to src/main/java/se/diabol/jenkins/core/TimestampFormat.java index 434f12563..38c5be550 100644 --- a/src/main/java/se/diabol/jenkins/pipeline/PipelineView.java +++ b/src/main/java/se/diabol/jenkins/core/TimestampFormat.java @@ -15,17 +15,20 @@ along with Delivery Pipeline Plugin. If not, see . */ -package se.diabol.jenkins.pipeline; +package se.diabol.jenkins.core; -import org.acegisecurity.AuthenticationException; -import se.diabol.jenkins.pipeline.trigger.TriggerException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; -public interface PipelineView { +public final class TimestampFormat { - void triggerManual(String projectName, String upstreamName, String buildId) - throws TriggerException, AuthenticationException; + private static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); - void triggerRebuild(String projectName, String buildId); + private TimestampFormat() { + } - void abortBuild(String projectName, String buildId) throws TriggerException, AuthenticationException; + public static String formatTimestamp(long timestamp) { + return DATE_TIME_FORMAT.format(new Date(timestamp)); + } } diff --git a/src/main/java/se/diabol/jenkins/pipeline/DeliveryPipelineView.java b/src/main/java/se/diabol/jenkins/pipeline/DeliveryPipelineView.java index 93400ed8f..b6a65e27c 100644 --- a/src/main/java/se/diabol/jenkins/pipeline/DeliveryPipelineView.java +++ b/src/main/java/se/diabol/jenkins/pipeline/DeliveryPipelineView.java @@ -48,6 +48,8 @@ import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.bind.JavaScriptMethod; import org.kohsuke.stapler.export.Exported; +import se.diabol.jenkins.core.PipelineView; +import se.diabol.jenkins.core.TimestampFormat; import se.diabol.jenkins.pipeline.domain.Component; import se.diabol.jenkins.pipeline.domain.Pipeline; import se.diabol.jenkins.pipeline.domain.PipelineException; @@ -58,7 +60,6 @@ import se.diabol.jenkins.pipeline.trigger.TriggerException; import se.diabol.jenkins.pipeline.util.FullScreen; import se.diabol.jenkins.pipeline.util.JenkinsUtil; -import se.diabol.jenkins.pipeline.util.PipelineUtils; import se.diabol.jenkins.pipeline.util.ProjectUtil; import java.io.IOException; @@ -110,6 +111,7 @@ public class DeliveryPipelineView extends View implements PipelineView { private boolean showStaticAnalysisResults = false; private boolean linkRelative = false; private boolean pagingEnabled = false; + private boolean showAbsoluteDateTime = false; private boolean showAggregatedChanges = false; private String aggregatedChangesGroupingPattern = null; private String theme = DEFAULT_THEME; @@ -204,6 +206,7 @@ public void setShowAggregatedPipeline(boolean showAggregatedPipeline) { } @Exported + @Override public boolean isAllowPipelineStart() { return allowPipelineStart; } @@ -213,6 +216,7 @@ public void setAllowPipelineStart(boolean allowPipelineStart) { } @Exported + @Override public boolean isAllowAbort() { return allowAbort; } @@ -328,11 +332,13 @@ public Api getApi() { } @Exported + @Override public String getLastUpdated() { - return PipelineUtils.formatTimestamp(System.currentTimeMillis()); + return TimestampFormat.formatTimestamp(System.currentTimeMillis()); } @Exported + @Override public String getError() { return error; } @@ -395,6 +401,15 @@ public void setPagingEnabled(boolean pagingEnabled) { this.pagingEnabled = pagingEnabled; } + @Exported + public boolean isShowAbsoluteDateTime() { + return showAbsoluteDateTime; + } + + public void setShowAbsoluteDateTime(boolean showAbsoluteDateTime) { + this.showAbsoluteDateTime = showAbsoluteDateTime; + } + @Exported public boolean isShowAggregatedChanges() { return showAggregatedChanges; @@ -521,6 +536,7 @@ protected static String withoutFolderPrefix(final String projectName) { } @Exported + @Override public List getPipelines() { try { LOG.fine("Getting pipelines"); diff --git a/src/main/java/se/diabol/jenkins/pipeline/PipelineApi.java b/src/main/java/se/diabol/jenkins/pipeline/PipelineApi.java index 95e8758ab..a55fe1540 100644 --- a/src/main/java/se/diabol/jenkins/pipeline/PipelineApi.java +++ b/src/main/java/se/diabol/jenkins/pipeline/PipelineApi.java @@ -27,11 +27,9 @@ import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; +import se.diabol.jenkins.core.PipelineView; import se.diabol.jenkins.pipeline.trigger.TriggerException; -import java.io.IOException; -import javax.servlet.ServletException; - public class PipelineApi extends Api { private final PipelineView view; @@ -83,7 +81,7 @@ public void doInputStep(StaplerRequest request, StaplerResponse response, @QueryParameter String project, @QueryParameter String upstream, - @QueryParameter String buildId) throws IOException, ServletException { + @QueryParameter String buildId) { doManualStep(request, response, project, upstream, buildId); } diff --git a/src/main/java/se/diabol/jenkins/pipeline/domain/Pipeline.java b/src/main/java/se/diabol/jenkins/pipeline/domain/Pipeline.java index 04fff1510..1fdc64f15 100644 --- a/src/main/java/se/diabol/jenkins/pipeline/domain/Pipeline.java +++ b/src/main/java/se/diabol/jenkins/pipeline/domain/Pipeline.java @@ -27,9 +27,9 @@ import hudson.model.Result; import org.kohsuke.stapler.export.Exported; import se.diabol.jenkins.core.GenericPipeline; +import se.diabol.jenkins.core.TimestampFormat; import se.diabol.jenkins.pipeline.domain.task.Task; import se.diabol.jenkins.pipeline.sort.BuildStartTimeComparator; -import se.diabol.jenkins.pipeline.util.PipelineUtils; import java.util.ArrayList; import java.util.HashMap; @@ -298,7 +298,7 @@ public List createPipelineLatest(int noOfPipelines, Component component) throws PipelineException { List result = new ArrayList<>(); if (firstProject.isInQueue()) { - String pipeLineTimestamp = PipelineUtils.formatTimestamp(firstProject.getQueueItem().getInQueueSince()); + String pipeLineTimestamp = TimestampFormat.formatTimestamp(firstProject.getQueueItem().getInQueueSince()); List pipelineStages = new ArrayList<>(); for (Stage stage : getStages()) { pipelineStages.add(stage.createLatestStage(context, null)); @@ -341,7 +341,7 @@ protected List getPipelines(Iterator it, ItemGroup context, int startI List pipelineChanges = Change.getChanges(firstBuild); Set contributors = showChanges ? UserInfo.getContributors(pipelineChanges) : null; - String pipeLineTimestamp = PipelineUtils.formatTimestamp(firstBuild.getTimeInMillis()); + String pipeLineTimestamp = TimestampFormat.formatTimestamp(firstBuild.getTimeInMillis()); List pipelineStages = new ArrayList<>(); Pipeline pipeline = this; if (showUpstream()) { diff --git a/src/main/java/se/diabol/jenkins/pipeline/domain/status/SimpleStatus.java b/src/main/java/se/diabol/jenkins/pipeline/domain/status/SimpleStatus.java index 94294f5d0..f05ecb30a 100644 --- a/src/main/java/se/diabol/jenkins/pipeline/domain/status/SimpleStatus.java +++ b/src/main/java/se/diabol/jenkins/pipeline/domain/status/SimpleStatus.java @@ -36,9 +36,9 @@ import org.kohsuke.stapler.export.Exported; import org.kohsuke.stapler.export.ExportedBean; import se.diabol.jenkins.core.AbstractItem; +import se.diabol.jenkins.core.TimestampFormat; import se.diabol.jenkins.pipeline.domain.status.promotion.AbstractPromotionStatusProvider; import se.diabol.jenkins.pipeline.domain.status.promotion.PromotionStatus; -import se.diabol.jenkins.pipeline.util.PipelineUtils; import se.diabol.jenkins.pipeline.util.ProjectUtil; import java.util.ArrayList; @@ -91,7 +91,7 @@ public long getLastActivity() { @Exported public String getTimestamp() { if (lastActivity != -1) { - return PipelineUtils.formatTimestamp(lastActivity); + return TimestampFormat.formatTimestamp(lastActivity); } else { return null; } diff --git a/src/main/java/se/diabol/jenkins/pipeline/util/PipelineUtils.java b/src/main/java/se/diabol/jenkins/pipeline/util/PipelineUtils.java index ccd448015..06733048c 100644 --- a/src/main/java/se/diabol/jenkins/pipeline/util/PipelineUtils.java +++ b/src/main/java/se/diabol/jenkins/pipeline/util/PipelineUtils.java @@ -17,9 +17,6 @@ */ package se.diabol.jenkins.pipeline.util; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; import java.util.Random; public final class PipelineUtils { @@ -29,11 +26,6 @@ public final class PipelineUtils { private PipelineUtils() { } - public static String formatTimestamp(long timestamp) { - DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); - return format.format(new Date(timestamp)); - } - public static long getRandom() { return RANDOM.nextLong(); } diff --git a/src/main/java/se/diabol/jenkins/workflow/WorkflowPipelineView.java b/src/main/java/se/diabol/jenkins/workflow/WorkflowPipelineView.java index 48f816625..ce83ebed9 100644 --- a/src/main/java/se/diabol/jenkins/workflow/WorkflowPipelineView.java +++ b/src/main/java/se/diabol/jenkins/workflow/WorkflowPipelineView.java @@ -46,15 +46,15 @@ import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.export.Exported; +import se.diabol.jenkins.core.PipelineView; +import se.diabol.jenkins.core.TimestampFormat; import se.diabol.jenkins.pipeline.PipelineApi; -import se.diabol.jenkins.pipeline.PipelineView; import se.diabol.jenkins.pipeline.domain.Change; import se.diabol.jenkins.pipeline.domain.PipelineException; import se.diabol.jenkins.pipeline.sort.ComponentComparatorDescriptor; import se.diabol.jenkins.pipeline.sort.GenericComponentComparator; import se.diabol.jenkins.pipeline.trigger.TriggerException; import se.diabol.jenkins.pipeline.util.JenkinsUtil; -import se.diabol.jenkins.pipeline.util.PipelineUtils; import se.diabol.jenkins.pipeline.util.ProjectUtil; import se.diabol.jenkins.workflow.model.Component; import se.diabol.jenkins.workflow.model.Pipeline; @@ -89,6 +89,7 @@ public class WorkflowPipelineView extends View implements PipelineView { private boolean allowPipelineStart = false; private boolean allowAbort = false; private boolean showChanges = false; + private boolean showAbsoluteDateTime = false; private String theme = DEFAULT_THEME; private int maxNumberOfVisiblePipelines = -1; @Deprecated @@ -147,6 +148,7 @@ public void setSorting(String sorting) { } @Exported + @Override public boolean isAllowPipelineStart() { return allowPipelineStart; } @@ -156,6 +158,7 @@ public void setAllowPipelineStart(boolean allowPipelineStart) { } @Exported + @Override public boolean isAllowAbort() { return allowAbort; } @@ -172,6 +175,15 @@ public void setShowChanges(boolean showChanges) { this.showChanges = showChanges; } + @Exported + public boolean isShowAbsoluteDateTime() { + return showAbsoluteDateTime; + } + + public void setShowAbsoluteDateTime(boolean showAbsoluteDateTime) { + this.showAbsoluteDateTime = showAbsoluteDateTime; + } + public String getTheme() { return this.theme == null ? DEFAULT_THEME : this.theme; } @@ -208,8 +220,9 @@ public void setComponentSpecs(List componentSpecs) { } @Exported + @Override public String getLastUpdated() { - return PipelineUtils.formatTimestamp(System.currentTimeMillis()); + return TimestampFormat.formatTimestamp(System.currentTimeMillis()); } @Exported @@ -221,8 +234,8 @@ public void setLinkToConsoleLog(boolean linkToConsoleLog) { this.linkToConsoleLog = linkToConsoleLog; } - @Override @Exported + @Override public String getDescription() { if (super.description == null) { setDescription(this.description); @@ -236,11 +249,13 @@ public void setDescription(String description) { } @Exported + @Override public String getError() { return error; } @Exported + @Override public List getPipelines() { try { LOG.fine("Getting pipelines"); diff --git a/src/main/java/se/diabol/jenkins/workflow/model/Pipeline.java b/src/main/java/se/diabol/jenkins/workflow/model/Pipeline.java index 845270305..362bcdca5 100644 --- a/src/main/java/se/diabol/jenkins/workflow/model/Pipeline.java +++ b/src/main/java/se/diabol/jenkins/workflow/model/Pipeline.java @@ -23,11 +23,11 @@ import org.jenkinsci.plugins.workflow.job.WorkflowRun; import org.kohsuke.stapler.export.Exported; import se.diabol.jenkins.core.GenericPipeline; +import se.diabol.jenkins.core.TimestampFormat; import se.diabol.jenkins.pipeline.domain.Change; import se.diabol.jenkins.pipeline.domain.PipelineException; import se.diabol.jenkins.pipeline.domain.TriggerCause; import se.diabol.jenkins.pipeline.domain.UserInfo; -import se.diabol.jenkins.pipeline.util.PipelineUtils; import java.util.List; import java.util.Map; @@ -127,7 +127,7 @@ public long getLastActivity() { } public static Pipeline resolve(WorkflowJob project, WorkflowRun build) throws PipelineException { - String pipelineTimestamp = PipelineUtils.formatTimestamp(build.getTimeInMillis()); + String pipelineTimestamp = TimestampFormat.formatTimestamp(build.getTimeInMillis()); List stageNodes = FlowNodeUtil.getStageNodes(build.getExecution()); return new Pipeline(project.getName(), diff --git a/src/main/resources/se/diabol/jenkins/pipeline/DeliveryPipelineView/configure-entries.jelly b/src/main/resources/se/diabol/jenkins/pipeline/DeliveryPipelineView/configure-entries.jelly index 4be3eee2e..2a2a8bfd3 100644 --- a/src/main/resources/se/diabol/jenkins/pipeline/DeliveryPipelineView/configure-entries.jelly +++ b/src/main/resources/se/diabol/jenkins/pipeline/DeliveryPipelineView/configure-entries.jelly @@ -63,6 +63,10 @@ + + + + diff --git a/src/main/resources/se/diabol/jenkins/pipeline/DeliveryPipelineView/help-showAbsoluteDateTime.html b/src/main/resources/se/diabol/jenkins/pipeline/DeliveryPipelineView/help-showAbsoluteDateTime.html new file mode 100644 index 000000000..47c60c673 --- /dev/null +++ b/src/main/resources/se/diabol/jenkins/pipeline/DeliveryPipelineView/help-showAbsoluteDateTime.html @@ -0,0 +1,3 @@ +
+ Show dates and times as absolute values instead of as relative to the current time. +
diff --git a/src/main/resources/se/diabol/jenkins/workflow/WorkflowPipelineView/configure-entries.jelly b/src/main/resources/se/diabol/jenkins/workflow/WorkflowPipelineView/configure-entries.jelly index 6e858f63d..3b941eed9 100644 --- a/src/main/resources/se/diabol/jenkins/workflow/WorkflowPipelineView/configure-entries.jelly +++ b/src/main/resources/se/diabol/jenkins/workflow/WorkflowPipelineView/configure-entries.jelly @@ -31,6 +31,9 @@ + + + diff --git a/src/main/resources/se/diabol/jenkins/workflow/WorkflowPipelineView/help-showAbsoluteDateTime.html b/src/main/resources/se/diabol/jenkins/workflow/WorkflowPipelineView/help-showAbsoluteDateTime.html new file mode 100644 index 000000000..47c60c673 --- /dev/null +++ b/src/main/resources/se/diabol/jenkins/workflow/WorkflowPipelineView/help-showAbsoluteDateTime.html @@ -0,0 +1,3 @@ +
+ Show dates and times as absolute values instead of as relative to the current time. +
diff --git a/src/main/webapp/pipe.js b/src/main/webapp/pipe.js index e64905dd4..c6dbe5ea5 100644 --- a/src/main/webapp/pipe.js +++ b/src/main/webapp/pipe.js @@ -43,6 +43,7 @@ function pipelineUtils() { var triggered; var contributors; var tasks = []; + var showAbsoluteDateTime = data.showAbsoluteDateTime; displayErrorIfAvailable(data, errorDiv); @@ -98,7 +99,7 @@ function pipelineUtils() { html.push(' triggered by ' + triggered); } - html.push(' started ' + formatDate(pipeline.timestamp, lastUpdate) + ''); + html.push(' started ' + formatDate(pipeline.timestamp, lastUpdate, showAbsoluteDateTime) + ''); if (data.showTotalBuildTime) { html.push('

Total build time: ' + formatDuration(pipeline.totalBuildTime) + '

'); @@ -157,7 +158,7 @@ function pipelineUtils() { id = getTaskId(task.id, i); - timestamp = formatDate(task.status.timestamp, lastUpdate); + timestamp = formatDate(task.status.timestamp, lastUpdate, showAbsoluteDateTime); tasks.push({id: id, taskId: task.id, buildId: task.buildId}); @@ -292,7 +293,7 @@ function pipelineUtils() { pipe = comp.pipelines[d]; head = document.getElementById(pipe.id); if (head) { - head.innerHTML = formatDate(pipe.timestamp, lastUpdate) + head.innerHTML = formatDate(pipe.timestamp, lastUpdate, showAbsoluteDateTime) } for (var l = 0; l < pipe.stages.length; l++) { @@ -301,7 +302,7 @@ function pipelineUtils() { ta = st.tasks[m]; time = document.getElementById(getTaskId(ta.id, d) + '.timestamp'); if (time) { - time.innerHTML = formatDate(ta.status.timestamp, lastUpdate); + time.innerHTML = formatDate(ta.status.timestamp, lastUpdate, showAbsoluteDateTime); } } } @@ -571,8 +572,12 @@ function replace(string, replace, replaceWith) { } -function formatDate(date, currentTime) { - return date !== null ? moment(date, 'YYYY-MM-DDTHH:mm:ss').from(moment(currentTime, 'YYYY-MM-DDTHH:mm:ss')) : ''; +function formatDate(date, currentTime, showAbsoluteDateTime) { + if (showAbsoluteDateTime) { + return date !== null ? moment(date, 'YYYY-MM-DDTHH:mm:ss').format('YYYY-MM-DD HH:mm:ss') : ''; + } else { + return date !== null ? moment(date, 'YYYY-MM-DDTHH:mm:ss').from(moment(currentTime, 'YYYY-MM-DDTHH:mm:ss')) : ''; + } } function formatDuration(millis) { diff --git a/src/test/java/se/diabol/jenkins/pipeline/DeliveryPipelineViewTest.java b/src/test/java/se/diabol/jenkins/pipeline/DeliveryPipelineViewTest.java index 1bcdba91e..f7dd82547 100644 --- a/src/test/java/se/diabol/jenkins/pipeline/DeliveryPipelineViewTest.java +++ b/src/test/java/se/diabol/jenkins/pipeline/DeliveryPipelineViewTest.java @@ -207,6 +207,7 @@ public void shouldHaveDefaults() { assertFalse(view.isLinkRelative()); assertFalse(view.getPagingEnabled()); assertFalse(view.isAllowPipelineStart()); + assertFalse(view.isAllowAbort()); assertEquals("default", view.getTheme()); assertEquals(-1, view.getMaxNumberOfVisiblePipelines()); assertFalse(view.isShowAggregatedChanges()); diff --git a/src/test/java/se/diabol/jenkins/pipeline/util/PipelineUtilsTest.java b/src/test/java/se/diabol/jenkins/pipeline/util/PipelineUtilsTest.java index a8d6cf204..09943cf6e 100644 --- a/src/test/java/se/diabol/jenkins/pipeline/util/PipelineUtilsTest.java +++ b/src/test/java/se/diabol/jenkins/pipeline/util/PipelineUtilsTest.java @@ -21,6 +21,7 @@ import se.diabol.jenkins.pipeline.test.TestUtil; public class PipelineUtilsTest { + @Test public void testValidUtilClass() throws Exception { TestUtil.assertUtilityClassWellDefined(PipelineUtils.class);