From b1415bda59e1020c433a63ff1830a3012eb04428 Mon Sep 17 00:00:00 2001 From: gcummings Date: Tue, 5 Mar 2013 15:05:00 +0000 Subject: [PATCH] JENKINS-7280 - Allow filtering of the Run Paramters List - All, Completed, Successful & Stable using Enum --- .../hudson/model/RunParameterDefinition.java | 85 +++++++- .../java/hudson/model/RunParameterValue.java | 5 +- core/src/main/java/hudson/util/RunList.java | 15 +- .../model/RunParameterDefinition/config.jelly | 8 + .../model/RunParameterDefinition/index.jelly | 2 +- .../java/hudson/model/ParametersTest.java | 2 +- .../model/RunParameterDefinitionTest.java | 203 +++++++++++++++++- .../webapp/help/parameter/run-filter.html | 9 + .../webapp/help/parameter/run-project.html | 1 + 9 files changed, 318 insertions(+), 12 deletions(-) create mode 100755 war/src/main/webapp/help/parameter/run-filter.html diff --git a/core/src/main/java/hudson/model/RunParameterDefinition.java b/core/src/main/java/hudson/model/RunParameterDefinition.java index 04d074f01e..107263f4c9 100644 --- a/core/src/main/java/hudson/model/RunParameterDefinition.java +++ b/core/src/main/java/hudson/model/RunParameterDefinition.java @@ -1,7 +1,7 @@ /* * The MIT License * - * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Tom Huybrechts + * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Tom Huybrechts, Geoff Cummings * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,31 +30,63 @@ import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.export.Exported; import hudson.Extension; +import hudson.util.EnumConverter; +import hudson.util.RunList; +import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.QueryParameter; public class RunParameterDefinition extends SimpleParameterDefinition { + /** + * Constants that control how Run Parameter is filtered + */ + public enum RunParameterFilter { + ALL, + STABLE, + SUCCESSFUL, + COMPLETED; + + public String getName() { + return name(); + } + + static { + Stapler.CONVERT_UTILS.register(new EnumConverter(), RunParameterFilter.class); + } + } + private final String projectName; private final String runId; + private final RunParameterFilter filter; @DataBoundConstructor - public RunParameterDefinition(String name, String projectName, String description) { + public RunParameterDefinition(String name, String projectName, String description, RunParameterFilter filter) { super(name, description); this.projectName = projectName; this.runId = null; + this.filter = filter; } - private RunParameterDefinition(String name, String projectName, String runId, String description) { + /** + * @deprecated as of 1.517 + */ + public RunParameterDefinition(String name, String projectName, String description) { + // delegate to updated constructor with additional RunParameterFilter parameter defaulted to ALL. + this(name, projectName, description, RunParameterFilter.ALL); + } + + private RunParameterDefinition(String name, String projectName, String runId, String description, RunParameterFilter filter) { super(name, description); this.projectName = projectName; this.runId = runId; + this.filter = filter; } @Override public ParameterDefinition copyWithDefaultValue(ParameterValue defaultValue) { if (defaultValue instanceof RunParameterValue) { RunParameterValue value = (RunParameterValue) defaultValue; - return new RunParameterDefinition(getName(), value.getRunId(), getDescription()); + return new RunParameterDefinition(getName(), value.getRunId(), getDescription(), getFilter()); } else { return this; } @@ -69,6 +101,32 @@ public class RunParameterDefinition extends SimpleParameterDefinition { return Jenkins.getInstance().getItemByFullName(projectName, Job.class); } + /** + * @return The current filter value, if filter is null, returns ALL + */ + public RunParameterFilter getFilter() { + // if filter is null, default to RunParameterFilter.ALL + return (null == filter) ? RunParameterFilter.ALL : filter; + } + + /** + * @since 1.517 + * @return Returns a list of builds, filtered based on the filter value. + */ + public RunList getBuilds() { + // use getFilter() method so we dont have to worry about null filter value. + switch (getFilter()) { + case COMPLETED: + return getProject().getBuilds().overThresholdOnly(Result.ABORTED); + case SUCCESSFUL: + return getProject().getBuilds().overThresholdOnly(Result.UNSTABLE); + case STABLE : + return getProject().getBuilds().overThresholdOnly(Result.SUCCESS); + default: + return getProject().getBuilds(); + } + } + @Extension public static class DescriptorImpl extends ParameterDescriptor { @Override @@ -98,7 +156,24 @@ public class RunParameterDefinition extends SimpleParameterDefinition { return createValue(runId); } - Run lastBuild = getProject().getLastBuild(); + Run lastBuild = null; + + // use getFilter() so we dont have to worry about null filter value. + switch (getFilter()) { + case COMPLETED: + lastBuild = getProject().getLastCompletedBuild(); + break; + case SUCCESSFUL: + lastBuild = getProject().getLastSuccessfulBuild(); + break; + case STABLE : + lastBuild = getProject().getLastStableBuild(); + break; + default: + lastBuild = getProject().getLastBuild(); + break; + } + if (lastBuild != null) { return createValue(lastBuild.getExternalizableId()); } else { diff --git a/core/src/main/java/hudson/model/RunParameterValue.java b/core/src/main/java/hudson/model/RunParameterValue.java index 3ee6072cad..6368a94277 100644 --- a/core/src/main/java/hudson/model/RunParameterValue.java +++ b/core/src/main/java/hudson/model/RunParameterValue.java @@ -1,7 +1,7 @@ /* * The MIT License * - * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Tom Huybrechts + * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Tom Huybrechts, Geoff Cummings * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -82,6 +82,9 @@ public class RunParameterValue extends ParameterValue { env.put(name + "_NAME", run.getDisplayName()); // since 1.504 + String buildResult = (null == run.getResult()) ? "UNKNOWN" : run.getResult().toString(); + env.put(name + "_RESULT", buildResult); // since 1.517 + env.put(name.toUpperCase(Locale.ENGLISH),value); // backward compatibility pre 1.345 } diff --git a/core/src/main/java/hudson/util/RunList.java b/core/src/main/java/hudson/util/RunList.java index 25f7deadd3..0fc740a3f1 100644 --- a/core/src/main/java/hudson/util/RunList.java +++ b/core/src/main/java/hudson/util/RunList.java @@ -1,7 +1,7 @@ /* * The MIT License * - * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi + * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Geoff Cummings * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -240,6 +240,19 @@ public class RunList extends AbstractList { }); } + /** + * Filter the list to builds >= threshold. + * + * @since 1.516 + */ + public RunList overThresholdOnly(final Result threshold) { + return filter(new Predicate() { + public boolean apply(R r) { + return (r.getResult() != null && r.getResult().isBetterOrEqualTo(threshold)); + } + }); + } + /** * Filter the list to builds on a single node only */ diff --git a/core/src/main/resources/hudson/model/RunParameterDefinition/config.jelly b/core/src/main/resources/hudson/model/RunParameterDefinition/config.jelly index 007c8e0bdc..16aeae2d46 100755 --- a/core/src/main/resources/hudson/model/RunParameterDefinition/config.jelly +++ b/core/src/main/resources/hudson/model/RunParameterDefinition/config.jelly @@ -35,4 +35,12 @@ THE SOFTWARE. + + + \ No newline at end of file diff --git a/core/src/main/resources/hudson/model/RunParameterDefinition/index.jelly b/core/src/main/resources/hudson/model/RunParameterDefinition/index.jelly index 486ab16d62..600f6b4f86 100755 --- a/core/src/main/resources/hudson/model/RunParameterDefinition/index.jelly +++ b/core/src/main/resources/hudson/model/RunParameterDefinition/index.jelly @@ -30,7 +30,7 @@ THE SOFTWARE.
diff --git a/test/src/test/java/hudson/model/ParametersTest.java b/test/src/test/java/hudson/model/ParametersTest.java index 9e32f79653..b5aa636c6e 100755 --- a/test/src/test/java/hudson/model/ParametersTest.java +++ b/test/src/test/java/hudson/model/ParametersTest.java @@ -24,7 +24,7 @@ public class ParametersTest extends HudsonTestCase { new StringParameterDefinition("string", "defaultValue", "string description"), new BooleanParameterDefinition("boolean", true, "boolean description"), new ChoiceParameterDefinition("choice", "Choice 1\nChoice 2", "choice description"), - new RunParameterDefinition("run", otherProject.getName(), "run description")); + new RunParameterDefinition("run", otherProject.getName(), "run description", null)); project.addProperty(pdp); CaptureEnvironmentBuilder builder = new CaptureEnvironmentBuilder(); project.getBuildersList().add(builder); diff --git a/test/src/test/java/hudson/model/RunParameterDefinitionTest.java b/test/src/test/java/hudson/model/RunParameterDefinitionTest.java index 7d0da8964c..1f0e909507 100644 --- a/test/src/test/java/hudson/model/RunParameterDefinitionTest.java +++ b/test/src/test/java/hudson/model/RunParameterDefinitionTest.java @@ -1,7 +1,7 @@ /* * The MIT License * - * Copyright 2013 Jesse Glick. + * Copyright 2013 Jesse Glick, Geoff Cummings * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,16 @@ package hudson.model; import hudson.EnvVars; import static org.junit.Assert.*; +import hudson.Launcher; +import hudson.model.RunParameterDefinition.RunParameterFilter; +import hudson.tasks.BuildStepMonitor; +import hudson.tasks.Publisher; +import hudson.util.LogTaskListener; + +import java.util.Collections; +import java.util.logging.Level; +import java.util.logging.Logger; + import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Bug; @@ -34,7 +44,10 @@ import org.jvnet.hudson.test.MockFolder; public class RunParameterDefinitionTest { - @Rule public JenkinsRule j = new JenkinsRule(); + private static final Logger LOGGER = Logger.getLogger(Run.class.getName()); + + @Rule + public JenkinsRule j = new JenkinsRule(); @Bug(16462) @Test public void inFolders() throws Exception { @@ -47,7 +60,7 @@ public class RunParameterDefinitionTest { String id = build2.getExternalizableId(); assertEquals("dir/sub dir/some project#2", id); assertEquals(build2, Run.fromExternalizableId(id)); - RunParameterDefinition def = new RunParameterDefinition("build", "dir/sub dir/some project", "my build"); + RunParameterDefinition def = new RunParameterDefinition("build", "dir/sub dir/some project", "my build", null); assertEquals("dir/sub dir/some project", def.getProjectName()); assertEquals(p, def.getProject()); EnvVars env = new EnvVars(); @@ -65,4 +78,188 @@ public class RunParameterDefinitionTest { assertEquals("2", env.get("build_NUMBER")); } + @Test + public void testNULLFilter() throws Exception { + + FreeStyleProject project = j.createFreeStyleProject("project"); + FreeStyleBuild successfulBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.UNSTABLE))); + FreeStyleBuild unstableBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.FAILURE))); + FreeStyleBuild failedBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.NOT_BUILT))); + FreeStyleBuild notBuiltBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.ABORTED))); + FreeStyleBuild abortedBuild = project.scheduleBuild2(0).get(); + + FreeStyleProject paramProject = j.createFreeStyleProject("paramProject"); + ParametersDefinitionProperty pdp = + new ParametersDefinitionProperty(new RunParameterDefinition("RUN", + project.getName(), + "run description", + null)); + paramProject.addProperty(pdp); + + FreeStyleBuild build = paramProject.scheduleBuild2(0).get(); + assertEquals(Integer.toString(project.getLastBuild().getNumber()), + build.getEnvironment(new LogTaskListener(LOGGER, Level.INFO)).get("RUN_NUMBER")); + } + + + @Test + public void testALLFilter() throws Exception { + + FreeStyleProject project = j.createFreeStyleProject("project"); + FreeStyleBuild successfulBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.UNSTABLE))); + FreeStyleBuild unstableBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.FAILURE))); + FreeStyleBuild failedBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.NOT_BUILT))); + FreeStyleBuild notBuiltBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.ABORTED))); + FreeStyleBuild abortedBuild = project.scheduleBuild2(0).get(); + + FreeStyleProject paramProject = j.createFreeStyleProject("paramProject"); + ParametersDefinitionProperty pdp = + new ParametersDefinitionProperty(new RunParameterDefinition("RUN", + project.getName(), + "run description", + RunParameterFilter.ALL)); + paramProject.addProperty(pdp); + + FreeStyleBuild build = paramProject.scheduleBuild2(0).get(); + assertEquals(Integer.toString(project.getLastBuild().getNumber()), + build.getEnvironment(new LogTaskListener(LOGGER, Level.INFO)).get("RUN_NUMBER")); + } + + @Test + public void testCOMPLETEDFilter() throws Exception { + + FreeStyleProject project = j.createFreeStyleProject("project"); + FreeStyleBuild successfulBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.UNSTABLE))); + FreeStyleBuild unstableBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.FAILURE))); + FreeStyleBuild failedBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.NOT_BUILT))); + FreeStyleBuild notBuiltBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.ABORTED))); + FreeStyleBuild abortedBuild = project.scheduleBuild2(0).get(); + + FreeStyleProject paramProject = j.createFreeStyleProject("paramProject"); + ParametersDefinitionProperty pdp = + new ParametersDefinitionProperty(new RunParameterDefinition("RUN", + project.getName(), + "run description", + RunParameterFilter.COMPLETED)); + paramProject.addProperty(pdp); + + FreeStyleBuild build = paramProject.scheduleBuild2(0).get(); + assertEquals(Integer.toString(abortedBuild.getNumber()), + build.getEnvironment(new LogTaskListener(LOGGER, Level.INFO)).get("RUN_NUMBER")); + } + + @Test + public void testSUCCESSFULFilter() throws Exception { + + FreeStyleProject project = j.createFreeStyleProject("project"); + FreeStyleBuild successfulBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.UNSTABLE))); + FreeStyleBuild unstableBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.FAILURE))); + FreeStyleBuild failedBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.NOT_BUILT))); + FreeStyleBuild notBuiltBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.ABORTED))); + FreeStyleBuild abortedBuild = project.scheduleBuild2(0).get(); + + FreeStyleProject paramProject = j.createFreeStyleProject("paramProject"); + ParametersDefinitionProperty pdp = + new ParametersDefinitionProperty(new RunParameterDefinition("RUN", + project.getName(), + "run description", + RunParameterFilter.SUCCESSFUL)); + paramProject.addProperty(pdp); + + FreeStyleBuild build = paramProject.scheduleBuild2(0).get(); + assertEquals(Integer.toString(unstableBuild.getNumber()), + build.getEnvironment(new LogTaskListener(LOGGER, Level.INFO)).get("RUN_NUMBER")); + } + + + @Test + public void testSTABLEFilter() throws Exception { + + FreeStyleProject project = j.createFreeStyleProject("project"); + FreeStyleBuild successfulBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.UNSTABLE))); + FreeStyleBuild unstableBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.FAILURE))); + FreeStyleBuild failedBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.NOT_BUILT))); + FreeStyleBuild notBuiltBuild = project.scheduleBuild2(0).get(); + + project.getPublishersList().replaceBy(Collections.singleton(new ResultPublisher(Result.ABORTED))); + FreeStyleBuild abortedBuild = project.scheduleBuild2(0).get(); + + FreeStyleProject paramProject = j.createFreeStyleProject("paramProject"); + ParametersDefinitionProperty pdp = + new ParametersDefinitionProperty(new RunParameterDefinition("RUN", + project.getName(), + "run description", + RunParameterFilter.STABLE)); + paramProject.addProperty(pdp); + + FreeStyleBuild build = paramProject.scheduleBuild2(0).get(); + assertEquals(Integer.toString(successfulBuild.getNumber()), + build.getEnvironment(new LogTaskListener(LOGGER, Level.INFO)).get("RUN_NUMBER")); + } + + + static class ResultPublisher extends Publisher { + + private Result result = Result.FAILURE; + + public ResultPublisher(Result result) { + this.result = result; + } + + public @Override + boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) { + build.setResult(result); + return true; + } + + public BuildStepMonitor getRequiredMonitorService() { + return BuildStepMonitor.NONE; + } + + public Descriptor getDescriptor() { + return new Descriptor(ResultPublisher.class) { + public String getDisplayName() { + return "ResultPublisher"; + } + }; + } + } } diff --git a/war/src/main/webapp/help/parameter/run-filter.html b/war/src/main/webapp/help/parameter/run-filter.html new file mode 100755 index 0000000000..98b3bf9ac8 --- /dev/null +++ b/war/src/main/webapp/help/parameter/run-filter.html @@ -0,0 +1,9 @@ +
+Filter the list of builds which are included in the drop-down list. +
+'All Builds' - List all builds including in-progress builds.
+'Completed Builds Only' - List all completed builds.
+'Successful Builds Only' - List all Successful builds (Stable and Unstable)
+'Stable Builds Only' - List all Stable builds.
+
+
diff --git a/war/src/main/webapp/help/parameter/run-project.html b/war/src/main/webapp/help/parameter/run-project.html index 36ab460547..239784ea32 100755 --- a/war/src/main/webapp/help/parameter/run-project.html +++ b/war/src/main/webapp/help/parameter/run-project.html @@ -6,5 +6,6 @@ PARAMETER_NAME=<jenkins_url>/job/<job_name>/<run_number PARAMETER_NAME_JOBNAME=<job_name> PARAMETER_NAME_NUMBER=<run_number> PARAMETER_NAME_NAME=<display_name> +PARAMETER_NAME_RESULT=<run_result>
\ No newline at end of file