提交 fe41dc89 编写于 作者: O Oliver Gondža

Merge pull request #1997 from pjanouse/JENKINS-32273

[JENKINS-32273] Unified an issue handling in CLI
......@@ -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);
......
......@@ -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<ParameterValue> values = new ArrayList<ParameterValue>();
......@@ -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<? extends AbstractBuild> 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."
);
}
......
......@@ -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()
......
......@@ -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
*
* <p>
* 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)
*
* <p>
* Note: For details - see JENKINS-32273
*/
public int main(List<String> 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);
......
......@@ -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));
......
......@@ -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);
......
......@@ -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.
......
......@@ -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);
}
}
......
......@@ -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()));
}
}
......
......@@ -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);
}
......
......@@ -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);
}
......
......@@ -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);
......
......@@ -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);
......
......@@ -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<String> 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<String> hs = new HashSet<String>();
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;
}
}
......@@ -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<String> 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<String> hs = new HashSet<String>();
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;
}
}
......@@ -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<String> 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;
}
}
......@@ -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;
}
......
......@@ -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;
......
......@@ -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());
......
......@@ -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<String> sources = new ArrayList<String>();
@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");
}
}
......@@ -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<String> toolTypes = new ArrayList<String>();
......@@ -101,9 +101,9 @@ public class InstallToolCommand extends CLICommand {
private int error(List<String> 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));
......
......@@ -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<TopLevelItem> 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.");
}
}
}
......
......@@ -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 {
......
......@@ -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;
}
}
......@@ -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<String> hs = new HashSet<String>();
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;
}
}
......@@ -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);
......
......@@ -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);
......
......@@ -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
*
* <p>
* 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)
*
* <p>
* Note: For details - see JENKINS-32273
*/
@Override
public int main(List<String> 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;
......
......@@ -73,9 +73,9 @@ public abstract class GenericItemOptionHandler<T extends Item> 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);
......
......@@ -54,7 +54,7 @@ public class NodeOptionHandler extends OptionHandler<Node> {
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;
......
......@@ -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<View> {
* 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> {
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");
}
}
......
......@@ -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"));
}
/*
......
......@@ -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);
......
......@@ -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));
......
......@@ -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");
......
......@@ -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"));
......
......@@ -78,7 +78,7 @@ public class CreateJobCommandTest {
}
});
cmd.setTransportAuth(User.get("alice").impersonate());
assertThat(invoker.withStdin(new ByteArrayInputStream("<project/>".getBytes("US-ASCII"))).invokeWithArgs("d/p"), failedWith(-1));
assertThat(invoker.withStdin(new ByteArrayInputStream("<project/>".getBytes("US-ASCII"))).invokeWithArgs("d/p"), failedWith(6));
cmd.setTransportAuth(User.get("bob").impersonate());
assertThat(invoker.withStdin(new ByteArrayInputStream("<project/>".getBytes("US-ASCII"))).invokeWithArgs("d/p"), succeededSilently());
assertNotNull(d.getItem("p"));
......
......@@ -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));
}
}
......@@ -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"));
}
}
......@@ -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");
......
......@@ -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);
......
......@@ -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());
......
......@@ -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());
}
}
......@@ -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"));
}
}
......@@ -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."));
}
......
......@@ -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"));
......
......@@ -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 {
......
......@@ -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());
}
}
......@@ -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"));
}
}
......@@ -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() {
......
......@@ -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 {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册