From d0c45040d6aafa22842e4c3ba7dac908f251522c Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 24 Oct 2013 14:55:08 -0400 Subject: [PATCH] =?UTF-8?q?Get/UpdateJobCommand=20should=20work=20with=20t?= =?UTF-8?q?he=20most=20generic=20possible=20type=E2=80=94AbstractItem.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changelog.html | 3 + .../main/java/hudson/cli/GetJobCommand.java | 4 +- .../java/hudson/cli/UpdateJobCommand.java | 4 +- .../handlers/AbstractItemOptionHandler.java | 48 +++++++++++++ .../AbstractProjectOptionHandler.java | 26 ++----- .../handlers/GenericItemOptionHandler.java | 72 +++++++++++++++++++ .../handlers/TopLevelItemOptionHandler.java | 29 ++------ .../java/hudson/model/AbstractProject.java | 11 +-- core/src/main/java/hudson/model/Items.java | 21 ++++++ .../java/hudson/cli/GetJobCommandTest.java | 66 +++++++++++++++++ 10 files changed, 227 insertions(+), 57 deletions(-) create mode 100644 core/src/main/java/hudson/cli/handlers/AbstractItemOptionHandler.java create mode 100644 core/src/main/java/hudson/cli/handlers/GenericItemOptionHandler.java create mode 100644 test/src/test/java/hudson/cli/GetJobCommandTest.java diff --git a/changelog.html b/changelog.html index ba3c08d119..4ef9ac3733 100644 --- a/changelog.html +++ b/changelog.html @@ -61,6 +61,9 @@ Upcoming changes
  • Pass full list of all possible jobs to ViewJobFilter when recurse option is set (issue 20143) +
  • + get-job and update-job CLI commands can now work with folders, or indeed any AbstractItem. + (issue 20236)
  • Added API allowing plugins to hide entries from the context menu even while they appear in the sidepanel. (issue 19173) diff --git a/core/src/main/java/hudson/cli/GetJobCommand.java b/core/src/main/java/hudson/cli/GetJobCommand.java index 0b8223442c..efc1e90836 100644 --- a/core/src/main/java/hudson/cli/GetJobCommand.java +++ b/core/src/main/java/hudson/cli/GetJobCommand.java @@ -24,7 +24,7 @@ package hudson.cli; import hudson.Extension; -import hudson.model.AbstractProject; +import hudson.model.AbstractItem; import hudson.model.Item; import hudson.util.IOUtils; import org.kohsuke.args4j.Argument; @@ -35,7 +35,7 @@ import org.kohsuke.args4j.Argument; @Extension public class GetJobCommand extends CLICommand { @Argument(metaVar="JOB",usage="Name of the job",required=true) - public AbstractProject job; + public AbstractItem job; @Override public String getShortDescription() { diff --git a/core/src/main/java/hudson/cli/UpdateJobCommand.java b/core/src/main/java/hudson/cli/UpdateJobCommand.java index eaea422772..a9a34403ec 100644 --- a/core/src/main/java/hudson/cli/UpdateJobCommand.java +++ b/core/src/main/java/hudson/cli/UpdateJobCommand.java @@ -24,7 +24,7 @@ package hudson.cli; import hudson.Extension; -import hudson.model.AbstractProject; +import hudson.model.AbstractItem; import org.kohsuke.args4j.Argument; import javax.xml.transform.Source; @@ -36,7 +36,7 @@ import javax.xml.transform.stream.StreamSource; @Extension public class UpdateJobCommand extends CLICommand { @Argument(metaVar="JOB",usage="Name of the job",required=true) - public AbstractProject job; + public AbstractItem job; @Override public String getShortDescription() { diff --git a/core/src/main/java/hudson/cli/handlers/AbstractItemOptionHandler.java b/core/src/main/java/hudson/cli/handlers/AbstractItemOptionHandler.java new file mode 100644 index 0000000000..c99f309079 --- /dev/null +++ b/core/src/main/java/hudson/cli/handlers/AbstractItemOptionHandler.java @@ -0,0 +1,48 @@ +/* + * The MIT License + * + * Copyright 2013 Jesse Glick. + * + * 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 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package hudson.cli.handlers; + +import hudson.model.AbstractItem; +import org.kohsuke.MetaInfServices; +import org.kohsuke.args4j.CmdLineParser; +import org.kohsuke.args4j.OptionDef; +import org.kohsuke.args4j.spi.OptionHandler; +import org.kohsuke.args4j.spi.Setter; + +/** + * Refers to an {@link AbstractItem} by name. + * @since 1.538 + */ +@MetaInfServices(OptionHandler.class) public class AbstractItemOptionHandler extends GenericItemOptionHandler { + + public AbstractItemOptionHandler(CmdLineParser parser, OptionDef option, Setter setter) { + super(parser, option, setter); + } + + @Override protected Class type() { + return AbstractItem.class; + } + +} diff --git a/core/src/main/java/hudson/cli/handlers/AbstractProjectOptionHandler.java b/core/src/main/java/hudson/cli/handlers/AbstractProjectOptionHandler.java index 0dc515751c..b630e48b56 100644 --- a/core/src/main/java/hudson/cli/handlers/AbstractProjectOptionHandler.java +++ b/core/src/main/java/hudson/cli/handlers/AbstractProjectOptionHandler.java @@ -24,42 +24,26 @@ package hudson.cli.handlers; import hudson.model.AbstractProject; -import jenkins.model.Jenkins; -import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.OptionDef; -import org.kohsuke.args4j.spi.OptionHandler; -import org.kohsuke.args4j.spi.Parameters; import org.kohsuke.args4j.spi.Setter; import org.kohsuke.MetaInfServices; +import org.kohsuke.args4j.spi.OptionHandler; /** * Refer to {@link AbstractProject} by its name. * * @author Kohsuke Kawaguchi */ -@MetaInfServices +@MetaInfServices(OptionHandler.class) @SuppressWarnings("rawtypes") -public class AbstractProjectOptionHandler extends OptionHandler { +public class AbstractProjectOptionHandler extends GenericItemOptionHandler { public AbstractProjectOptionHandler(CmdLineParser parser, OptionDef option, Setter setter) { super(parser, option, setter); } - @Override - public int parseArguments(Parameters params) throws CmdLineException { - Jenkins h = Jenkins.getInstance(); - String src = params.getParameter(0); - - AbstractProject s = h.getItemByFullName(src,AbstractProject.class); - if (s==null) { - AbstractProject nearest = AbstractProject.findNearest(src); - if (nearest!=null) - throw new CmdLineException(owner, "No such job '"+src+"' perhaps you meant '"+ nearest.getFullName() +"'?"); - else - throw new CmdLineException(owner, "No such job '"+src+"'"); - } - setter.addValue(s); - return 1; + @Override protected Class type() { + return AbstractProject.class; } @Override diff --git a/core/src/main/java/hudson/cli/handlers/GenericItemOptionHandler.java b/core/src/main/java/hudson/cli/handlers/GenericItemOptionHandler.java new file mode 100644 index 0000000000..502d65f925 --- /dev/null +++ b/core/src/main/java/hudson/cli/handlers/GenericItemOptionHandler.java @@ -0,0 +1,72 @@ +/* + * The MIT License + * + * Copyright 2013 Jesse Glick. + * + * 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 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package hudson.cli.handlers; + +import hudson.model.Item; +import hudson.model.Items; +import jenkins.model.Jenkins; +import org.kohsuke.args4j.CmdLineException; +import org.kohsuke.args4j.CmdLineParser; +import org.kohsuke.args4j.OptionDef; +import org.kohsuke.args4j.spi.OptionHandler; +import org.kohsuke.args4j.spi.Parameters; +import org.kohsuke.args4j.spi.Setter; + +/** + * Refers to an {@link Item} by its name. + * May be subclassed to handle specific kinds of items. + * (Use {@code @MetaInfServices(OptionHandler.class)} to register the subclass.) + * @param the kind of item being handled + * @since 1.538 + */ +public abstract class GenericItemOptionHandler extends OptionHandler { + + protected GenericItemOptionHandler(CmdLineParser parser, OptionDef option, Setter setter) { + super(parser, option, setter); + } + + protected abstract Class type(); + + @Override public int parseArguments(Parameters params) throws CmdLineException { + Jenkins j = Jenkins.getInstance(); + String src = params.getParameter(0); + T s = j.getItemByFullName(src, type()); + if (s == null) { + T nearest = Items.findNearest(type(), src, j); + if (nearest != null) { + throw new CmdLineException(owner, "No such job '" + src + "'; perhaps you meant '" + nearest.getFullName() + "'?"); + } else { + throw new CmdLineException(owner, "No such job '" + src + "'"); + } + } + setter.addValue(s); + return 1; + } + + @Override public String getDefaultMetaVariable() { + return "ITEM"; + } + +} diff --git a/core/src/main/java/hudson/cli/handlers/TopLevelItemOptionHandler.java b/core/src/main/java/hudson/cli/handlers/TopLevelItemOptionHandler.java index 0c4a4ea978..97fdf4b8c5 100644 --- a/core/src/main/java/hudson/cli/handlers/TopLevelItemOptionHandler.java +++ b/core/src/main/java/hudson/cli/handlers/TopLevelItemOptionHandler.java @@ -1,14 +1,10 @@ package hudson.cli.handlers; -import hudson.model.AbstractProject; -import jenkins.model.Jenkins; import hudson.model.TopLevelItem; import org.kohsuke.MetaInfServices; -import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.OptionDef; import org.kohsuke.args4j.spi.OptionHandler; -import org.kohsuke.args4j.spi.Parameters; import org.kohsuke.args4j.spi.Setter; /** @@ -16,33 +12,18 @@ import org.kohsuke.args4j.spi.Setter; * * @author Kohsuke Kawaguchi */ -@MetaInfServices -public class TopLevelItemOptionHandler extends OptionHandler { +@MetaInfServices(OptionHandler.class) +public class TopLevelItemOptionHandler extends GenericItemOptionHandler { public TopLevelItemOptionHandler(CmdLineParser parser, OptionDef option, Setter setter) { super(parser, option, setter); } - @Override - @SuppressWarnings("rawtypes") - public int parseArguments(Parameters params) throws CmdLineException { - Jenkins h = Jenkins.getInstance(); - String src = params.getParameter(0); - - TopLevelItem s = h.getItemByFullName(src, TopLevelItem.class); - if (s==null) { - AbstractProject nearest = AbstractProject.findNearest(src); - if (nearest!=null) - throw new CmdLineException(owner, "No such job '"+src+"' perhaps you meant '"+ nearest.getFullName() +"'?"); - else - throw new CmdLineException(owner, "No such job '"+src+"'"); - } - - setter.addValue(s); - return 1; + @Override protected Class type() { + return TopLevelItem.class; } @Override public String getDefaultMetaVariable() { - return "JOB"; + return "JOB"; // TODO or should we pick up default value, ITEM? } } diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index a1f9eb8d0e..9fbcfda90b 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -80,7 +80,6 @@ import hudson.triggers.TriggerDescriptor; import hudson.util.AlternativeUiTextProvider; import hudson.util.AlternativeUiTextProvider.Message; import hudson.util.DescribableList; -import hudson.util.EditDistance; import hudson.util.FormValidation; import hudson.widgets.BuildHistoryWidget; import hudson.widgets.HistoryWidget; @@ -2299,6 +2298,7 @@ public abstract class AbstractProject

    ,R extends A /** * Finds a {@link AbstractProject} that has the name closest to the given name. + * @see Items#findNearest */ public static AbstractProject findNearest(String name) { return findNearest(name,Hudson.getInstance()); @@ -2308,15 +2308,10 @@ public abstract class AbstractProject

    ,R extends A * Finds a {@link AbstractProject} whose name (when referenced from the specified context) is closest to the given name. * * @since 1.419 + * @see Items#findNearest */ public static AbstractProject findNearest(String name, ItemGroup context) { - List projects = Hudson.getInstance().getAllItems(AbstractProject.class); - String[] names = new String[projects.size()]; - for( int i=0; i REVERSE_INTEGER_COMPARATOR = new Comparator() { diff --git a/core/src/main/java/hudson/model/Items.java b/core/src/main/java/hudson/model/Items.java index 746a5aa4fb..5ca561beaa 100644 --- a/core/src/main/java/hudson/model/Items.java +++ b/core/src/main/java/hudson/model/Items.java @@ -32,6 +32,7 @@ import hudson.XmlFile; import hudson.matrix.Axis; import hudson.triggers.Trigger; import hudson.util.DescriptorList; +import hudson.util.EditDistance; import hudson.util.XStream2; import jenkins.model.Jenkins; import org.apache.commons.lang.StringUtils; @@ -39,6 +40,7 @@ import org.apache.commons.lang.StringUtils; import java.io.File; import java.io.IOException; import java.util.*; +import javax.annotation.CheckForNull; /** * Convenience methods related to {@link Item}. @@ -279,6 +281,25 @@ public class Items { return r; } + /** + * Finds an item whose name (when referenced from the specified context) is closest to the given name. + * @param the type of item being considered + * @param type same as {@code T} + * @param name the supplied name + * @param context a context to start from (used to compute relative names) + * @return the closest available item + * @since 1.538 + */ + public static @CheckForNull T findNearest(Class type, String name, ItemGroup context) { + List projects = Jenkins.getInstance().getAllItems(type); + String[] names = new String[projects.size()]; + for (int i = 0; i < projects.size(); i++) { + names[i] = projects.get(i).getRelativeNameFrom(context); + } + String nearest = EditDistance.findNearest(name, names); + return Jenkins.getInstance().getItem(nearest, context, type); + } + /** * Used to load/save job configuration. * diff --git a/test/src/test/java/hudson/cli/GetJobCommandTest.java b/test/src/test/java/hudson/cli/GetJobCommandTest.java new file mode 100644 index 0000000000..2ecbf318ba --- /dev/null +++ b/test/src/test/java/hudson/cli/GetJobCommandTest.java @@ -0,0 +1,66 @@ +/* + * The MIT License + * + * Copyright 2012 Jesse Glick. + * + * 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 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package hudson.cli; + +import edu.umd.cs.findbugs.annotations.SuppressWarnings; +import hudson.model.FreeStyleProject; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.Collections; +import java.util.Locale; +import org.apache.commons.io.input.NullInputStream; +import static org.junit.Assert.*; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Bug; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.MockFolder; + +@SuppressWarnings("DM_DEFAULT_ENCODING") +public class GetJobCommandTest { + + @Rule public JenkinsRule j = new JenkinsRule(); + + @Bug(20236) + @Test public void withFolders() throws Exception { + MockFolder d = j.createFolder("d"); + FreeStyleProject p = d.createProject(FreeStyleProject.class, "p"); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + PrintStream outS = new PrintStream(out); + int result = new GetJobCommand().main(Collections.singletonList("d/p"), Locale.ENGLISH, new NullInputStream(0), outS, outS); + outS.flush(); + String output = out.toString(); + assertEquals(output, 0, result); + assertEquals(p.getConfigFile().asString(), output); + out = new ByteArrayOutputStream(); + outS = new PrintStream(out); + result = new GetJobCommand().main(Collections.singletonList("d"), Locale.ENGLISH, new NullInputStream(0), outS, outS); + outS.flush(); + output = out.toString(); + assertEquals(output, 0, result); + assertEquals(d.getConfigFile().asString(), output); + } + +} -- GitLab