提交 d0c45040 编写于 作者: J Jesse Glick

Get/UpdateJobCommand should work with the most generic possible type—AbstractItem.

上级 304b2c07
......@@ -61,6 +61,9 @@ Upcoming changes</a>
<li class=bug>
Pass full list of all possible jobs to ViewJobFilter when recurse option is set
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-20143">issue 20143</a>)
<li class=rfe>
<code>get-job</code> and <code>update-job</code> CLI commands can now work with folders, or indeed any <code>AbstractItem</code>.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-20236">issue 20236</a>)
<li class=rfe>
Added API allowing plugins to hide entries from the context menu even while they appear in the sidepanel.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-19173">issue 19173</a>)
......
......@@ -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() {
......
......@@ -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() {
......
/*
* 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<AbstractItem> {
public AbstractItemOptionHandler(CmdLineParser parser, OptionDef option, Setter<AbstractItem> setter) {
super(parser, option, setter);
}
@Override protected Class<AbstractItem> type() {
return AbstractItem.class;
}
}
......@@ -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<AbstractProject> {
public class AbstractProjectOptionHandler extends GenericItemOptionHandler<AbstractProject> {
public AbstractProjectOptionHandler(CmdLineParser parser, OptionDef option, Setter<AbstractProject> 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<AbstractProject> type() {
return AbstractProject.class;
}
@Override
......
/*
* 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 <T> the kind of item being handled
* @since 1.538
*/
public abstract class GenericItemOptionHandler<T extends Item> extends OptionHandler<T> {
protected GenericItemOptionHandler(CmdLineParser parser, OptionDef option, Setter<T> setter) {
super(parser, option, setter);
}
protected abstract Class<T> 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";
}
}
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<TopLevelItem> {
@MetaInfServices(OptionHandler.class)
public class TopLevelItemOptionHandler extends GenericItemOptionHandler<TopLevelItem> {
public TopLevelItemOptionHandler(CmdLineParser parser, OptionDef option, Setter<TopLevelItem> 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<TopLevelItem> type() {
return TopLevelItem.class;
}
@Override
public String getDefaultMetaVariable() {
return "JOB";
return "JOB"; // TODO or should we pick up default value, ITEM?
}
}
......@@ -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<P extends AbstractProject<P,R>,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<P extends AbstractProject<P,R>,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<AbstractProject> projects = Hudson.getInstance().getAllItems(AbstractProject.class);
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 (AbstractProject)Jenkins.getInstance().getItem(nearest,context);
return Items.findNearest(AbstractProject.class, name, context);
}
private static final Comparator<Integer> REVERSE_INTEGER_COMPARATOR = new Comparator<Integer>() {
......
......@@ -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 <T> 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 extends Item> T findNearest(Class<T> type, String name, ItemGroup context) {
List<T> 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.
*
......
/*
* 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);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册