diff --git a/core/src/main/java/hudson/cli/AddJobToViewCommand.java b/core/src/main/java/hudson/cli/AddJobToViewCommand.java index cea483785a304ea5651758c4f078e8b8d2cb18b3..792ff4feaa4cacdce65ddafceaf8c61cf0701ba6 100644 --- a/core/src/main/java/hudson/cli/AddJobToViewCommand.java +++ b/core/src/main/java/hudson/cli/AddJobToViewCommand.java @@ -31,7 +31,6 @@ import hudson.model.DirectlyModifiableView; import hudson.model.View; import org.kohsuke.args4j.Argument; -import org.kohsuke.args4j.CmdLineException; /** * @author ogondza @@ -55,9 +54,8 @@ public class AddJobToViewCommand extends CLICommand { protected int run() throws Exception { view.checkPermission(View.CONFIGURE); - if (!(view instanceof DirectlyModifiableView)) throw new CmdLineException( - null, "'" + view.getDisplayName() + "' view can not be modified directly" - ); + if (!(view instanceof DirectlyModifiableView)) throw new IllegalStateException( + "'" + view.getDisplayName() + "' view can not be modified directly"); for (TopLevelItem job: jobs) { ((DirectlyModifiableView) view).add(job); diff --git a/core/src/main/java/hudson/cli/BuildCommand.java b/core/src/main/java/hudson/cli/BuildCommand.java index 5a018aeeb70d50b41e4ee94f3175c603f2779b44..1c8a071d4e6a79925b37e0f8d5c9a46250f2fefe 100644 --- a/core/src/main/java/hudson/cli/BuildCommand.java +++ b/core/src/main/java/hudson/cli/BuildCommand.java @@ -42,6 +42,7 @@ import hudson.scm.PollingResult.Change; import hudson.util.EditDistance; import hudson.util.StreamTaskListener; import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.Option; import java.util.Map; @@ -90,7 +91,7 @@ public class BuildCommand extends CLICommand { @Option(name="-r") @Deprecated public int retryCnt = 10; - protected static final String BUILD_SCHEDULING_REFUSED = "Build scheduling Refused by an extension, hence not in Queue"; + protected static final String BUILD_SCHEDULING_REFUSED = "Build scheduling Refused by an extension, hence not in Queue."; protected int run() throws Exception { job.checkPermission(Item.BUILD); @@ -99,7 +100,7 @@ public class BuildCommand extends CLICommand { if (!parameters.isEmpty()) { ParametersDefinitionProperty pdp = job.getProperty(ParametersDefinitionProperty.class); if (pdp==null) - throw new AbortException(job.getFullDisplayName()+" is not parameterized but the -p option was specified"); + throw new IllegalStateException(job.getFullDisplayName()+" is not parameterized but the -p option was specified."); //TODO: switch to type annotations after the migration to Java 1.8 List values = new ArrayList(); @@ -108,12 +109,14 @@ public class BuildCommand extends CLICommand { String name = e.getKey(); ParameterDefinition pd = pdp.getParameterDefinition(name); if (pd==null) { - throw new AbortException(String.format("\'%s\' is not a valid parameter. Did you mean %s?", - name, EditDistance.findNearest(name, pdp.getParameterDefinitionNames()))); + String nearest = EditDistance.findNearest(name, pdp.getParameterDefinitionNames()); + throw new CmdLineException(null, nearest == null ? + String.format("'%s' is not a valid parameter.", name) : + String.format("'%s' is not a valid parameter. Did you mean %s?", name, nearest)); } ParameterValue val = pd.createValue(this, Util.fixNull(e.getValue())); if (val == null) { - throw new AbortException(String.format("Cannot resolve the value for the parameter \'%s\'.",name)); + throw new CmdLineException(null, String.format("Cannot resolve the value for the parameter '%s'.",name)); } values.add(val); } @@ -126,7 +129,7 @@ public class BuildCommand extends CLICommand { // not passed in use default ParameterValue defaultValue = pd.getDefaultParameterValue(); if (defaultValue == null) { - throw new AbortException(String.format("No default value for the parameter \'%s\'.",pd.getName())); + throw new CmdLineException(null, String.format("No default value for the parameter '%s'.",pd.getName())); } values.add(defaultValue); } @@ -147,16 +150,14 @@ public class BuildCommand extends CLICommand { } else if (job.isHoldOffBuildUntilSave()){ msg = Messages.BuildCommand_CLICause_CannotBuildConfigNotSaved(job.getFullDisplayName()); } - stderr.println(msg); - return -1; + throw new IllegalStateException(msg); } QueueTaskFuture f = job.scheduleBuild2(0, new CLICause(Jenkins.getAuthentication().getName()), a); if (wait || sync || follow) { if (f == null) { - stderr.println(BUILD_SCHEDULING_REFUSED); - return -1; + throw new IllegalStateException(BUILD_SCHEDULING_REFUSED); } AbstractBuild b = f.waitForStart(); // wait for the start stdout.println("Started "+b.getFullDisplayName()); @@ -177,7 +178,9 @@ public class BuildCommand extends CLICommand { } catch (FileNotFoundException e) { if ( i == retryCnt ) { - throw e; + Exception myException = new AbortException(); + myException.initCause(e); + throw myException; } i++; Thread.sleep(retryInterval); @@ -193,7 +196,9 @@ public class BuildCommand extends CLICommand { } else { // if the CLI is aborted, try to abort the build as well f.cancel(true); - throw e; + Exception myException = new AbortException(); + myException.initCause(e); + throw myException; } } } @@ -214,9 +219,9 @@ public class BuildCommand extends CLICommand { "With the -f option, this command changes the exit code based on\n" + "the outcome of the build (exit code 0 indicates a success)\n" + "however, unlike -s, interrupting the command will not interrupt\n" + - "the job (exit code 125 indicates the command was interrupted)\n" + + "the job (exit code 125 indicates the command was interrupted).\n" + "With the -c option, a build will only run if there has been\n" + - "an SCM change" + "an SCM change." ); } diff --git a/core/src/main/java/hudson/cli/CLIAction.java b/core/src/main/java/hudson/cli/CLIAction.java index 3253fc2840074f4674e69d3f45456716f0692fcd..d1973761d234d251a5f98ee12d3dbfed3ec5d313 100644 --- a/core/src/main/java/hudson/cli/CLIAction.java +++ b/core/src/main/java/hudson/cli/CLIAction.java @@ -71,7 +71,7 @@ public class CLIAction implements UnprotectedRootAction, StaplerProxy { } public void doCommand(StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException { - final Jenkins jenkins = Jenkins.getInstance(); + final Jenkins jenkins = Jenkins.getActiveInstance(); jenkins.checkPermission(Jenkins.READ); // Strip trailing slash @@ -112,7 +112,7 @@ public class CLIAction implements UnprotectedRootAction, StaplerProxy { FullDuplexHttpChannel server; if(req.getHeader("Side").equals("download")) { - duplexChannels.put(uuid,server=new FullDuplexHttpChannel(uuid, !Jenkins.getInstance().hasPermission(Jenkins.ADMINISTER)) { + duplexChannels.put(uuid,server=new FullDuplexHttpChannel(uuid, !Jenkins.getActiveInstance().hasPermission(Jenkins.ADMINISTER)) { @Override protected void main(Channel channel) throws IOException, InterruptedException { // capture the identity given by the transport, since this can be useful for SecurityRealm.createCliAuthenticator() diff --git a/core/src/main/java/hudson/cli/CLICommand.java b/core/src/main/java/hudson/cli/CLICommand.java index a40a8b5bac1175fb1dfe2a6ade5a26f37d319deb..2272ef64bd5538326e52a5b1646604c68e3ae2c9 100644 --- a/core/src/main/java/hudson/cli/CLICommand.java +++ b/core/src/main/java/hudson/cli/CLICommand.java @@ -195,7 +195,7 @@ public abstract class CLICommand implements ExtensionPoint, Cloneable { * to an empty method. * You would however then have to consider {@link CliAuthenticator} and {@link #getTransportAuthentication}, * so this is not really recommended. - * + * * @param args * Arguments to the sub command. For example, if the CLI is invoked like "java -jar cli.jar foo bar zot", * then "foo" is the sub-command and the argument list is ["bar","zot"]. @@ -209,7 +209,23 @@ public abstract class CLICommand implements ExtensionPoint, Cloneable { * @param stderr * Connected to the stderr of the CLI client. * @return - * Exit code from the command. + * Exit code from the CLI command execution + * + *

+ * Jenkins standard exit codes from CLI: + * 0 means everything went well. + * 1 means further unspecified exception is thrown while performing the command. + * 2 means CmdLineException is thrown while performing the command. + * 3 means IllegalArgumentException is thrown while performing the command. + * 4 mean IllegalStateException is thrown while performing the command. + * 5 means AbortException is thrown while performing the command. + * 6 means AccessDeniedException is thrown while performing the command. + * 7 means BadCredentialsException is thrown while performing the command. + * 8-15 are reserved for future usage + * 16+ mean a custom CLI exit error code (meaning defined by the CLI command itself) + * + *

+ * Note: For details - see JENKINS-32273 */ public int main(List args, Locale locale, InputStream stdin, PrintStream stdout, PrintStream stderr) { this.stdin = new BufferedInputStream(stdin); @@ -220,49 +236,65 @@ public abstract class CLICommand implements ExtensionPoint, Cloneable { CmdLineParser p = getCmdLineParser(); // add options from the authenticator - SecurityContext sc = SecurityContextHolder.getContext(); - Authentication old = sc.getAuthentication(); + SecurityContext sc = null; + Authentication old = null; + try { + sc = SecurityContextHolder.getContext(); + old = sc.getAuthentication(); - CliAuthenticator authenticator = Jenkins.getInstance().getSecurityRealm().createCliAuthenticator(this); - sc.setAuthentication(getTransportAuthentication()); - new ClassParser().parse(authenticator,p); + CliAuthenticator authenticator = Jenkins.getActiveInstance().getSecurityRealm().createCliAuthenticator(this); + sc.setAuthentication(getTransportAuthentication()); + new ClassParser().parse(authenticator,p); - try { p.parseArgument(args.toArray(new String[args.size()])); Authentication auth = authenticator.authenticate(); if (auth==Jenkins.ANONYMOUS) auth = loadStoredAuthentication(); sc.setAuthentication(auth); // run the CLI with the right credential if (!(this instanceof LoginCommand || this instanceof HelpCommand)) - Jenkins.getInstance().checkPermission(Jenkins.READ); + Jenkins.getActiveInstance().checkPermission(Jenkins.READ); return run(); } catch (CmdLineException e) { - stderr.println(e.getMessage()); + stderr.println(""); + stderr.println("ERROR: " + e.getMessage()); printUsage(stderr, p); - return -1; - } catch (AccessDeniedException e) { - stderr.println(e.getMessage()); - return -1; + return 2; + } catch (IllegalStateException e) { + stderr.println(""); + stderr.println("ERROR: " + e.getMessage()); + return 4; + } catch (IllegalArgumentException e) { + stderr.println(""); + stderr.println("ERROR: " + e.getMessage()); + return 3; } catch (AbortException e) { // signals an error without stack trace - stderr.println(e.getMessage()); - return -1; + stderr.println(""); + stderr.println("ERROR: " + e.getMessage()); + return 5; + } catch (AccessDeniedException e) { + stderr.println(""); + stderr.println("ERROR: " + e.getMessage()); + return 6; } catch (BadCredentialsException e) { // to the caller, we can't reveal whether the user didn't exist or the password didn't match. // do that to the server log instead String id = UUID.randomUUID().toString(); - LOGGER.log(Level.INFO, "CLI login attempt failed: "+id, e); - stderr.println("Bad Credentials. Search the server log for "+id+" for more details."); - return -1; - } catch (Exception e) { - final String errorMsg = String.format("Unexpected exception occurred while performing %s command!", + LOGGER.log(Level.INFO, "CLI login attempt failed: " + id, e); + stderr.println(""); + stderr.println("ERROR: Bad Credentials. Search the server log for " + id + " for more details."); + return 7; + } catch (Throwable e) { + final String errorMsg = String.format("Unexpected exception occurred while performing %s command.", getName()); - stderr.println(errorMsg); + stderr.println(""); + stderr.println("ERROR: " + errorMsg); LOGGER.log(Level.WARNING, errorMsg, e); e.printStackTrace(stderr); - return -1; + return 1; } finally { - sc.setAuthentication(old); // restore + if(sc != null) + sc.setAuthentication(old); // restore } } @@ -351,13 +383,22 @@ public abstract class CLICommand implements ExtensionPoint, Cloneable { * To execute CLI method from outside, use {@link #main(List, Locale, InputStream, PrintStream, PrintStream)} * * @return - * 0 to indicate a success, otherwise an error code. - * @throws AbortException - * If the processing should be aborted. Hudson will report the error message - * without stack trace, and then exits this command. + * 0 to indicate a success, otherwise a custom error code. + * Error codes 1-15 shouldn;t be used in {@link #run()} as a custom error code. * @throws Exception - * All the other exceptions cause the stack trace to be dumped, and then - * the command exits with an error code. + * If a further unspecified exception is thrown; means: Unknown and/or unexpected issue occurred + * @throws CmdLineException + * If a wrong parameter specified, input value can't be decoded etc. + * @throws IllegalArgumentException + * If the execution can't continue due to wrong input parameter (job doesn't exist etc.) + * @throws IllegalStateException + * If the execution can't continue due to an incorect state of Jenkins, job, build etc. + * @throws AbortException + * If the execution can't continue due to an other (rare, but foreseeable) issue + * @throws AccessDeniedException + * If the caller doesn't have sufficent rights for requested action + * @throws BadCredentialsException + * If bad credentials were provided to CLI */ protected abstract int run() throws Exception; @@ -494,7 +535,7 @@ public abstract class CLICommand implements ExtensionPoint, Cloneable { */ protected void registerOptionHandlers() { try { - for (Class c : Index.list(OptionHandlerExtension.class, Jenkins.getInstance().pluginManager.uberClassLoader,Class.class)) { + for (Class c : Index.list(OptionHandlerExtension.class, Jenkins.getActiveInstance().pluginManager.uberClassLoader,Class.class)) { Type t = Types.getBaseClass(c, OptionHandler.class); CmdLineParser.registerHandler(Types.erasure(Types.getTypeArgument(t,0)), c); } @@ -546,7 +587,7 @@ public abstract class CLICommand implements ExtensionPoint, Cloneable { static { // register option handlers that are defined ClassLoaders cls = new ClassLoaders(); - Jenkins j = Jenkins.getInstance(); + Jenkins j = Jenkins.getActiveInstance(); if (j!=null) {// only when running on the master cls.put(j.getPluginManager().uberClassLoader); diff --git a/core/src/main/java/hudson/cli/CliProtocol.java b/core/src/main/java/hudson/cli/CliProtocol.java index eecb4c5faf9da881203b3668cbfd9fe23f330182..99cdd172d17712b0d19da7ab5ff08e697df74a05 100644 --- a/core/src/main/java/hudson/cli/CliProtocol.java +++ b/core/src/main/java/hudson/cli/CliProtocol.java @@ -77,7 +77,7 @@ public class CliProtocol extends AgentProtocol { Channel channel = cb .withMode(Mode.BINARY) .withRestricted(true) - .withBaseLoader(Jenkins.getInstance().pluginManager.uberClassLoader) + .withBaseLoader(Jenkins.getActiveInstance().pluginManager.uberClassLoader) .build(new BufferedInputStream(c.in), new BufferedOutputStream(c.out)); channel.setProperty(CliEntryPoint.class.getName(),new CliManagerImpl(channel)); diff --git a/core/src/main/java/hudson/cli/CliProtocol2.java b/core/src/main/java/hudson/cli/CliProtocol2.java index 0f2757df786b7dc72c0e8d4e59528aa79df4e6ad..1be9fff35b87bbb5c039ff13eb634b73a0dd4ded 100644 --- a/core/src/main/java/hudson/cli/CliProtocol2.java +++ b/core/src/main/java/hudson/cli/CliProtocol2.java @@ -60,7 +60,7 @@ public class CliProtocol2 extends CliProtocol { try { // HACK: TODO: move the transport support into modules - Class cls = Jenkins.getInstance().pluginManager.uberClassLoader.loadClass("org.jenkinsci.main.modules.instance_identity.InstanceIdentity"); + Class cls = Jenkins.getActiveInstance().pluginManager.uberClassLoader.loadClass("org.jenkinsci.main.modules.instance_identity.InstanceIdentity"); Object iid = cls.getDeclaredMethod("get").invoke(null); PrivateKey instanceId = (PrivateKey)cls.getDeclaredMethod("getPrivate").invoke(iid); diff --git a/core/src/main/java/hudson/cli/ClientAuthenticationCache.java b/core/src/main/java/hudson/cli/ClientAuthenticationCache.java index b00b816d37d6e0391a307584480dfeccb6da0983..1f33b8337666701c589dcb73b242129ada5825bc 100644 --- a/core/src/main/java/hudson/cli/ClientAuthenticationCache.java +++ b/core/src/main/java/hudson/cli/ClientAuthenticationCache.java @@ -66,7 +66,7 @@ public class ClientAuthenticationCache implements Serializable { * @return {@link jenkins.model.Jenkins#ANONYMOUS} if no such credential is found, or if the stored credential is invalid. */ public Authentication get() { - Jenkins h = Jenkins.getInstance(); + Jenkins h = Jenkins.getActiveInstance(); Secret userName = Secret.decrypt(props.getProperty(getPropertyKey())); if (userName==null) return Jenkins.ANONYMOUS; // failed to decrypt try { @@ -83,7 +83,7 @@ public class ClientAuthenticationCache implements Serializable { * Computes the key that identifies this Hudson among other Hudsons that the user has a credential for. */ private String getPropertyKey() { - String url = Jenkins.getInstance().getRootUrl(); + String url = Jenkins.getActiveInstance().getRootUrl(); if (url!=null) return url; return Secret.fromString("key").toString(); } @@ -92,7 +92,7 @@ public class ClientAuthenticationCache implements Serializable { * Persists the specified authentication. */ public void set(Authentication a) throws IOException, InterruptedException { - Jenkins h = Jenkins.getInstance(); + Jenkins h = Jenkins.getActiveInstance(); // make sure that this security realm is capable of retrieving the authentication by name, // as it's not required. diff --git a/core/src/main/java/hudson/cli/CommandDuringBuild.java b/core/src/main/java/hudson/cli/CommandDuringBuild.java index 3834238a41fafb0b9f951e30880bca5144709ccc..59f5329faafd04ba98ccbeb128d4449f704ac584 100644 --- a/core/src/main/java/hudson/cli/CommandDuringBuild.java +++ b/core/src/main/java/hudson/cli/CommandDuringBuild.java @@ -45,7 +45,7 @@ public abstract class CommandDuringBuild extends CLICommand { protected Run getCurrentlyBuilding() throws CmdLineException { Run r = optCurrentlyBuilding(); if (r==null) - throw new CmdLineException("This CLI command works only when invoked from inside a build"); + throw new IllegalStateException("This CLI command works only when invoked from inside a build"); return r; } @@ -55,29 +55,32 @@ public abstract class CommandDuringBuild extends CLICommand { protected Run optCurrentlyBuilding() throws CmdLineException { try { CLICommand c = CLICommand.getCurrent(); - if (c==null) throw new IllegalStateException("Not executing a CLI command"); + if (c==null) + throw new IllegalStateException("Not executing a CLI command"); String[] envs = c.checkChannel().call(new GetCharacteristicEnvironmentVariables()); if (envs[0]==null || envs[1]==null) return null; - Job j = Jenkins.getInstance().getItemByFullName(envs[0],Job.class); - if (j==null) throw new CmdLineException("No such job: "+envs[0]); + Job j = Jenkins.getActiveInstance().getItemByFullName(envs[0],Job.class); + if (j==null) + throw new IllegalArgumentException("No such job: "+envs[0]); try { Run r = j.getBuildByNumber(Integer.parseInt(envs[1])); - if (r==null) throw new CmdLineException("No such build #"+envs[1]+" in "+envs[0]); + if (r==null) + throw new IllegalArgumentException("No such build #"+envs[1]+" in "+envs[0]); if (!r.isBuilding()) { - throw new CmdLineException(r + " is not currently being built"); + throw new IllegalStateException(r + " is not currently being built"); } return r; } catch (NumberFormatException e) { - throw new CmdLineException("Invalid build number: "+envs[1]); + throw new IllegalArgumentException("Invalid build number: "+envs[1]); } } catch (IOException e) { - throw new CmdLineException("Failed to identify the build being executed",e); + throw new IllegalArgumentException("Failed to identify the build being executed",e); } catch (InterruptedException e) { - throw new CmdLineException("Failed to identify the build being executed",e); + throw new IllegalArgumentException("Failed to identify the build being executed",e); } } diff --git a/core/src/main/java/hudson/cli/ConsoleCommand.java b/core/src/main/java/hudson/cli/ConsoleCommand.java index 5da97b0947b11846a0f282c7b9d0ca9685eba955..92fd0e74c6b80160c49136e3f9efc2bd4d91abc7 100644 --- a/core/src/main/java/hudson/cli/ConsoleCommand.java +++ b/core/src/main/java/hudson/cli/ConsoleCommand.java @@ -50,17 +50,20 @@ public class ConsoleCommand extends CLICommand { int n = Integer.parseInt(build); run = job.getBuildByNumber(n); if (run==null) - throw new CmdLineException("No such build #"+n); + throw new IllegalArgumentException("No such build #"+n); } catch (NumberFormatException e) { // maybe a permalink? Permalink p = job.getPermalinks().get(build); if (p!=null) { run = (AbstractBuild)p.resolve(job); if (run==null) - throw new CmdLineException("Permalink "+build+" produced no build"); + throw new IllegalStateException("Permalink "+build+" produced no build"); } else { Permalink nearest = job.getPermalinks().findNearest(build); - throw new CmdLineException(String.format("Not sure what you meant by \"%s\". Did you mean \"%s\"?", build, nearest.getId())); + throw new IllegalArgumentException(nearest == null ? + String.format("Not sure what you meant by \"%s\".", build) : + String.format("Not sure what you meant by \"%s\". Did you mean \"%s\"?", + build, nearest.getId())); } } diff --git a/core/src/main/java/hudson/cli/CopyJobCommand.java b/core/src/main/java/hudson/cli/CopyJobCommand.java index 7d83fa99a076ec00c7228c6e4b58b7f562d111ff..3eb8049c1f723ee81963a34550eaa01db554a1af 100644 --- a/core/src/main/java/hudson/cli/CopyJobCommand.java +++ b/core/src/main/java/hudson/cli/CopyJobCommand.java @@ -50,11 +50,10 @@ public class CopyJobCommand extends CLICommand { public String dst; protected int run() throws Exception { - Jenkins jenkins = Jenkins.getInstance(); + Jenkins jenkins = Jenkins.getActiveInstance(); if (jenkins.getItemByFullName(dst)!=null) { - stderr.println("Job '"+dst+"' already exists"); - return -1; + throw new IllegalStateException("Job '"+dst+"' already exists"); } ModifiableTopLevelItemGroup ig = jenkins; @@ -69,7 +68,7 @@ public class CopyJobCommand extends CLICommand { if (item instanceof ModifiableTopLevelItemGroup) { ig = (ModifiableTopLevelItemGroup) item; } else { - throw new IllegalArgumentException("Can't create job from CLI in " + group); + throw new IllegalStateException("Can't create job from CLI in " + group); } dst = dst.substring(i + 1); } diff --git a/core/src/main/java/hudson/cli/CreateJobCommand.java b/core/src/main/java/hudson/cli/CreateJobCommand.java index 1e1b807c5ee257880a094a74c8d8bde7dc3db83d..0f0108c361b67c490db7c0d911f79bc07cbfb267 100644 --- a/core/src/main/java/hudson/cli/CreateJobCommand.java +++ b/core/src/main/java/hudson/cli/CreateJobCommand.java @@ -45,11 +45,10 @@ public class CreateJobCommand extends CLICommand { public String name; protected int run() throws Exception { - Jenkins h = Jenkins.getInstance(); + Jenkins h = Jenkins.getActiveInstance(); if (h.getItemByFullName(name)!=null) { - stderr.println("Job '"+name+"' already exists"); - return -1; + throw new IllegalStateException("Job '"+name+"' already exists"); } ModifiableTopLevelItemGroup ig = h; @@ -64,7 +63,7 @@ public class CreateJobCommand extends CLICommand { if (item instanceof ModifiableTopLevelItemGroup) { ig = (ModifiableTopLevelItemGroup) item; } else { - throw new IllegalArgumentException("Can't create job from CLI in " + group); + throw new IllegalStateException("Can't create job from CLI in " + group); } name = name.substring(i + 1); } diff --git a/core/src/main/java/hudson/cli/CreateNodeCommand.java b/core/src/main/java/hudson/cli/CreateNodeCommand.java index b7ccac632fe260a0b8bc55ee10743a975e72a9bf..6a7f6dee7698cf6f5f4dddeb2167dd5df003a51f 100644 --- a/core/src/main/java/hudson/cli/CreateNodeCommand.java +++ b/core/src/main/java/hudson/cli/CreateNodeCommand.java @@ -53,7 +53,7 @@ public class CreateNodeCommand extends CLICommand { @Override protected int run() throws Exception { - final Jenkins jenkins = Jenkins.getInstance(); + final Jenkins jenkins = Jenkins.getActiveInstance(); jenkins.checkPermission(Computer.CREATE); final Node newNode = (Node) Jenkins.XSTREAM2.fromXML(stdin); @@ -70,10 +70,7 @@ public class CreateNodeCommand extends CLICommand { } if (jenkins.getNode(newNode.getNodeName()) != null) { - - throw new CmdLineException( - null, "Node '" + newNode.getNodeName() + "' already exists" - ); + throw new IllegalStateException("Node '" + newNode.getNodeName() + "' already exists"); } jenkins.addNode(newNode); diff --git a/core/src/main/java/hudson/cli/CreateViewCommand.java b/core/src/main/java/hudson/cli/CreateViewCommand.java index 73fd374b854195f0d96de49f582f61c364509b32..d22a0b424f68a2e2926bd1b19cfa094735ea6b4a 100644 --- a/core/src/main/java/hudson/cli/CreateViewCommand.java +++ b/core/src/main/java/hudson/cli/CreateViewCommand.java @@ -49,7 +49,7 @@ public class CreateViewCommand extends CLICommand { @Override protected int run() throws Exception { - final Jenkins jenkins = Jenkins.getInstance(); + final Jenkins jenkins = Jenkins.getActiveInstance(); jenkins.checkPermission(View.CREATE); View newView; @@ -57,16 +57,12 @@ public class CreateViewCommand extends CLICommand { newView = View.createViewFromXML(viewName, stdin); } catch (Failure ex) { - - stderr.format("Invalid view name: %s\n", ex.getMessage()); - return -1; + throw new IllegalArgumentException("Invalid view name: " + ex.getMessage()); } final String newName = newView.getViewName(); if (jenkins.getView(newName) != null) { - - stderr.format("View '%s' already exists\n", newName); - return -1; + throw new IllegalStateException("View '" + newName + "' already exists"); } jenkins.addView(newView); diff --git a/core/src/main/java/hudson/cli/DeleteJobCommand.java b/core/src/main/java/hudson/cli/DeleteJobCommand.java index 361d889bccdd376eae9a0e4cc8db0215bcb74b6f..127ec43f6c59672859aa45f589290b9b3c15a28b 100644 --- a/core/src/main/java/hudson/cli/DeleteJobCommand.java +++ b/core/src/main/java/hudson/cli/DeleteJobCommand.java @@ -23,6 +23,7 @@ */ package hudson.cli; +import hudson.AbortException; import hudson.Extension; import hudson.model.AbstractItem; import jenkins.model.Jenkins; @@ -42,8 +43,6 @@ public class DeleteJobCommand extends CLICommand { @Argument(usage="Name of the job(s) to delete", required=true, multiValued=true) private List jobs; - private static final Logger LOGGER = Logger.getLogger(DeleteJobCommand.class.getName()); - @Override public String getShortDescription() { @@ -54,12 +53,7 @@ public class DeleteJobCommand extends CLICommand { protected int run() throws Exception { boolean errorOccurred = false; - final Jenkins jenkins = Jenkins.getInstance(); - - if (jenkins == null) { - stderr.println("The Jenkins instance has not been started, or was already shut down!"); - return -1; - } + final Jenkins jenkins = Jenkins.getActiveInstance(); final HashSet hs = new HashSet(); hs.addAll(jobs); @@ -71,31 +65,26 @@ public class DeleteJobCommand extends CLICommand { job = (AbstractItem) jenkins.getItemByFullName(job_s); if(job == null) { - stderr.format("No such job '%s'\n", job_s); - errorOccurred = true; - continue; - } - - try { - job.checkPermission(AbstractItem.DELETE); - } catch (Exception e) { - stderr.println(e.getMessage()); - errorOccurred = true; - continue; + throw new IllegalArgumentException("No such job '" + job_s + "'"); } + job.checkPermission(AbstractItem.DELETE); job.delete(); } catch (Exception e) { - final String errorMsg = String.format("Unexpected exception occurred during deletion of job '%s': %s", - job == null ? "(null)" : job.getFullName(), - e.getMessage()); + if(hs.size() == 1) { + throw e; + } + + final String errorMsg = String.format(job_s + ": " + e.getMessage()); stderr.println(errorMsg); - LOGGER.warning(errorMsg); errorOccurred = true; - //noinspection UnnecessaryContinue continue; } } - return errorOccurred ? -1 : 0; + + if (errorOccurred) { + throw new AbortException("Error occured while performing this command, see previous stderr output."); + } + return 0; } } diff --git a/core/src/main/java/hudson/cli/DeleteNodeCommand.java b/core/src/main/java/hudson/cli/DeleteNodeCommand.java index 4d48e2b78f14cb5e618321d50858ee395c080e11..5fc70fc764aba7388f3a265e9f410bdcd2818ad0 100644 --- a/core/src/main/java/hudson/cli/DeleteNodeCommand.java +++ b/core/src/main/java/hudson/cli/DeleteNodeCommand.java @@ -23,9 +23,9 @@ */ package hudson.cli; +import hudson.AbortException; import hudson.Extension; import hudson.model.Node; -import org.acegisecurity.AccessDeniedException; import jenkins.model.Jenkins; import org.kohsuke.args4j.Argument; @@ -43,8 +43,6 @@ public class DeleteNodeCommand extends CLICommand { @Argument(usage="Nodes name to delete", required=true, multiValued=true) private List nodes; - private static final Logger LOGGER = Logger.getLogger(DeleteNodeCommand.class.getName()); - @Override public String getShortDescription() { @@ -55,12 +53,7 @@ public class DeleteNodeCommand extends CLICommand { protected int run() throws Exception { boolean errorOccurred = false; - final Jenkins jenkins = Jenkins.getInstance(); - - if (jenkins == null) { - stderr.println("The Jenkins instance has not been started, or was already shut down!"); - return -1; - } + final Jenkins jenkins = Jenkins.getActiveInstance(); final HashSet hs = new HashSet(); hs.addAll(nodes); @@ -71,29 +64,26 @@ public class DeleteNodeCommand extends CLICommand { try { node = jenkins.getNode(node_s); - if(node == null) { - stderr.format("No such node '%s'\n", node_s); - errorOccurred = true; - continue; + if (node == null) { + throw new IllegalArgumentException("No such node '" + node_s + "'"); } node.toComputer().doDoDelete(); - } catch (AccessDeniedException e) { - stderr.println(e.getMessage()); - errorOccurred = true; - //noinspection UnnecessaryContinue - continue; } catch (Exception e) { - final String errorMsg = String.format("Unexpected exception occurred during deletion of node '%s': %s", - node == null ? "(null)" : node.toComputer().getName(), - e.getMessage()); + if(hs.size() == 1) { + throw e; + } + + final String errorMsg = String.format(node_s + ": " + e.getMessage()); stderr.println(errorMsg); - LOGGER.warning(errorMsg); errorOccurred = true; - //noinspection UnnecessaryContinue continue; } } - return errorOccurred ? -1 : 0; + + if (errorOccurred) { + throw new AbortException("Error occured while performing this command, see previous stderr output."); + } + return 0; } } diff --git a/core/src/main/java/hudson/cli/DeleteViewCommand.java b/core/src/main/java/hudson/cli/DeleteViewCommand.java index 4c86edeb70221ed239d4d973371430ce792cccbe..900e9cdc915b04028574cbbdd5300f79bee2bb69 100644 --- a/core/src/main/java/hudson/cli/DeleteViewCommand.java +++ b/core/src/main/java/hudson/cli/DeleteViewCommand.java @@ -23,6 +23,7 @@ */ package hudson.cli; +import hudson.AbortException; import hudson.Extension; import hudson.cli.handlers.ViewOptionHandler; import hudson.model.ViewGroup; @@ -44,8 +45,6 @@ public class DeleteViewCommand extends CLICommand { @Argument(usage="View names to delete", required=true, multiValued=true) private List views; - private static final Logger LOGGER = Logger.getLogger(DeleteViewCommand.class.getName()); - @Override public String getShortDescription() { @@ -67,42 +66,37 @@ public class DeleteViewCommand extends CLICommand { View view = null; try { - try { - view = voh.getView(view_s); - if (view == null) { - stderr.println("user is missing the View/Read permission"); - errorOccurred = true; - continue; - } - view.checkPermission(View.DELETE); - } catch (Exception e) { - stderr.println(e.getMessage()); - errorOccurred = true; - continue; + view = voh.getView(view_s); + + if (view == null) { + throw new IllegalArgumentException("View name is empty"); } + view.checkPermission(View.DELETE); + ViewGroup group = view.getOwner(); if (!group.canDelete(view)) { - stderr.format("%s does not allow to delete '%s' view\n", + throw new IllegalStateException(String.format("%s does not allow to delete '%s' view", group.getDisplayName(), - view.getViewName() - ); - errorOccurred = true; - continue; + view.getViewName())); } group.deleteView(view); } catch (Exception e) { - final String errorMsg = String.format("Unexpected exception occurred during deletion of view '%s': %s", - view == null ? "(null)" : view.getViewName(), - e.getMessage()); + if(hs.size() == 1) { + throw e; + } + + final String errorMsg = String.format(view_s + ": " + e.getMessage()); stderr.println(errorMsg); - LOGGER.warning(errorMsg); errorOccurred = true; - //noinspection UnnecessaryContinue continue; } } - return errorOccurred ? -1 : 0; + + if (errorOccurred) { + throw new AbortException("Error occured while performing this command, see previous stderr output."); + } + return 0; } } diff --git a/core/src/main/java/hudson/cli/GroovyCommand.java b/core/src/main/java/hudson/cli/GroovyCommand.java index a77f41fd92057bf0c9561759646c3abe8e080881..144c2dfe0cfe9d846e73c54cc77b4ab350af95b2 100644 --- a/core/src/main/java/hudson/cli/GroovyCommand.java +++ b/core/src/main/java/hudson/cli/GroovyCommand.java @@ -63,7 +63,7 @@ public class GroovyCommand extends CLICommand { protected int run() throws Exception { // this allows the caller to manipulate the JVM state, so require the execute script privilege. - Jenkins.getInstance().checkPermission(Jenkins.RUN_SCRIPTS); + Jenkins.getActiveInstance().checkPermission(Jenkins.RUN_SCRIPTS); Binding binding = new Binding(); binding.setProperty("out",new PrintWriter(stdout,true)); @@ -73,7 +73,7 @@ public class GroovyCommand extends CLICommand { binding.setProperty("channel",channel); String j = getClientEnvironmentVariable("JOB_NAME"); if (j!=null) { - Item job = Jenkins.getInstance().getItemByFullName(j); + Item job = Jenkins.getActiveInstance().getItemByFullName(j); binding.setProperty("currentJob", job); String b = getClientEnvironmentVariable("BUILD_NUMBER"); if (b!=null && job instanceof AbstractProject) { @@ -82,7 +82,7 @@ public class GroovyCommand extends CLICommand { } } - GroovyShell groovy = new GroovyShell(Jenkins.getInstance().getPluginManager().uberClassLoader, binding); + GroovyShell groovy = new GroovyShell(Jenkins.getActiveInstance().getPluginManager().uberClassLoader, binding); groovy.run(loadScript(),"RemoteClass",remaining.toArray(new String[remaining.size()])); return 0; } diff --git a/core/src/main/java/hudson/cli/GroovyshCommand.java b/core/src/main/java/hudson/cli/GroovyshCommand.java index 48babcb90dbc98a2ca04941813357fec51505427..6299c60576b0a6fee0eac0763fe70cbf92ecf65e 100644 --- a/core/src/main/java/hudson/cli/GroovyshCommand.java +++ b/core/src/main/java/hudson/cli/GroovyshCommand.java @@ -61,7 +61,7 @@ public class GroovyshCommand extends CLICommand { @Override protected int run() { // this allows the caller to manipulate the JVM state, so require the admin privilege. - Jenkins.getInstance().checkPermission(Jenkins.RUN_SCRIPTS); + Jenkins.getActiveInstance().checkPermission(Jenkins.RUN_SCRIPTS); // this being remote means no jline capability is available System.setProperty("jline.terminal", UnsupportedTerminal.class.getName()); @@ -78,12 +78,12 @@ public class GroovyshCommand extends CLICommand { Binding binding = new Binding(); // redirect "println" to the CLI binding.setProperty("out", new PrintWriter(stdout,true)); - binding.setProperty("hudson", Jenkins.getInstance()); // backward compatibility - binding.setProperty("jenkins", Jenkins.getInstance()); + binding.setProperty("hudson", Jenkins.getActiveInstance()); // backward compatibility + binding.setProperty("jenkins", Jenkins.getActiveInstance()); IO io = new IO(new BufferedInputStream(stdin),stdout,stderr); - final ClassLoader cl = Jenkins.getInstance().pluginManager.uberClassLoader; + final ClassLoader cl = Jenkins.getActiveInstance().pluginManager.uberClassLoader; Closure registrar = new Closure(null, null) { private static final long serialVersionUID = 1L; diff --git a/core/src/main/java/hudson/cli/HelpCommand.java b/core/src/main/java/hudson/cli/HelpCommand.java index bebb39dfcd9ce8aff1f1fb1a42c685e9ce941899..295e6e0e8e966f9e724d4eda231dff37b1e0952f 100644 --- a/core/src/main/java/hudson/cli/HelpCommand.java +++ b/core/src/main/java/hudson/cli/HelpCommand.java @@ -23,12 +23,14 @@ */ package hudson.cli; +import hudson.AbortException; import hudson.Extension; import jenkins.model.Jenkins; import java.util.Map; import java.util.TreeMap; +import org.acegisecurity.AccessDeniedException; import org.kohsuke.args4j.Argument; /** @@ -48,11 +50,10 @@ public class HelpCommand extends CLICommand { } @Override - protected int run() { - if (!Jenkins.getInstance().hasPermission(Jenkins.READ)) { - stderr.println("You must authenticate to access this Jenkins.\n" + protected int run() throws Exception { + if (!Jenkins.getActiveInstance().hasPermission(Jenkins.READ)) { + throw new AccessDeniedException("You must authenticate to access this Jenkins.\n" + "Use --username/--password/--password-file parameters or login command."); - return -1; } if (command != null) @@ -76,12 +77,11 @@ public class HelpCommand extends CLICommand { return 0; } - private int showCommandDetails() { + private int showCommandDetails() throws Exception { CLICommand command = CLICommand.clone(this.command); if (command == null) { - stderr.format("No such command %s. Awailable commands are: ", this.command); showAllCommands(); - return -1; + throw new AbortException(String.format("No such command %s. Available commands are above. ", this.command)); } command.printUsage(stderr, command.getCmdLineParser()); diff --git a/core/src/main/java/hudson/cli/InstallPluginCommand.java b/core/src/main/java/hudson/cli/InstallPluginCommand.java index 1fd23d81acba7de5c3a4050e4925c96b797934b9..21484e05bfe4333e77483f907903506ae7a05217 100644 --- a/core/src/main/java/hudson/cli/InstallPluginCommand.java +++ b/core/src/main/java/hudson/cli/InstallPluginCommand.java @@ -23,6 +23,7 @@ */ package hudson.cli; +import hudson.AbortException; import hudson.Extension; import hudson.FilePath; import hudson.PluginManager; @@ -57,20 +58,20 @@ public class InstallPluginCommand extends CLICommand { @Argument(metaVar="SOURCE",required=true,usage="If this points to a local file, that file will be installed. " + "If this is an URL, Jenkins downloads the URL and installs that as a plugin." + "Otherwise the name is assumed to be the short name of the plugin in the existing update center (like \"findbugs\")," + - "and the plugin will be installed from the update center") + "and the plugin will be installed from the update center.") public List sources = new ArrayList(); - @Option(name="-name",usage="If specified, the plugin will be installed as this short name (whereas normally the name is inferred from the source name automatically.)") + @Option(name="-name",usage="If specified, the plugin will be installed as this short name (whereas normally the name is inferred from the source name automatically).") public String name; - @Option(name="-restart",usage="Restart Jenkins upon successful installation") + @Option(name="-restart",usage="Restart Jenkins upon successful installation.") public boolean restart; @Option(name="-deploy",usage="Deploy plugins right away without postponing them until the reboot.") public boolean dynamicLoad; protected int run() throws Exception { - Jenkins h = Jenkins.getInstance(); + Jenkins h = Jenkins.getActiveInstance(); h.checkPermission(PluginManager.UPLOAD_PLUGINS); PluginManager pm = h.getPluginManager(); @@ -113,8 +114,11 @@ public class InstallPluginCommand extends CLICommand { if (p!=null) { stdout.println(Messages.InstallPluginCommand_InstallingFromUpdateCenter(source)); Throwable e = p.deploy(dynamicLoad).get().getError(); - if (e!=null) - throw new IOException("Failed to install plugin "+source,e); + if (e!=null) { + AbortException myException = new AbortException("Failed to install plugin " + source); + myException.initCause(e); + throw myException; + } continue; } @@ -137,7 +141,7 @@ public class InstallPluginCommand extends CLICommand { } } - return 1; + throw new AbortException("Error occurred, see previous output."); } if (restart) @@ -150,6 +154,6 @@ public class InstallPluginCommand extends CLICommand { } private File getTargetFile() { - return new File(Jenkins.getInstance().getPluginManager().rootDir,name+".jpi"); + return new File(Jenkins.getActiveInstance().getPluginManager().rootDir,name+".jpi"); } } diff --git a/core/src/main/java/hudson/cli/InstallToolCommand.java b/core/src/main/java/hudson/cli/InstallToolCommand.java index 7e0c37ac281beccff8a57a7db2c63dfaa5c6ab24..c387241f5a9066aadba2166f9faa4c23f6f8efd5 100644 --- a/core/src/main/java/hudson/cli/InstallToolCommand.java +++ b/core/src/main/java/hudson/cli/InstallToolCommand.java @@ -62,18 +62,18 @@ public class InstallToolCommand extends CLICommand { } protected int run() throws Exception { - Jenkins h = Jenkins.getInstance(); + Jenkins h = Jenkins.getActiveInstance(); h.checkPermission(Jenkins.READ); // where is this build running? BuildIDs id = checkChannel().call(new BuildIDs()); if (!id.isComplete()) - throw new AbortException("This command can be only invoked from a build executing inside Hudson"); + throw new IllegalStateException("This command can be only invoked from a build executing inside Hudson"); - AbstractProject p = Jenkins.getInstance().getItemByFullName(id.job, AbstractProject.class); + AbstractProject p = h.getItemByFullName(id.job, AbstractProject.class); if (p==null) - throw new AbortException("No such job found: "+id.job); + throw new IllegalStateException("No such job found: "+id.job); p.checkPermission(Item.CONFIGURE); List toolTypes = new ArrayList(); @@ -101,9 +101,9 @@ public class InstallToolCommand extends CLICommand { private int error(List candidates, String given, String noun) throws AbortException { if (given ==null) - throw new AbortException("No tool "+ noun +" was specified. Valid values are "+candidates.toString()); + throw new IllegalArgumentException("No tool "+ noun +" was specified. Valid values are "+candidates.toString()); else - throw new AbortException("Unrecognized tool "+noun+". Perhaps you meant '"+ EditDistance.findNearest(given,candidates)+"'?"); + throw new IllegalArgumentException("Unrecognized tool "+noun+". Perhaps you meant '"+ EditDistance.findNearest(given,candidates)+"'?"); } /** @@ -113,15 +113,15 @@ public class InstallToolCommand extends CLICommand { Run b = p.getBuildByNumber(Integer.parseInt(id.number)); if (b==null) - throw new AbortException("No such build: "+id.number); + throw new IllegalStateException("No such build: "+id.number); Executor exec = b.getExecutor(); if (exec==null) - throw new AbortException(b.getFullDisplayName()+" is not building"); + throw new IllegalStateException(b.getFullDisplayName()+" is not building"); Node node = exec.getOwner().getNode(); if (node == null) { - throw new AbortException("The node " + exec.getOwner().getDisplayName() + " has been deleted"); + throw new IllegalStateException("The node " + exec.getOwner().getDisplayName() + " has been deleted"); } t = t.translate(node, EnvVars.getRemote(checkChannel()), new StreamTaskListener(stderr)); diff --git a/core/src/main/java/hudson/cli/ListJobsCommand.java b/core/src/main/java/hudson/cli/ListJobsCommand.java index 97ea8d29671f992d942a72639dc604c99f654d2e..45b9661e283768f21de570287777570bf4a294d6 100644 --- a/core/src/main/java/hudson/cli/ListJobsCommand.java +++ b/core/src/main/java/hudson/cli/ListJobsCommand.java @@ -50,7 +50,7 @@ public class ListJobsCommand extends CLICommand { public String name; protected int run() throws Exception { - Jenkins h = Jenkins.getInstance(); + Jenkins h = Jenkins.getActiveInstance(); final Collection jobs; // If name is given retrieve jobs for the given view. @@ -70,8 +70,7 @@ public class ListJobsCommand extends CLICommand { } // No view and no item group with the given name found. else { - stderr.println("No view or item group with the given name found"); - return -1; + throw new IllegalArgumentException("No view or item group with the given name '" + name + "' found."); } } } diff --git a/core/src/main/java/hudson/cli/ListPluginsCommand.java b/core/src/main/java/hudson/cli/ListPluginsCommand.java index f21ea7e70152271f30f03398363472de2b1f0bf4..99c926cdaf1ef8c648ff1a339b6fdf61314497f2 100644 --- a/core/src/main/java/hudson/cli/ListPluginsCommand.java +++ b/core/src/main/java/hudson/cli/ListPluginsCommand.java @@ -47,7 +47,7 @@ public class ListPluginsCommand extends CLICommand { public String name; protected int run() { - Jenkins h = Jenkins.getInstance(); + Jenkins h = Jenkins.getActiveInstance(); PluginManager pluginManager = h.getPluginManager(); if (this.name != null) { @@ -57,7 +57,7 @@ public class ListPluginsCommand extends CLICommand { printPlugin(plugin, plugin.getShortName().length(), plugin.getDisplayName().length()); } else { - stderr.println(String.format("No plugin with the name '%s' found", this.name)); + throw new IllegalArgumentException("No plugin with the name '" + name + "' found"); } } else { diff --git a/core/src/main/java/hudson/cli/OnlineNodeCommand.java b/core/src/main/java/hudson/cli/OnlineNodeCommand.java index 2ed90c746165a26ffacb448327b6b440b72374a5..10bd1523d75c39003bd25cdb8362140d38980cf6 100644 --- a/core/src/main/java/hudson/cli/OnlineNodeCommand.java +++ b/core/src/main/java/hudson/cli/OnlineNodeCommand.java @@ -43,8 +43,6 @@ public class OnlineNodeCommand extends CLICommand { @Argument(metaVar="NAME", usage="Slave name, or empty string for master") public String computerName; - private static final Logger LOGGER = Logger.getLogger(OnlineNodeCommand.class.getName()); - @Override public String getShortDescription() { @@ -54,32 +52,17 @@ public class OnlineNodeCommand extends CLICommand { @Override protected int run() throws Exception { - boolean errorOccurred = false; - - final Jenkins jenkins = Jenkins.getInstance(); + final Jenkins jenkins = Jenkins.getActiveInstance(); Computer computer = jenkins.getComputer(computerName); if (computer == null) { - stderr.println(hudson.model.Messages.Computer_NoSuchSlaveExists(computerName, null)); - errorOccurred = true; + throw new IllegalArgumentException(hudson.model.Messages.Computer_NoSuchSlaveExists(computerName, null)); } else { - try { - computer.cliOnline(); - } catch (AccessDeniedException e) { - stderr.println(e.getMessage()); - errorOccurred = true; - } catch (Exception e) { - final String errorMsg = String.format("Unexpected exception occurred during performing online operation on node '%s': %s", - computer == null ? "(null)" : computer.getName(), - e.getMessage()); - stderr.println(errorMsg); - LOGGER.warning(errorMsg); - errorOccurred = true; - } + computer.cliOnline(); } - return errorOccurred ? 1 : 0; + return 0; } } diff --git a/core/src/main/java/hudson/cli/ReloadJobCommand.java b/core/src/main/java/hudson/cli/ReloadJobCommand.java index a8905b79e0c17df9fa857fa226332bf201b04765..800161b29be47ce3b4a7aa129eb8b64302a17efd 100644 --- a/core/src/main/java/hudson/cli/ReloadJobCommand.java +++ b/core/src/main/java/hudson/cli/ReloadJobCommand.java @@ -23,6 +23,7 @@ */ package hudson.cli; +import hudson.AbortException; import hudson.Extension; import hudson.model.AbstractItem; import hudson.model.AbstractProject; @@ -58,12 +59,7 @@ public class ReloadJobCommand extends CLICommand { protected int run() throws Exception { boolean errorOccurred = false; - final Jenkins jenkins = Jenkins.getInstance(); - - if (jenkins == null) { - stderr.println("The Jenkins instance has not been started, or was already shut down!"); - return -1; - } + final Jenkins jenkins = Jenkins.getActiveInstance(); final HashSet hs = new HashSet(); hs.addAll(jobs); @@ -83,35 +79,29 @@ public class ReloadJobCommand extends CLICommand { if(job == null) { // TODO: JENKINS-30785 AbstractProject project = AbstractProject.findNearest(job_s); - if(project == null) { - stderr.format("No such job \u2018%s\u2019 exists.\n", job_s); - } else { - stderr.format("No such job \u2018%s\u2019 exists. Perhaps you meant \u2018%s\u2019?", job_s, project.getFullName()); - } - errorOccurred = true; - continue; - } - - try { - job.checkPermission(AbstractItem.CONFIGURE); - } catch (Exception e) { - stderr.println(e.getMessage()); - errorOccurred = true; - continue; + throw new IllegalArgumentException(project == null ? + "No such job \u2018" + job_s + "\u2019 exists." : + String.format("No such job \u2018%s\u2019 exists. Perhaps you meant \u2018%s\u2019?", + job_s, project.getFullName())); } + job.checkPermission(AbstractItem.CONFIGURE); job.doReload(); } catch (Exception e) { - final String errorMsg = String.format("Unexpected exception occurred during reloading of job '%s': %s", - job == null ? "(null)" : job.getFullName(), - e.getMessage()); + if(hs.size() == 1) { + throw e; + } + + final String errorMsg = String.format(job_s + ": " + e.getMessage()); stderr.println(errorMsg); - LOGGER.warning(errorMsg); errorOccurred = true; - //noinspection UnnecessaryContinue continue; } } - return errorOccurred ? 1 : 0; + + if (errorOccurred) { + throw new AbortException("Error occured while performing this command, see previous stderr output."); + } + return 0; } } diff --git a/core/src/main/java/hudson/cli/RemoveJobFromViewCommand.java b/core/src/main/java/hudson/cli/RemoveJobFromViewCommand.java index 8c317d908f97bccfe39c14f8434a2167e1814249..786f33d21e1ee5fc1cb0d68cec7bcb8605816d40 100644 --- a/core/src/main/java/hudson/cli/RemoveJobFromViewCommand.java +++ b/core/src/main/java/hudson/cli/RemoveJobFromViewCommand.java @@ -55,9 +55,8 @@ public class RemoveJobFromViewCommand extends CLICommand { protected int run() throws Exception { view.checkPermission(View.CONFIGURE); - if (!(view instanceof DirectlyModifiableView)) throw new CmdLineException( - null, "'" + view.getDisplayName() + "' view can not be modified directly" - ); + if (!(view instanceof DirectlyModifiableView)) + throw new IllegalStateException("'" + view.getDisplayName() + "' view can not be modified directly"); for (TopLevelItem job: jobs) { ((DirectlyModifiableView) view).remove(job); diff --git a/core/src/main/java/hudson/cli/SetBuildDisplayNameCommand.java b/core/src/main/java/hudson/cli/SetBuildDisplayNameCommand.java index 08b08b7d7166b510e545d598cfddbad85c299ad7..f52dc58a57f7785257d19a75617f8fc33f3c1122 100644 --- a/core/src/main/java/hudson/cli/SetBuildDisplayNameCommand.java +++ b/core/src/main/java/hudson/cli/SetBuildDisplayNameCommand.java @@ -30,8 +30,7 @@ public class SetBuildDisplayNameCommand extends CLICommand implements Serializab protected int run() throws Exception { Run run = job.getBuildByNumber(number); if (run == null) { - stderr.format("Build #%d does not exist\n", number); - return -1; + throw new IllegalArgumentException("Build #" + number + " does not exist"); } run.checkPermission(Run.UPDATE); diff --git a/core/src/main/java/hudson/cli/declarative/CLIRegisterer.java b/core/src/main/java/hudson/cli/declarative/CLIRegisterer.java index a96daf60f9ca8c510232bb3f045735376350e203..e063bb08cdd2996b08e0fa24e519ca051c093ca2 100644 --- a/core/src/main/java/hudson/cli/declarative/CLIRegisterer.java +++ b/core/src/main/java/hudson/cli/declarative/CLIRegisterer.java @@ -23,6 +23,7 @@ */ package hudson.cli.declarative; +import hudson.AbortException; import hudson.Extension; import hudson.ExtensionComponent; import hudson.ExtensionFinder; @@ -34,7 +35,9 @@ import jenkins.ExtensionComponentSet; import jenkins.ExtensionRefreshException; import jenkins.model.Jenkins; import hudson.security.CliAuthenticator; +import org.acegisecurity.AccessDeniedException; import org.acegisecurity.Authentication; +import org.acegisecurity.BadCredentialsException; import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContextHolder; import org.jvnet.hudson.annotation_indexer.Index; @@ -56,6 +59,9 @@ import java.util.List; import java.util.Locale; import java.util.Stack; import static java.util.logging.Level.SEVERE; + +import java.util.UUID; +import java.util.logging.Level; import java.util.logging.Logger; /** @@ -151,6 +157,40 @@ public class CLIRegisterer extends ExtensionFinder { return parser; } + /** + * Envelope an annotated CLI command + * + * @param args + * Arguments to the sub command. For example, if the CLI is invoked like "java -jar cli.jar foo bar zot", + * then "foo" is the sub-command and the argument list is ["bar","zot"]. + * @param locale + * Locale of the client (which can be different from that of the server.) Good behaving command implementation + * would use this locale for formatting messages. + * @param stdin + * Connected to the stdin of the CLI client. + * @param stdout + * Connected to the stdout of the CLI client. + * @param stderr + * Connected to the stderr of the CLI client. + * @return + * Exit code from the CLI command execution + * + *

+ * Jenkins standard exit codes from CLI: + * 0 means everything went well. + * 1 means further unspecified exception is thrown while performing the command. + * 2 means CmdLineException is thrown while performing the command. + * 3 means IllegalArgumentException is thrown while performing the command. + * 4 mean IllegalStateException is thrown while performing the command. + * 5 means AbortException is thrown while performing the command. + * 6 means AccessDeniedException is thrown while performing the command. + * 7 means BadCredentialsException is thrown while performing the command. + * 8-15 are reserved for future usage + * 16+ mean a custom CLI exit error code (meaning defined by the CLI command itself) + * + *

+ * Note: For details - see JENKINS-32273 + */ @Override public int main(List args, Locale locale, InputStream stdin, PrintStream stdout, PrintStream stderr) { this.stdout = stdout; @@ -166,13 +206,13 @@ public class CLIRegisterer extends ExtensionFinder { try { // authentication CliAuthenticator authenticator = Jenkins.getInstance().getSecurityRealm().createCliAuthenticator(this); - new ClassParser().parse(authenticator,parser); + new ClassParser().parse(authenticator, parser); // fill up all the binders parser.parseArgument(args); Authentication auth = authenticator.authenticate(); - if (auth== Jenkins.ANONYMOUS) + if (auth == Jenkins.ANONYMOUS) auth = loadStoredAuthentication(); sc.setAuthentication(auth); // run the CLI with the right credential hudson.checkPermission(Jenkins.READ); @@ -195,10 +235,40 @@ public class CLIRegisterer extends ExtensionFinder { sc.setAuthentication(old); // restore } } catch (CmdLineException e) { - stderr.println(e.getMessage()); - printUsage(stderr,parser); - return 1; - } catch (Exception e) { + stderr.println(""); + stderr.println("ERROR: " + e.getMessage()); + printUsage(stderr, parser); + return 2; + } catch (IllegalStateException e) { + stderr.println(""); + stderr.println("ERROR: " + e.getMessage()); + return 4; + } catch (IllegalArgumentException e) { + stderr.println(""); + stderr.println("ERROR: " + e.getMessage()); + return 3; + } catch (AbortException e) { + stderr.println(""); + stderr.println("ERROR: " + e.getMessage()); + return 5; + } catch (AccessDeniedException e) { + stderr.println(""); + stderr.println("ERROR: " + e.getMessage()); + return 6; + } catch (BadCredentialsException e) { + // to the caller, we can't reveal whether the user didn't exist or the password didn't match. + // do that to the server log instead + String id = UUID.randomUUID().toString(); + LOGGER.log(Level.INFO, "CLI login attempt failed: " + id, e); + stderr.println(""); + stderr.println("ERROR: Bad Credentials. Search the server log for " + id + " for more details."); + return 7; + } catch (Throwable e) { + final String errorMsg = String.format("Unexpected exception occurred while performing %s command.", + getName()); + stderr.println(""); + stderr.println("ERROR: " + errorMsg); + LOGGER.log(Level.WARNING, errorMsg, e); e.printStackTrace(stderr); return 1; } @@ -213,7 +283,7 @@ public class CLIRegisterer extends ExtensionFinder { } } } catch (IOException e) { - LOGGER.log(SEVERE, "Failed to discvoer @CLIMethod",e); + LOGGER.log(SEVERE, "Failed to discover @CLIMethod",e); } return r; diff --git a/core/src/main/java/hudson/cli/handlers/GenericItemOptionHandler.java b/core/src/main/java/hudson/cli/handlers/GenericItemOptionHandler.java index e27bb32dc8709b8972c64cd7db80b24b0c61634f..cd6b6b9377557af47348c1e767521da18b7ff0a0 100644 --- a/core/src/main/java/hudson/cli/handlers/GenericItemOptionHandler.java +++ b/core/src/main/java/hudson/cli/handlers/GenericItemOptionHandler.java @@ -73,9 +73,9 @@ public abstract class GenericItemOptionHandler extends OptionHan }); T nearest = Items.findNearest(type(), src, j); if (nearest != null) { - throw new CmdLineException(owner, "No such job '" + src + "'; perhaps you meant '" + nearest.getFullName() + "'?"); + throw new IllegalArgumentException("No such job '" + src + "'; perhaps you meant '" + nearest.getFullName() + "'?"); } else { - throw new CmdLineException(owner, "No such job '" + src + "'"); + throw new IllegalArgumentException("No such job '" + src + "'"); } } setter.addValue(s); diff --git a/core/src/main/java/hudson/cli/handlers/NodeOptionHandler.java b/core/src/main/java/hudson/cli/handlers/NodeOptionHandler.java index 516f1e6ed411c19f3741cbec69cda42a602c9bc6..90905d5348968191b2d75e61ceeb01b3ca670b5f 100644 --- a/core/src/main/java/hudson/cli/handlers/NodeOptionHandler.java +++ b/core/src/main/java/hudson/cli/handlers/NodeOptionHandler.java @@ -54,7 +54,7 @@ public class NodeOptionHandler extends OptionHandler { String nodeName = params.getParameter(0); final Node node = Jenkins.getInstance().getNode(nodeName); - if (node == null) throw new CmdLineException(owner, "No such node '" + nodeName + "'"); + if (node == null) throw new IllegalArgumentException("No such node '" + nodeName + "'"); setter.addValue(node); return 1; diff --git a/core/src/main/java/hudson/cli/handlers/ViewOptionHandler.java b/core/src/main/java/hudson/cli/handlers/ViewOptionHandler.java index 77d086a1d1776141cc5932bb5a41cda0d902d0f5..784aef7a70a5a20b0805a17d6259b068b8ce1468 100644 --- a/core/src/main/java/hudson/cli/handlers/ViewOptionHandler.java +++ b/core/src/main/java/hudson/cli/handlers/ViewOptionHandler.java @@ -30,6 +30,7 @@ import java.util.StringTokenizer; import jenkins.model.Jenkins; +import org.acegisecurity.AccessDeniedException; import org.kohsuke.MetaInfServices; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; @@ -81,22 +82,21 @@ public class ViewOptionHandler extends OptionHandler { * Note: Personal user's views aren't supported now. * * @param name A view name - * @return The {@link View} instance. Null if {@link Jenkins#getInstance()} returns null - * sor user doesn't have a READ permission. - * @throws CmdLineException - * If view isn't found or an un-expected error occurred + * @return The {@link View} instance. Null if name is empty string + * @throws IllegalArgumentException + * If the view isn't found + * @throws IllegalStateException + * If cannot get active Jenkins instance or view can't contain a views + * @throws AccessDeniedException + * If user doens't have a READ permission for the view * @since TODO */ @CheckForNull - public View getView(final String name) throws CmdLineException { + public View getView(final String name) { - ViewGroup group = Jenkins.getInstance(); + ViewGroup group = Jenkins.getActiveInstance(); View view = null; - if (group == null) - throw new CmdLineException(owner, - "The Jenkins instance has not been started, or was already shut down!"); - final StringTokenizer tok = new StringTokenizer(name, "/"); while(tok.hasMoreTokens()) { @@ -104,23 +104,16 @@ public class ViewOptionHandler extends OptionHandler { view = group.getView(viewName); if (view == null) - throw new CmdLineException(owner, String.format( + throw new IllegalArgumentException(String.format( "No view named %s inside view %s", viewName, group.getDisplayName() )); - try { - view.checkPermission(View.READ); - } catch (Exception e) { - throw new CmdLineException(owner, e.getMessage()); - } - + view.checkPermission(View.READ); if (view instanceof ViewGroup) { group = (ViewGroup) view; } else if (tok.hasMoreTokens()) { - throw new CmdLineException( - owner, view.getViewName() + " view can not contain views" - ); + throw new IllegalStateException(view.getViewName() + " view can not contain views"); } } diff --git a/core/src/test/java/hudson/cli/ListJobsCommandTest.java b/core/src/test/java/hudson/cli/ListJobsCommandTest.java index 51b4cd980cb1b1cc2783a46fbebc0f9025fba447..a08935c8556ce3b47de8365c96ba3d47b1d993c4 100644 --- a/core/src/test/java/hudson/cli/ListJobsCommandTest.java +++ b/core/src/test/java/hudson/cli/ListJobsCommandTest.java @@ -4,6 +4,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.fail; import static org.powermock.api.mockito.PowerMockito.mock; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.when; @@ -50,6 +51,7 @@ public class ListJobsCommandTest { jenkins = mock(Jenkins.class); mockStatic(Jenkins.class); when(Jenkins.getInstance()).thenReturn(jenkins); + when(Jenkins.getActiveInstance()).thenReturn(jenkins); command = mock(ListJobsCommand.class, Mockito.CALLS_REAL_METHODS); command.stdout = new PrintStream(stdout); command.stderr = new PrintStream(stderr); @@ -61,9 +63,13 @@ public class ListJobsCommandTest { when(jenkins.getView("NoSuchViewOrItemGroup")).thenReturn(null); when(jenkins.getItemByFullName("NoSuchViewOrItemGroup")).thenReturn(null); - assertThat(runWith("NoSuchViewOrItemGroup"), equalTo(-1)); + try { + runWith("NoSuchViewOrItemGroup"); + fail("Exception should be thrown in the previous call."); + } catch (IllegalArgumentException e) { // Expected + assertThat(e.getMessage(), containsString("No view or item group with the given name 'NoSuchViewOrItemGroup' found.")); + } assertThat(stdout, is(empty())); - assertThat(stderr.toString(), containsString("No view or item group with the given name found")); } /* diff --git a/core/src/test/java/hudson/cli/handlers/ViewOptionHandlerTest.java b/core/src/test/java/hudson/cli/handlers/ViewOptionHandlerTest.java index f6dd1d4b395c2b339ab6936f88989c47a82fb855..1f17d89d771c58d7cb93f0dc20477cc2bd083fd1 100644 --- a/core/src/test/java/hudson/cli/handlers/ViewOptionHandlerTest.java +++ b/core/src/test/java/hudson/cli/handlers/ViewOptionHandlerTest.java @@ -80,6 +80,7 @@ public class ViewOptionHandlerTest { PowerMockito.mockStatic(Jenkins.class); PowerMockito.when(Jenkins.getInstance()).thenReturn(jenkins); + PowerMockito.when(Jenkins.getActiveInstance()).thenReturn(jenkins); when(jenkins.getView("outer")).thenReturn(outer); when(jenkins.getDisplayName()).thenReturn("Jenkins"); } @@ -116,7 +117,7 @@ public class ViewOptionHandlerTest { assertEquals( "No view named missing_view inside view Jenkins", - parseFailedWith(CmdLineException.class, "missing_view") + parseFailedWith(IllegalArgumentException.class, "missing_view") ); verifyZeroInteractions(setter); @@ -126,7 +127,7 @@ public class ViewOptionHandlerTest { assertEquals( "No view named missing_view inside view outer", - parseFailedWith(CmdLineException.class, "outer/missing_view") + parseFailedWith(IllegalArgumentException.class, "outer/missing_view") ); verifyZeroInteractions(setter); @@ -136,7 +137,7 @@ public class ViewOptionHandlerTest { assertEquals( "No view named missing_view inside view nested", - parseFailedWith(CmdLineException.class, "outer/nested/missing_view") + parseFailedWith(IllegalArgumentException.class, "outer/nested/missing_view") ); verifyZeroInteractions(setter); @@ -146,19 +147,43 @@ public class ViewOptionHandlerTest { assertEquals( "inner view can not contain views", - parseFailedWith(CmdLineException.class, "outer/nested/inner/missing") + parseFailedWith(IllegalStateException.class, "outer/nested/inner/missing") ); verifyZeroInteractions(setter); } + @Test public void reportEmptyViewNameRequestAsNull() throws Exception { + assertEquals(handler.getView(""), null); + verifyZeroInteractions(setter); + } + + @Test public void reportViewSpaceNameRequestAsIAE() throws Exception { + try { + assertEquals(handler.getView(" "), null); + fail("No exception thrown. Expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + assertEquals("No view named inside view Jenkins", e.getMessage()); + verifyZeroInteractions(setter); + } + } + + @Test public void reportNullViewAsNPE() throws Exception { + try { + handler.getView(null); + fail("No exception thrown. Expected NullPointerException"); + } catch (NullPointerException e) { + verifyZeroInteractions(setter); + } + } + @Test public void refuseToReadOuterView() throws Exception { denyAccessOn(outer); assertEquals( "Access denied for: outer", - parseFailedWith(CmdLineException.class, "outer/nested/inner") + parseFailedWith(AccessDeniedException.class, "outer/nested/inner") ); verify(outer).checkPermission(View.READ); @@ -174,7 +199,7 @@ public class ViewOptionHandlerTest { assertEquals( "Access denied for: nested", - parseFailedWith(CmdLineException.class, "outer/nested/inner") + parseFailedWith(AccessDeniedException.class, "outer/nested/inner") ); verify(nested).checkPermission(View.READ); @@ -189,7 +214,7 @@ public class ViewOptionHandlerTest { assertEquals( "Access denied for: inner", - parseFailedWith(CmdLineException.class, "outer/nested/inner") + parseFailedWith(AccessDeniedException.class, "outer/nested/inner") ); verify(inner).checkPermission(View.READ); diff --git a/test/src/test/groovy/hudson/cli/BuildCommandTest.groovy b/test/src/test/groovy/hudson/cli/BuildCommandTest.groovy index 733726b55361284b33d45a46e8736d23437304a8..33a9b22f872980b6a7f7384a0f05325d47d6af53 100644 --- a/test/src/test/groovy/hudson/cli/BuildCommandTest.groovy +++ b/test/src/test/groovy/hudson/cli/BuildCommandTest.groovy @@ -201,8 +201,8 @@ public class BuildCommandTest { def invoker = new CLICommandInvoker(j, new BuildCommand()); def result = invoker.invokeWithArgs("the-project"); - assertThat(result, failedWith(-1)); - assertThat(result.stderr(), containsString("Cannot build the-project because it is disabled.")); + assertThat(result, failedWith(4)); + assertThat(result.stderr(), containsString("ERROR: Cannot build the-project because it is disabled.")); assertNull("Project should not be built", project.getBuildByNumber(1)); } @@ -213,8 +213,8 @@ public class BuildCommandTest { def invoker = new CLICommandInvoker(j, new BuildCommand()); def result = invoker.invokeWithArgs("new-one"); - assertThat(result, failedWith(-1)); - assertThat(result.stderr(), containsString("Cannot build new-one because its configuration has not been saved.")); + assertThat(result, failedWith(4)); + assertThat(result.stderr(), containsString("ERROR: Cannot build new-one because its configuration has not been saved.")); assertNull("Project should not be built", newOne.getBuildByNumber(1)); } @@ -257,8 +257,8 @@ public class BuildCommandTest { // Create CLI & run command def invoker = new CLICommandInvoker(j, new BuildCommand()); def result = invoker.invokeWithArgs("foo","-p","string=value"); - assertThat(result, failedWith(-1)); - assertThat(result.stderr(), containsString("No default value for the parameter \'FOO\'.")); + assertThat(result, failedWith(2)); + assertThat(result.stderr(), containsString("ERROR: No default value for the parameter \'FOO\'.")); Thread.sleep(5000); // Give the job 5 seconds to be submitted assertNull("Build should not be scheduled", j.jenkins.getQueue().getItem(project)); diff --git a/test/src/test/java/hudson/cli/CLIRegistererTest.java b/test/src/test/java/hudson/cli/CLIRegistererTest.java index 99d65175ff882c3d6795916b36137ef37711c380..fd5a427ba298f3982a238f1e3f1362c82417fc48 100644 --- a/test/src/test/java/hudson/cli/CLIRegistererTest.java +++ b/test/src/test/java/hudson/cli/CLIRegistererTest.java @@ -26,8 +26,8 @@ public class CLIRegistererTest { CLICommandInvoker command = new CLICommandInvoker(j, "quiet-down"); Result invocation = command.invokeWithArgs("--username", "foo", "--password", "invalid"); - assertThat(invocation, failedWith(1)); - assertThat(invocation.stderr(), containsString("BadCredentialsException: foo")); + assertThat(invocation, failedWith(7)); + assertThat(invocation.stderr(), containsString("ERROR: Bad Credentials. Search the server log for ")); assertThat("Unauthorized command was executed", Jenkins.getInstance().isQuietingDown(), is(false)); invocation = command.invokeWithArgs("--username", "foo", "--password", "foo"); diff --git a/test/src/test/java/hudson/cli/CopyJobCommandTest.java b/test/src/test/java/hudson/cli/CopyJobCommandTest.java index 06fac566f625ef4597b5ff1003793fd414e392e4..8d34edcd8e7e3dd3777fbd02880bebb475e0ad82 100644 --- a/test/src/test/java/hudson/cli/CopyJobCommandTest.java +++ b/test/src/test/java/hudson/cli/CopyJobCommandTest.java @@ -124,11 +124,11 @@ public class CopyJobCommandTest { } }); copyJobCommand.setTransportAuth(User.get("alice").impersonate()); - assertThat(command.invokeWithArgs("d1/p", "d2/p"), failedWith(-1)); + assertThat(command.invokeWithArgs("d1/p", "d2/p"), failedWith(3)); copyJobCommand.setTransportAuth(User.get("bob").impersonate()); - assertThat(command.invokeWithArgs("d1/p", "d2/p"), failedWith(-1)); + assertThat(command.invokeWithArgs("d1/p", "d2/p"), failedWith(6)); copyJobCommand.setTransportAuth(User.get("charlie").impersonate()); - assertThat(command.invokeWithArgs("d1/p", "d2/p"), failedWith(-1)); + assertThat(command.invokeWithArgs("d1/p", "d2/p"), failedWith(6)); copyJobCommand.setTransportAuth(User.get("debbie").impersonate()); assertThat(command.invokeWithArgs("d1/p", "d2/p"), succeededSilently()); assertNotNull(d2.getItem("p")); diff --git a/test/src/test/java/hudson/cli/CreateJobCommandTest.java b/test/src/test/java/hudson/cli/CreateJobCommandTest.java index a11b0461acf0b6042b5d72db7269725671c4e192..fd713b0a5383e8ff5107cab44b02e62cdd1e3b24 100644 --- a/test/src/test/java/hudson/cli/CreateJobCommandTest.java +++ b/test/src/test/java/hudson/cli/CreateJobCommandTest.java @@ -78,7 +78,7 @@ public class CreateJobCommandTest { } }); cmd.setTransportAuth(User.get("alice").impersonate()); - assertThat(invoker.withStdin(new ByteArrayInputStream("".getBytes("US-ASCII"))).invokeWithArgs("d/p"), failedWith(-1)); + assertThat(invoker.withStdin(new ByteArrayInputStream("".getBytes("US-ASCII"))).invokeWithArgs("d/p"), failedWith(6)); cmd.setTransportAuth(User.get("bob").impersonate()); assertThat(invoker.withStdin(new ByteArrayInputStream("".getBytes("US-ASCII"))).invokeWithArgs("d/p"), succeededSilently()); assertNotNull(d.getItem("p")); diff --git a/test/src/test/java/hudson/cli/CreateNodeCommandTest.java b/test/src/test/java/hudson/cli/CreateNodeCommandTest.java index ad207cc0d74efd7315785963480a27711a4b7d25..0cb5dfc6fc695eda7e3650a6f45c9f346a24b8c0 100644 --- a/test/src/test/java/hudson/cli/CreateNodeCommandTest.java +++ b/test/src/test/java/hudson/cli/CreateNodeCommandTest.java @@ -60,9 +60,9 @@ public class CreateNodeCommandTest { .invoke() ; - assertThat(result.stderr(), containsString("user is missing the Slave/Create permission")); + assertThat(result.stderr(), containsString("ERROR: user is missing the Slave/Create permission")); assertThat(result, hasNoStandardOutput()); - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(6)); } @Test public void createNode() throws Exception { @@ -129,9 +129,9 @@ public class CreateNodeCommandTest { .invoke() ; - assertThat(result.stderr(), containsString("Node 'SlaveFromXML' already exists")); + assertThat(result.stderr(), containsString("ERROR: Node 'SlaveFromXML' already exists")); assertThat(result, hasNoStandardOutput()); - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(4)); } @Test public void createNodeShouldFailIfNodeAlreadyExistWhenNameSpecifiedExplicitly() throws Exception { @@ -144,8 +144,8 @@ public class CreateNodeCommandTest { .invokeWithArgs("ExistingSlave") ; - assertThat(result.stderr(), containsString("Node 'ExistingSlave' already exists")); + assertThat(result.stderr(), containsString("ERROR: Node 'ExistingSlave' already exists")); assertThat(result, hasNoStandardOutput()); - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(4)); } } diff --git a/test/src/test/java/hudson/cli/CreateViewCommandTest.java b/test/src/test/java/hudson/cli/CreateViewCommandTest.java index 5ed9af5f6a2c16dd5c7a7298784f620220fbd9be..5b564ea0117abcf111f11afbca67e80799e43c8b 100644 --- a/test/src/test/java/hudson/cli/CreateViewCommandTest.java +++ b/test/src/test/java/hudson/cli/CreateViewCommandTest.java @@ -62,9 +62,9 @@ public class CreateViewCommandTest { .invoke() ; - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(6)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("user is missing the View/Create permission")); + assertThat(result.stderr(), containsString("ERROR: user is missing the View/Create permission")); } @Test public void createViewShouldSucceed() { @@ -111,9 +111,9 @@ public class CreateViewCommandTest { .invoke() ; - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(4)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("View 'ViewFromXML' already exists")); + assertThat(result.stderr(), containsString("ERROR: View 'ViewFromXML' already exists")); } @Test public void createViewShouldFailUsingInvalidName() { @@ -124,8 +124,8 @@ public class CreateViewCommandTest { .invokeWithArgs("..") ; - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("Invalid view name")); + assertThat(result.stderr(), containsString("ERROR: Invalid view name")); } } diff --git a/test/src/test/java/hudson/cli/DeleteJobCommandTest.java b/test/src/test/java/hudson/cli/DeleteJobCommandTest.java index 1f540c9e285e8c20017d1af0a756b2c4c78794b7..1bf3622f9929cd98ea65cbaa64204356b207946e 100644 --- a/test/src/test/java/hudson/cli/DeleteJobCommandTest.java +++ b/test/src/test/java/hudson/cli/DeleteJobCommandTest.java @@ -62,9 +62,9 @@ public class DeleteJobCommandTest { .authorizedTo(Job.READ, Jenkins.READ) .invokeWithArgs("aProject"); - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(6)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("user is missing the Job/Delete permission")); + assertThat(result.stderr(), containsString("ERROR: user is missing the Job/Delete permission")); } @Test public void deleteJobShouldFailWithoutJobReadPermission() throws IOException { @@ -75,9 +75,9 @@ public class DeleteJobCommandTest { .authorizedTo(Job.DELETE, Jenkins.READ) .invokeWithArgs("aProject"); - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("No such job 'aProject'")); + assertThat(result.stderr(), containsString("ERROR: No such job 'aProject'")); } @Test public void deleteJobShouldSucceed() throws Exception { @@ -98,9 +98,9 @@ public class DeleteJobCommandTest { .authorizedTo(Job.READ, Job.DELETE, Jenkins.READ) .invokeWithArgs("never_created"); - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("No such job 'never_created'")); + assertThat(result.stderr(), containsString("ERROR: No such job 'never_created'")); } @Test public void deleteJobManyShouldSucceed() throws Exception { @@ -119,7 +119,45 @@ public class DeleteJobCommandTest { assertThat(j.jenkins.getItem("aProject3"), nullValue()); } - @Test public void deleteJobManyShouldFailIfAJobDoesNotExist() throws Exception { + @Test public void deleteJobManyShouldFailIfFirstJobDoesNotExist() throws Exception { + + j.createFreeStyleProject("aProject1"); + j.createFreeStyleProject("aProject2"); + + final CLICommandInvoker.Result result = command + .authorizedTo(Job.READ, Job.DELETE, Jenkins.READ) + .invokeWithArgs("never_created", "aProject1", "aProject2"); + + assertThat(result, failedWith(5)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("never_created: No such job 'never_created'")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); + + assertThat(j.jenkins.getItem("aProject1"), nullValue()); + assertThat(j.jenkins.getItem("aProject2"), nullValue()); + assertThat(j.jenkins.getItem("never_created"), nullValue()); + } + + @Test public void deleteJobManyShouldFailIfMiddleJobDoesNotExist() throws Exception { + + j.createFreeStyleProject("aProject1"); + j.createFreeStyleProject("aProject2"); + + final CLICommandInvoker.Result result = command + .authorizedTo(Job.READ, Job.DELETE, Jenkins.READ) + .invokeWithArgs("aProject1","never_created", "aProject2"); + + assertThat(result, failedWith(5)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("never_created: No such job 'never_created'")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); + + assertThat(j.jenkins.getItem("aProject1"), nullValue()); + assertThat(j.jenkins.getItem("aProject2"), nullValue()); + assertThat(j.jenkins.getItem("never_created"), nullValue()); + } + + @Test public void deleteJobManyShouldFailIfLastJobDoesNotExist() throws Exception { j.createFreeStyleProject("aProject1"); j.createFreeStyleProject("aProject2"); @@ -128,15 +166,37 @@ public class DeleteJobCommandTest { .authorizedTo(Job.READ, Job.DELETE, Jenkins.READ) .invokeWithArgs("aProject1", "aProject2", "never_created"); - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(5)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("No such job 'never_created'")); + assertThat(result.stderr(), containsString("never_created: No such job 'never_created'")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); assertThat(j.jenkins.getItem("aProject1"), nullValue()); assertThat(j.jenkins.getItem("aProject2"), nullValue()); assertThat(j.jenkins.getItem("never_created"), nullValue()); } + @Test public void deleteJobManyShouldFailIfMoreJobsDoNotExist() throws Exception { + + j.createFreeStyleProject("aProject1"); + j.createFreeStyleProject("aProject2"); + + final CLICommandInvoker.Result result = command + .authorizedTo(Job.READ, Job.DELETE, Jenkins.READ) + .invokeWithArgs("aProject1", "never_created1", "never_created2", "aProject2"); + + assertThat(result, failedWith(5)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("never_created1: No such job 'never_created1'")); + assertThat(result.stderr(), containsString("never_created2: No such job 'never_created2'")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); + + assertThat(j.jenkins.getItem("aProject1"), nullValue()); + assertThat(j.jenkins.getItem("aProject2"), nullValue()); + assertThat(j.jenkins.getItem("never_created1"), nullValue()); + assertThat(j.jenkins.getItem("never_created2"), nullValue()); + } + @Test public void deleteJobManyShouldSucceedEvenAJobIsSpecifiedTwice() throws Exception { j.createFreeStyleProject("aProject1"); diff --git a/test/src/test/java/hudson/cli/DeleteNodeCommandTest.java b/test/src/test/java/hudson/cli/DeleteNodeCommandTest.java index 60b3494e0aee1321d7df03c24b3ce4dec10c8fdb..9db0e60419ca375eb662db56ffa49dc275726af4 100644 --- a/test/src/test/java/hudson/cli/DeleteNodeCommandTest.java +++ b/test/src/test/java/hudson/cli/DeleteNodeCommandTest.java @@ -60,9 +60,9 @@ public class DeleteNodeCommandTest { .invokeWithArgs("aNode") ; - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(6)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("user is missing the Slave/Delete permission")); + assertThat(result.stderr(), containsString("ERROR: user is missing the Slave/Delete permission")); } @Test public void deleteNodeShouldSucceed() throws Exception { @@ -85,9 +85,9 @@ public class DeleteNodeCommandTest { .invokeWithArgs("never_created") ; - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("No such node 'never_created'")); + assertThat(result.stderr(), containsString("ERROR: No such node 'never_created'")); } @Test public void deleteNodeManyShouldSucceed() throws Exception { @@ -106,7 +106,45 @@ public class DeleteNodeCommandTest { assertThat(j.jenkins.getView("aNode3"), nullValue()); } - @Test public void deleteNodeManyShouldFailIfANodeDoesNotExist() throws Exception { + @Test public void deleteNodeManyShouldFailIfFirstNodeDoesNotExist() throws Exception { + + j.createSlave("aNode1", "", null); + j.createSlave("aNode2", "", null); + + final CLICommandInvoker.Result result = command + .authorizedTo(Computer.DELETE, Jenkins.READ) + .invokeWithArgs("never_created", "aNode1", "aNode2"); + + assertThat(result, failedWith(5)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("never_created: No such node 'never_created'")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); + + assertThat(j.jenkins.getView("aNode1"), nullValue()); + assertThat(j.jenkins.getView("aNode2"), nullValue()); + assertThat(j.jenkins.getView("never_created"), nullValue()); + } + + @Test public void deleteNodeManyShouldFailIfMiddleNodeDoesNotExist() throws Exception { + + j.createSlave("aNode1", "", null); + j.createSlave("aNode2", "", null); + + final CLICommandInvoker.Result result = command + .authorizedTo(Computer.DELETE, Jenkins.READ) + .invokeWithArgs("aNode1", "never_created", "aNode2"); + + assertThat(result, failedWith(5)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("never_created: No such node 'never_created'")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); + + assertThat(j.jenkins.getView("aNode1"), nullValue()); + assertThat(j.jenkins.getView("aNode2"), nullValue()); + assertThat(j.jenkins.getView("never_created"), nullValue()); + } + + @Test public void deleteNodeManyShouldFailIfLastNodeDoesNotExist() throws Exception { j.createSlave("aNode1", "", null); j.createSlave("aNode2", "", null); @@ -115,15 +153,37 @@ public class DeleteNodeCommandTest { .authorizedTo(Computer.DELETE, Jenkins.READ) .invokeWithArgs("aNode1", "aNode2", "never_created"); - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(5)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("No such node 'never_created'")); + assertThat(result.stderr(), containsString("never_created: No such node 'never_created'")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); assertThat(j.jenkins.getView("aNode1"), nullValue()); assertThat(j.jenkins.getView("aNode2"), nullValue()); assertThat(j.jenkins.getView("never_created"), nullValue()); } + @Test public void deleteNodeManyShouldFailIfMoreNodesDoNotExist() throws Exception { + + j.createSlave("aNode1", "", null); + j.createSlave("aNode2", "", null); + + final CLICommandInvoker.Result result = command + .authorizedTo(Computer.DELETE, Jenkins.READ) + .invokeWithArgs("aNode1", "never_created1", "never_created2", "aNode2"); + + assertThat(result, failedWith(5)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("never_created1: No such node 'never_created1'")); + assertThat(result.stderr(), containsString("never_created2: No such node 'never_created2'")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); + + assertThat(j.jenkins.getView("aNode1"), nullValue()); + assertThat(j.jenkins.getView("aNode2"), nullValue()); + assertThat(j.jenkins.getView("never_created1"), nullValue()); + assertThat(j.jenkins.getView("never_created2"), nullValue()); + } + @Test public void deleteNodeManyShouldSucceedEvenANodeIsSpecifiedTwice() throws Exception { j.createSlave("aNode1", "", null); diff --git a/test/src/test/java/hudson/cli/DeleteViewCommandTest.java b/test/src/test/java/hudson/cli/DeleteViewCommandTest.java index c3938b51be6e0df0273b52d9836d83f5cb97496f..732270fcccc7c98b7fedd169341d4d406c2b66fe 100644 --- a/test/src/test/java/hudson/cli/DeleteViewCommandTest.java +++ b/test/src/test/java/hudson/cli/DeleteViewCommandTest.java @@ -67,9 +67,9 @@ public class DeleteViewCommandTest { .invokeWithArgs("aView") ; - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(6)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("user is missing the View/Delete permission")); + assertThat(result.stderr(), containsString("ERROR: user is missing the View/Delete permission")); } @Test public void deleteViewShouldFailWithoutViewReadPermission() throws IOException { @@ -81,9 +81,9 @@ public class DeleteViewCommandTest { .invokeWithArgs("aView") ; - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(6)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("user is missing the View/Read permission")); + assertThat(result.stderr(), containsString("ERROR: user is missing the View/Read permission")); } @Test public void deleteViewShouldSucceed() throws Exception { @@ -106,9 +106,9 @@ public class DeleteViewCommandTest { .invokeWithArgs("never_created") ; - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("No view named never_created inside view Jenkins")); + assertThat(result.stderr(), containsString("ERROR: No view named never_created inside view Jenkins")); } // ViewGroup.canDelete() @@ -119,10 +119,32 @@ public class DeleteViewCommandTest { .invokeWithArgs("All") ; - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(4)); assertThat(result, hasNoStandardOutput()); assertThat(j.jenkins.getView("All"), notNullValue()); - assertThat(result.stderr(), containsString("Jenkins does not allow to delete 'All' view")); + assertThat(result.stderr(), containsString("ERROR: Jenkins does not allow to delete 'All' view")); + } + + @Test public void deleteViewShoudlFailIfViewNameIsEmpty() { + final CLICommandInvoker.Result result = command + .authorizedTo(View.READ, View.DELETE, Jenkins.READ) + .invokeWithArgs("") + ; + + assertThat(result, failedWith(3)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("ERROR: View name is empty")); + } + + @Test public void deleteViewShoudlFailIfViewNameIsSpace() { + final CLICommandInvoker.Result result = command + .authorizedTo(View.READ, View.DELETE, Jenkins.READ) + .invokeWithArgs(" ") + ; + + assertThat(result, failedWith(3)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("ERROR: No view named inside view Jenkins")); } @Test public void deleteViewManyShouldSucceed() throws Exception { @@ -141,7 +163,45 @@ public class DeleteViewCommandTest { assertThat(j.jenkins.getView("aView3"), nullValue()); } - @Test public void deleteViewManyShouldFailIfAViewDoesNotExist() throws Exception { + @Test public void deleteViewManyShouldFailIfFirstViewDoesNotExist() throws Exception { + + j.jenkins.addView(new ListView("aView1")); + j.jenkins.addView(new ListView("aView2")); + + final CLICommandInvoker.Result result = command + .authorizedTo(View.READ, View.DELETE, Jenkins.READ) + .invokeWithArgs("never_created", "aView1", "aView2"); + + assertThat(result, failedWith(5)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("never_created: No view named never_created inside view Jenkins")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); + + assertThat(j.jenkins.getView("aView1"), nullValue()); + assertThat(j.jenkins.getView("aView2"), nullValue()); + assertThat(j.jenkins.getView("never_created"), nullValue()); + } + + @Test public void deleteViewManyShouldFailIfMiddleViewDoesNotExist() throws Exception { + + j.jenkins.addView(new ListView("aView1")); + j.jenkins.addView(new ListView("aView2")); + + final CLICommandInvoker.Result result = command + .authorizedTo(View.READ, View.DELETE, Jenkins.READ) + .invokeWithArgs("aView1", "never_created", "aView2"); + + assertThat(result, failedWith(5)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("never_created: No view named never_created inside view Jenkins")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); + + assertThat(j.jenkins.getView("aView1"), nullValue()); + assertThat(j.jenkins.getView("aView2"), nullValue()); + assertThat(j.jenkins.getView("never_created"), nullValue()); + } + + @Test public void deleteViewManyShouldFailIfLastViewDoesNotExist() throws Exception { j.jenkins.addView(new ListView("aView1")); j.jenkins.addView(new ListView("aView2")); @@ -150,15 +210,37 @@ public class DeleteViewCommandTest { .authorizedTo(View.READ, View.DELETE, Jenkins.READ) .invokeWithArgs("aView1", "aView2", "never_created"); - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(5)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("No view named never_created inside view Jenkins")); + assertThat(result.stderr(), containsString("never_created: No view named never_created inside view Jenkins")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); assertThat(j.jenkins.getView("aView1"), nullValue()); assertThat(j.jenkins.getView("aView2"), nullValue()); assertThat(j.jenkins.getView("never_created"), nullValue()); } + @Test public void deleteViewManyShouldFailIfMoreViewsDoNotExist() throws Exception { + + j.jenkins.addView(new ListView("aView1")); + j.jenkins.addView(new ListView("aView2")); + + final CLICommandInvoker.Result result = command + .authorizedTo(View.READ, View.DELETE, Jenkins.READ) + .invokeWithArgs("aView1", "never_created1", "never_created2", "aView2"); + + assertThat(result, failedWith(5)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("never_created1: No view named never_created1 inside view Jenkins")); + assertThat(result.stderr(), containsString("never_created2: No view named never_created2 inside view Jenkins")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); + + assertThat(j.jenkins.getView("aView1"), nullValue()); + assertThat(j.jenkins.getView("aView2"), nullValue()); + assertThat(j.jenkins.getView("never_created1"), nullValue()); + assertThat(j.jenkins.getView("never_created2"), nullValue()); + } + @Test public void deleteViewManyShouldSucceedEvenAViewSpecifiedTwice() throws Exception { j.jenkins.addView(new ListView("aView1")); @@ -182,9 +264,10 @@ public class DeleteViewCommandTest { .authorizedTo(View.READ, View.DELETE, Jenkins.READ) .invokeWithArgs("aView1", "aView2", "All"); - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(5)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("Jenkins does not allow to delete 'All' view")); + assertThat(result.stderr(), containsString("All: Jenkins does not allow to delete 'All' view")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); assertThat(j.jenkins.getView("aView1"), nullValue()); assertThat(j.jenkins.getView("aView2"), nullValue()); diff --git a/test/src/test/java/hudson/cli/GetNodeCommandTest.java b/test/src/test/java/hudson/cli/GetNodeCommandTest.java index e6d2c8ac084dd1741c89c23b2386dacffd396fc1..eb20a1162cd7f028ee04799fb9df81fe190d7e4a 100644 --- a/test/src/test/java/hudson/cli/GetNodeCommandTest.java +++ b/test/src/test/java/hudson/cli/GetNodeCommandTest.java @@ -59,8 +59,8 @@ public class GetNodeCommandTest { .invokeWithArgs("MySlave") ; - assertThat(result.stderr(), containsString("user is missing the Slave/ExtendedRead permission")); - assertThat(result, failedWith(-1)); + assertThat(result.stderr(), containsString("ERROR: user is missing the Slave/ExtendedRead permission")); + assertThat(result, failedWith(6)); assertThat(result, hasNoStandardOutput()); } @@ -86,8 +86,8 @@ public class GetNodeCommandTest { .invokeWithArgs("MySlave") ; - assertThat(result.stderr(), containsString("No such node 'MySlave'")); - assertThat(result, failedWith(-1)); + assertThat(result.stderr(), containsString("ERROR: No such node 'MySlave'")); + assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); } } diff --git a/test/src/test/java/hudson/cli/GetViewCommandTest.java b/test/src/test/java/hudson/cli/GetViewCommandTest.java index 4eb47f1553b11d7530ed8c72f24670e0bba331c5..d3a6fd9ef78607b79fdfd88186158264e41c1a57 100644 --- a/test/src/test/java/hudson/cli/GetViewCommandTest.java +++ b/test/src/test/java/hudson/cli/GetViewCommandTest.java @@ -63,9 +63,9 @@ public class GetViewCommandTest { .invokeWithArgs("aView") ; - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(6)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("user is missing the View/Read permission")); + assertThat(result.stderr(), containsString("ERROR: user is missing the View/Read permission")); } @Test public void getViewShouldYieldConfigXml() throws Exception { @@ -90,8 +90,8 @@ public class GetViewCommandTest { .invokeWithArgs("never_created") ; - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("No view named never_created inside view Jenkins")); + assertThat(result.stderr(), containsString("ERROR: No view named never_created inside view Jenkins")); } } diff --git a/test/src/test/java/hudson/cli/OnlineNodeCommandTest.java b/test/src/test/java/hudson/cli/OnlineNodeCommandTest.java index 1204d4af56f5c50c7a6e6a191e99b863f4469879..686cb2d64d6d43fff02706dd35b0bfeaef9f5067 100644 --- a/test/src/test/java/hudson/cli/OnlineNodeCommandTest.java +++ b/test/src/test/java/hudson/cli/OnlineNodeCommandTest.java @@ -63,18 +63,18 @@ public class OnlineNodeCommandTest { .authorizedTo(Jenkins.READ) .invokeWithArgs("aNode"); - assertThat(result, failedWith(1)); + assertThat(result, failedWith(6)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("user is missing the Slave/Connect permission")); + assertThat(result.stderr(), containsString("ERROR: user is missing the Slave/Connect permission")); } @Test public void onlineNodeShouldFailIfNodeDoesNotExist() throws Exception { final CLICommandInvoker.Result result = command .authorizedTo(Computer.CONNECT, Jenkins.READ) .invokeWithArgs("never_created"); - assertThat(result, failedWith(1)); + assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("No such slave \"never_created\" exists.")); + assertThat(result.stderr(), containsString("ERROR: No such slave \"never_created\" exists.")); } diff --git a/test/src/test/java/hudson/cli/ReloadJobCommandTest.java b/test/src/test/java/hudson/cli/ReloadJobCommandTest.java index ff99a88e958408e0d48042770fa8ad61ee6d28e8..40869bab3fd5f9ab711cc0eb64003477227f03b9 100644 --- a/test/src/test/java/hudson/cli/ReloadJobCommandTest.java +++ b/test/src/test/java/hudson/cli/ReloadJobCommandTest.java @@ -67,9 +67,9 @@ public class ReloadJobCommandTest { .authorizedTo(Job.READ, Jenkins.READ) .invokeWithArgs("aProject"); - assertThat(result, failedWith(1)); + assertThat(result, failedWith(6)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("user is missing the Job/Configure permission")); + assertThat(result.stderr(), containsString("ERROR: user is missing the Job/Configure permission")); assertThat(project.scheduleBuild2(0).get().getLog(), containsString("echo 1")); } @@ -86,9 +86,9 @@ public class ReloadJobCommandTest { .authorizedTo(Job.CONFIGURE, Jenkins.READ) .invokeWithArgs("aProject"); - assertThat(result, failedWith(1)); + assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("No such job \u2018aProject\u2019 exists.")); + assertThat(result.stderr(), containsString("ERROR: No such job \u2018aProject\u2019 exists.")); assertThat(project.scheduleBuild2(0).get().getLog(), containsString("echo 1")); } @@ -116,9 +116,9 @@ public class ReloadJobCommandTest { final CLICommandInvoker.Result result = command .authorizedTo(Job.READ, Job.CONFIGURE, Jenkins.READ) .invokeWithArgs("never_created"); - assertThat(result, failedWith(1)); + assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("No such job \u2018never_created\u2019 exists.")); + assertThat(result.stderr(), containsString("ERROR: No such job \u2018never_created\u2019 exists.")); } @Test public void reloadJobShouldFailIfJobDoesNotExistButNearExists() throws Exception { @@ -128,9 +128,9 @@ public class ReloadJobCommandTest { final CLICommandInvoker.Result result = command .authorizedTo(Job.READ, Job.CONFIGURE, Jenkins.READ) .invokeWithArgs("never_created1"); - assertThat(result, failedWith(1)); + assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("No such job \u2018never_created1\u2019 exists. Perhaps you meant \u2018never_created\u2019?")); + assertThat(result.stderr(), containsString("ERROR: No such job \u2018never_created1\u2019 exists. Perhaps you meant \u2018never_created\u2019?")); } @Test public void reloadJobManyShouldSucceed() throws Exception { @@ -161,7 +161,59 @@ public class ReloadJobCommandTest { assertThat(project3.scheduleBuild2(0).get().getLog(), containsString("echo 2")); } - @Test public void reloadJobManyShouldFailIfAJobDoesNotExist() throws Exception { + @Test public void reloadJobManyShouldFailIfFirstJobDoesNotExist() throws Exception { + + FreeStyleProject project1 = j.createFreeStyleProject("aProject1"); + project1.getBuildersList().add(new Shell("echo 1")); + FreeStyleProject project2 = j.createFreeStyleProject("aProject2"); + project2.getBuildersList().add(new Shell("echo 1")); + + assertThat(project1.scheduleBuild2(0).get().getLog(), containsString("echo 1")); + assertThat(project2.scheduleBuild2(0).get().getLog(), containsString("echo 1")); + + changeProjectOnTheDisc(project1, "echo 1", "echo 2"); + changeProjectOnTheDisc(project2, "echo 1", "echo 2"); + + final CLICommandInvoker.Result result = command + .authorizedTo(Job.READ, Job.CONFIGURE, Jenkins.READ) + .invokeWithArgs("never_created", "aProject1", "aProject2"); + + assertThat(result, failedWith(5)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("never_created: No such job \u2018never_created\u2019 exists.")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); + + assertThat(project1.scheduleBuild2(0).get().getLog(), containsString("echo 2")); + assertThat(project2.scheduleBuild2(0).get().getLog(), containsString("echo 2")); + } + + @Test public void reloadJobManyShouldFailIfMiddleJobDoesNotExist() throws Exception { + + FreeStyleProject project1 = j.createFreeStyleProject("aProject1"); + project1.getBuildersList().add(new Shell("echo 1")); + FreeStyleProject project2 = j.createFreeStyleProject("aProject2"); + project2.getBuildersList().add(new Shell("echo 1")); + + assertThat(project1.scheduleBuild2(0).get().getLog(), containsString("echo 1")); + assertThat(project2.scheduleBuild2(0).get().getLog(), containsString("echo 1")); + + changeProjectOnTheDisc(project1, "echo 1", "echo 2"); + changeProjectOnTheDisc(project2, "echo 1", "echo 2"); + + final CLICommandInvoker.Result result = command + .authorizedTo(Job.READ, Job.CONFIGURE, Jenkins.READ) + .invokeWithArgs("aProject1", "never_created", "aProject2"); + + assertThat(result, failedWith(5)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("never_created: No such job \u2018never_created\u2019 exists.")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); + + assertThat(project1.scheduleBuild2(0).get().getLog(), containsString("echo 2")); + assertThat(project2.scheduleBuild2(0).get().getLog(), containsString("echo 2")); + } + + @Test public void reloadJobManyShouldFailIfLastJobDoesNotExist() throws Exception { FreeStyleProject project1 = j.createFreeStyleProject("aProject1"); project1.getBuildersList().add(new Shell("echo 1")); @@ -178,9 +230,37 @@ public class ReloadJobCommandTest { .authorizedTo(Job.READ, Job.CONFIGURE, Jenkins.READ) .invokeWithArgs("aProject1", "aProject2", "never_created"); - assertThat(result, failedWith(1)); + assertThat(result, failedWith(5)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("never_created: No such job \u2018never_created\u2019 exists.")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); + + assertThat(project1.scheduleBuild2(0).get().getLog(), containsString("echo 2")); + assertThat(project2.scheduleBuild2(0).get().getLog(), containsString("echo 2")); + } + + @Test public void reloadJobManyShouldFailIfMoreJobsDoNotExist() throws Exception { + + FreeStyleProject project1 = j.createFreeStyleProject("aProject1"); + project1.getBuildersList().add(new Shell("echo 1")); + FreeStyleProject project2 = j.createFreeStyleProject("aProject2"); + project2.getBuildersList().add(new Shell("echo 1")); + + assertThat(project1.scheduleBuild2(0).get().getLog(), containsString("echo 1")); + assertThat(project2.scheduleBuild2(0).get().getLog(), containsString("echo 1")); + + changeProjectOnTheDisc(project1, "echo 1", "echo 2"); + changeProjectOnTheDisc(project2, "echo 1", "echo 2"); + + final CLICommandInvoker.Result result = command + .authorizedTo(Job.READ, Job.CONFIGURE, Jenkins.READ) + .invokeWithArgs("aProject1", "never_created1", "never_created2", "aProject2"); + + assertThat(result, failedWith(5)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("No such job \u2018never_created\u2019 exists.")); + assertThat(result.stderr(), containsString("never_created1: No such job \u2018never_created1\u2019 exists.")); + assertThat(result.stderr(), containsString("never_created2: No such job \u2018never_created2\u2019 exists.")); + assertThat(result.stderr(), containsString("ERROR: Error occured while performing this command, see previous stderr output.")); assertThat(project1.scheduleBuild2(0).get().getLog(), containsString("echo 2")); assertThat(project2.scheduleBuild2(0).get().getLog(), containsString("echo 2")); diff --git a/test/src/test/java/hudson/cli/SetBuildDisplayNameCommandTest.java b/test/src/test/java/hudson/cli/SetBuildDisplayNameCommandTest.java index f706fa2b70ae5e469347f0dc72b8f2f738169875..224aa2b2e3111f19dd30c74d048b22a448693e82 100644 --- a/test/src/test/java/hudson/cli/SetBuildDisplayNameCommandTest.java +++ b/test/src/test/java/hudson/cli/SetBuildDisplayNameCommandTest.java @@ -57,9 +57,9 @@ public class SetBuildDisplayNameCommandTest { .invokeWithArgs("project", "42", "DisplayName") ; - assertThat(result.stderr(), containsString("Build #42 does not exist")); + assertThat(result.stderr(), containsString("ERROR: Build #42 does not exist")); assertThat(result, hasNoStandardOutput()); - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(3)); } @Test public void setDescriptionSuccessfully() throws Exception { diff --git a/test/src/test/java/hudson/cli/UpdateNodeCommandTest.java b/test/src/test/java/hudson/cli/UpdateNodeCommandTest.java index b4a977dbe958ceec179e134b10a6d9724d18ae15..cac9dda8abc332a5c18c9890b06426065ddf7fa4 100644 --- a/test/src/test/java/hudson/cli/UpdateNodeCommandTest.java +++ b/test/src/test/java/hudson/cli/UpdateNodeCommandTest.java @@ -60,8 +60,8 @@ public class UpdateNodeCommandTest { .invokeWithArgs("MySlave") ; - assertThat(result.stderr(), containsString("user is missing the Slave/Configure permission")); - assertThat(result, failedWith(-1)); + assertThat(result.stderr(), containsString("ERROR: user is missing the Slave/Configure permission")); + assertThat(result, failedWith(6)); assertThat(result, hasNoStandardOutput()); } @@ -92,8 +92,8 @@ public class UpdateNodeCommandTest { .invokeWithArgs("MySlave") ; - assertThat(result.stderr(), containsString("No such node 'MySlave'")); - assertThat(result, failedWith(-1)); + assertThat(result.stderr(), containsString("ERROR: No such node 'MySlave'")); + assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); } } diff --git a/test/src/test/java/hudson/cli/UpdateViewCommandTest.java b/test/src/test/java/hudson/cli/UpdateViewCommandTest.java index 937c2e7bac3f8926cc7c3b8f70712f669521cf03..ad2ceffe1bb291b5c236d3f8ff502ff45ec4589f 100644 --- a/test/src/test/java/hudson/cli/UpdateViewCommandTest.java +++ b/test/src/test/java/hudson/cli/UpdateViewCommandTest.java @@ -61,9 +61,9 @@ public class UpdateViewCommandTest { .invokeWithArgs("aView") ; - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(6)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("user is missing the View/Configure permission")); + assertThat(result.stderr(), containsString("ERROR: user is missing the View/Configure permission")); } @Test public void updateViewShouldModifyViewConfiguration() throws Exception { @@ -94,8 +94,8 @@ public class UpdateViewCommandTest { .invokeWithArgs("not_created") ; - assertThat(result, failedWith(-1)); + assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); - assertThat(result.stderr(), containsString("No view named not_created inside view Jenkins")); + assertThat(result.stderr(), containsString("ERROR: No view named not_created inside view Jenkins")); } } diff --git a/test/src/test/java/hudson/cli/ViewManipulationTest.java b/test/src/test/java/hudson/cli/ViewManipulationTest.java index b77ea0854e4aa32238b916cf4f4a7e1c85b5cb82..fe2bedb3d5fcfadcef2338b61cc0bd44ce0eafd7 100644 --- a/test/src/test/java/hudson/cli/ViewManipulationTest.java +++ b/test/src/test/java/hudson/cli/ViewManipulationTest.java @@ -84,12 +84,12 @@ public class ViewManipulationTest { j.createFreeStyleProject("a_project"); res = add().invokeWithArgs("All", "a_project"); - assertThat(res, failedWith(-1)); - assertThat(res.stderr(), containsString("'All' view can not be modified directly")); + assertThat(res, failedWith(4)); + assertThat(res.stderr(), containsString("ERROR: 'All' view can not be modified directly")); res = remove().invokeWithArgs("All", "a_project"); - assertThat(res, failedWith(-1)); - assertThat(res.stderr(), containsString("'All' view can not be modified directly")); + assertThat(res, failedWith(4)); + assertThat(res.stderr(), containsString("ERROR: 'All' view can not be modified directly")); } @Test @@ -99,12 +99,12 @@ public class ViewManipulationTest { j.createFreeStyleProject("a_project"); res = add().authorizedTo(Jenkins.READ, Job.READ, View.READ).invokeWithArgs("a_view", "a_project"); - assertThat(res, failedWith(-1)); - assertThat(res.stderr(), containsString("user is missing the View/Configure permission")); + assertThat(res, failedWith(6)); + assertThat(res.stderr(), containsString("ERROR: user is missing the View/Configure permission")); res = remove().authorizedTo(Jenkins.READ, Job.READ, View.READ).invokeWithArgs("a_view", "a_project"); - assertThat(res, failedWith(-1)); - assertThat(res.stderr(), containsString("user is missing the View/Configure permission")); + assertThat(res, failedWith(6)); + assertThat(res.stderr(), containsString("ERROR: user is missing the View/Configure permission")); } private CLICommandInvoker add() { diff --git a/test/src/test/java/jenkins/security/Security218CliTest.java b/test/src/test/java/jenkins/security/Security218CliTest.java index 546cdc8fde467d4a78df969d5178f1661bd6926c..ae4cbeac4d9208431d07453270cea780d7bb79f7 100644 --- a/test/src/test/java/jenkins/security/Security218CliTest.java +++ b/test/src/test/java/jenkins/security/Security218CliTest.java @@ -76,7 +76,7 @@ public class Security218CliTest { @Test @Issue("SECURITY-218") public void probeSpring1() throws Exception { - probe(Payload.Spring1, -1); + probe(Payload.Spring1, 1); } private void probe(Payload payload, int expectedResultCode) throws Exception {