Navigation Menu

Skip to content

Commit

Permalink
[JENKINS-28041] Extended delete-job CLI command to accept multiple na…
Browse files Browse the repository at this point in the history
…mes to delete
  • Loading branch information
pjanouse committed May 7, 2015
1 parent 67e4e88 commit c05b80f
Show file tree
Hide file tree
Showing 21 changed files with 256 additions and 11 deletions.
92 changes: 92 additions & 0 deletions core/src/main/java/hudson/cli/DeleteJobCommand.java
@@ -0,0 +1,92 @@
/*
* The MIT License
*
* Copyright (c) 2015 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.cli;

import hudson.Extension;
import hudson.model.AbstractItem;
import hudson.model.AbstractProject;
import hudson.model.View;
import hudson.model.ViewGroup;
import jenkins.model.Jenkins;
import org.kohsuke.args4j.Argument;

import java.util.List;
import java.util.HashSet;

/**
* @author pjanouse
* @since TODO
*/
@Extension
public class DeleteJobCommand extends CLICommand {

@Argument(usage="Name of the job(s) to delete", required=true, multiValued=true)
private List<String> jobs;

@Override
public String getShortDescription() {

return Messages.DeleteJobCommand_ShortDescription();
}

@Override
protected int run() throws Exception {

boolean errorOccurred = false;

HashSet<String> hs = new HashSet<String>();
hs.addAll(jobs);

for (String job_s: hs) {
AbstractItem job = (AbstractItem) Jenkins.getInstance().getItemByFullName(job_s);

if(job == null) {
stderr.format("No such job '%s'\n", job_s);
errorOccurred = true;
continue;
}

try {
job.checkPermission(AbstractItem.READ);
job.checkPermission(AbstractItem.DELETE);
} catch (Exception e) {
stderr.println(e.getMessage());
errorOccurred = true;
continue;
}

try {
job.delete();
} catch (Exception e) {
stderr.format("Unexpected exception occurred during deletion of job '%s': %s\n",
job.getDisplayName(),
e.getMessage()
);
errorOccurred = true;
continue;
}
}
return errorOccurred ? -1 : 0;
}
}
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/model/AbstractItem.java
Expand Up @@ -538,7 +538,7 @@ public synchronized void doSubmitDescription( StaplerRequest req, StaplerRespons
* since it predates {@code <l:confirmationLink>}. {@code /delete} goes to a Jelly page
* which should now be unused by core but is left in case plugins are still using it.
*/
@CLIMethod(name="delete-job")
// @CLIMethod(name="delete-job")
@RequirePOST
public void doDoDelete( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException, InterruptedException {
delete();
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/resources/hudson/cli/Messages.properties
Expand Up @@ -22,6 +22,8 @@ DeleteBuildsCommand.ShortDescription=\
Deletes build record(s).
DeleteViewCommand.ShortDescription=\
Deletes view(s).
DeleteJobCommand.ShortDescription=\
Deletes job(s).
GroovyCommand.ShortDescription=\
Executes the specified Groovy script.
GroovyshCommand.ShortDescription=\
Expand Down
1 change: 1 addition & 0 deletions core/src/main/resources/hudson/cli/Messages_da.properties
@@ -1 +1,2 @@
DeleteNodeCommand.ShortDescription=Sletter en node
DeleteJobCommand.ShortDescription=Sletter et job
1 change: 1 addition & 0 deletions core/src/main/resources/hudson/cli/Messages_de.properties
@@ -1 +1,2 @@
DeleteNodeCommand.ShortDescription=Knoten l\u00f6schen.
DeleteJobCommand.ShortDescription=Job l\u00f6schen.
1 change: 1 addition & 0 deletions core/src/main/resources/hudson/cli/Messages_es.properties
Expand Up @@ -47,5 +47,6 @@ WhoAmICommand.ShortDescription=Muestra tus credenciales y permisos
UpdateJobCommand.ShortDescription=Actualiza el fichero XML de la definición de una tarea desde la entrada estándard. Es lo contrario al comando get-job.
GroovyshCommand.ShortDescription=Ejecuta una shell interactiva de groovy.
SetBuildDescriptionCommand.ShortDescription=Establece la descripción de una ejecución.
DeleteJobCommand.ShortDescription=Borrar una tarea

DeleteNodeCommand.ShortDescription=Borrar un nodo
1 change: 1 addition & 0 deletions core/src/main/resources/hudson/cli/Messages_it.properties
@@ -1 +1,2 @@
DeleteNodeCommand.ShortDescription=Cancella un nodo
DeleteJobCommand.ShortDescription=Cancella un job
1 change: 1 addition & 0 deletions core/src/main/resources/hudson/cli/Messages_ja.properties
Expand Up @@ -71,3 +71,4 @@ BuildCommand.CLICause.CannotBuildUnknownReasons=\
\u30d3\u30eb\u30c9\u3067\u304d\u307e\u305b\u3093(\u539f\u56e0\u4e0d\u660e)\u3002

DeleteNodeCommand.ShortDescription=\u30ce\u30fc\u30c9\u3092\u524a\u9664\u3057\u307e\u3059\u3002
DeleteJobCommand.ShortDescription=\u30b8\u30e7\u30d6\u3092\u524a\u9664\u3057\u307e\u3059\u3002
2 changes: 2 additions & 0 deletions core/src/main/resources/hudson/cli/Messages_pt_BR.properties
Expand Up @@ -113,3 +113,5 @@ InstallPluginCommand.ShortDescription=Instala um plugin a partir de um arquivo,

# Deletes a node
CLI.delete-node.shortDescription=Remover o n\u00f3
# Deletes a job
DeleteJobCommand.ShortDescription=Remover uma job
@@ -1 +1,2 @@
DeleteNodeCommand.ShortDescription=Deletes a node
DeleteJobCommand.ShortDescription=Deletes a job
Expand Up @@ -74,3 +74,4 @@ UpdateJobCommand.ShortDescription=\
BuildCommand.CLICause.ShortDescription=\u7531 {0} \u7684\u547d\u4ee4\u5217\u4ecb\u9762\u555f\u52d5

DeleteNodeCommand.ShortDescription=\u522a\u9664\u6307\u5b9a\u7bc0\u9ede\u3002
DeleteJobCommand.ShortDescription=\u522a\u9664\u4f5c\u696d\u3002
1 change: 0 additions & 1 deletion core/src/main/resources/hudson/model/Messages.properties
Expand Up @@ -93,7 +93,6 @@ BallColor.Success=Success
BallColor.Unstable=Unstable

CLI.clear-queue.shortDescription=Clears the build queue.
CLI.delete-job.shortDescription=Deletes a job.
CLI.reload-job.shortDescription=Reloads this job from disk.
CLI.disable-job.shortDescription=Disables a job.
CLI.enable-job.shortDescription=Enables a job.
Expand Down
Expand Up @@ -82,7 +82,6 @@ UpdateCenter.PluginCategory.cli=Kommandolinieinterface
UpdateCenter.PluginCategory.builder=Byggev\u00e6rkt\u00f8jer
Slave.UnixSlave=Dette er en Unix slave
FileParameterDefinition.DisplayName=Filparametre
CLI.delete-job.shortDescription=Sletter et job
Run.Summary.Unstable=Ustabil
CLI.reload-configuration.shortDescription=Genindl\u00e6s alle data fra filsystemet. \
Nyttigt hvis du har modificeret konfigurationsfiler direkte, udenom Jenkins.
Expand Down
Expand Up @@ -83,7 +83,6 @@ CLI.quiet-down.shortDescription=Jenkins' Aktivit\u00e4t reduzieren, z.B. zur Vor
CLI.cancel-quiet-down.shortDescription=Wirkung des Befehls "quiet-down" wieder aufheben.
CLI.reload-configuration.shortDescription=Alle Daten im Speicher verwerfen und Konfiguration neu von Festplatte laden. Dies ist n\u00fctzlich, wenn Sie \u00c4nderungen direkt im Dateisystem vorgenommen haben.
CLI.clear-queue.shortDescription=Build-Warteschlange l\u00f6schen.
CLI.delete-job.shortDescription=Job l\u00f6schen.
CLI.disable-job.shortDescription=Job deaktivieren.
CLI.enable-job.shortDescription=Job aktivieren.
CLI.connect-node.shortDescription=Erneut mit Knoten verbinden.
Expand Down
Expand Up @@ -59,7 +59,6 @@ BallColor.Success=Correcto
BallColor.Unstable=Inestable

CLI.clear-queue.shortDescription=Limpiar la cola de trabajos
CLI.delete-job.shortDescription=Borrar una tarea
CLI.disable-job.shortDescription=Desactivar una tarea
CLI.enable-job.shortDescription=Activar una tarea
CLI.disconnect-node.shortDescription=Desconectarse de un nodo
Expand Down
Expand Up @@ -77,7 +77,6 @@ BallColor.Success=Successo
BallColor.Unstable=Instabile

CLI.clear-queue.shortDescription=Pulisce la coda di lavoro
CLI.delete-job.shortDescription=Cancella un job
CLI.disable-job.shortDescription=Disabilita un job
CLI.enable-job.shortDescription=Abilita un job
CLI.disconnect-node.shortDescription=Disconnects from a node
Expand Down
Expand Up @@ -320,7 +320,6 @@ CLI.quiet-down.shortDescription=Jenkins\u306f\u518d\u8d77\u52d5\u306b\u5411\u305
CLI.cancel-quiet-down.shortDescription="quite-down"\u30b3\u30de\u30f3\u30c9\u306e\u51e6\u7406\u3092\u30ad\u30e3\u30f3\u30bb\u30eb\u3057\u307e\u3059\u3002
CLI.reload-configuration.shortDescription=\u30e1\u30e2\u30ea\u306b\u3042\u308b\u3059\u3079\u3066\u306e\u30c7\u30fc\u30bf\u3092\u7834\u68c4\u3057\u3066\u3001\u30d5\u30a1\u30a4\u30eb\u304b\u3089\u518d\u30ed\u30fc\u30c9\u3057\u307e\u3059\u3002\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3092\u76f4\u63a5\u4fee\u6b63\u3057\u305f\u5834\u5408\u306b\u5f79\u306b\u7acb\u3061\u307e\u3059\u3002
CLI.clear-queue.shortDescription=\u30d3\u30eb\u30c9\u30ad\u30e5\u30fc\u3092\u30af\u30ea\u30a2\u3057\u307e\u3059\u3002
CLI.delete-job.shortDescription=\u30b8\u30e7\u30d6\u3092\u524a\u9664\u3057\u307e\u3059\u3002
CLI.disable-job.shortDescription=\u30b8\u30e7\u30d6\u3092\u7121\u52b9\u5316\u3057\u307e\u3059\u3002
CLI.enable-job.shortDescription=\u30b8\u30e7\u30d6\u3092\u6709\u52b9\u5316\u3057\u307e\u3059\u3002
CLI.disconnect-node.shortDescription=\u30ce\u30fc\u30c9\u3068\u306e\u63a5\u7d9a\u3092\u5207\u65ad\u3057\u307e\u3059\u3002
Expand Down
Expand Up @@ -187,8 +187,6 @@ UpdateCenter.PluginCategory.builder=Ferramentas de build
# File Parameter
FileParameterDefinition.DisplayName=Par\u00e2metros de arquivo
# {0} {0,choice,0#tests are|1#test is|1<tests are} still failing
# Deletes a job
CLI.delete-job.shortDescription=Remover uma job
# unstable
Run.Summary.Unstable=Inst\u00e1vel
# Discard all the loaded data in memory and reload everything from file system. Useful when you modified config files directly on disk.
Expand Down
Expand Up @@ -63,7 +63,6 @@ BallColor.Success=Success
BallColor.Unstable=Unstable

CLI.clear-queue.shortDescription=Clears the build queue
CLI.delete-job.shortDescription=Deletes a job
CLI.disable-job.shortDescription=Disables a job
CLI.enable-job.shortDescription=Enables a job
CLI.disconnect-node.shortDescription=Disconnects from a node
Expand Down
Expand Up @@ -82,7 +82,6 @@ BallColor.Success=\u6210\u529f
BallColor.Unstable=\u4e0d\u7a69\u5b9a

CLI.clear-queue.shortDescription=\u6e05\u9664\u5efa\u7f6e\u4f47\u5217\u3002
CLI.delete-job.shortDescription=\u522a\u9664\u4f5c\u696d\u3002
CLI.disable-job.shortDescription=\u505c\u7528\u4f5c\u696d\u3002
CLI.enable-job.shortDescription=\u555f\u7528\u4f5c\u696d\u3002
CLI.disconnect-node.shortDescription=\u4e2d\u65b7\u8207\u6307\u5b9a\u7bc0\u9ede\u7684\u9023\u7dda\u3002
Expand Down
152 changes: 152 additions & 0 deletions test/src/test/java/hudson/cli/DeleteJobCommandTest.java
@@ -0,0 +1,152 @@
/*
* The MIT License
*
* Copyright 2015 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package hudson.cli;

import hudson.model.Job;
import jenkins.model.Jenkins;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;

import java.io.IOException;

import static hudson.cli.CLICommandInvoker.Matcher.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.nullValue;

/**
* @author pjanouse
* @since TODO
*/
public class DeleteJobCommandTest {

private CLICommandInvoker command;

@Rule public final JenkinsRule j = new JenkinsRule();

@Before public void setUp() {

command = new CLICommandInvoker(j, new DeleteJobCommand());
}

@Test public void deleteJobShouldFailWithoutJobDeletePermission() throws IOException {

j.createFreeStyleProject("aProject");

final CLICommandInvoker.Result result = command
.authorizedTo(Job.READ, Jenkins.READ)
.invokeWithArgs("aProject");

assertThat(result, failedWith(-1));
assertThat(result, hasNoStandardOutput());
assertThat(result.stderr(), containsString("user is missing the Job/Delete permission"));
}

@Test public void deleteJobShouldFailWithoutJobReadPermission() throws IOException {

j.createFreeStyleProject("aProject");

final CLICommandInvoker.Result result = command
.authorizedTo(Job.DELETE, Jenkins.READ)
.invokeWithArgs("aProject");

assertThat(result, failedWith(-1));
assertThat(result, hasNoStandardOutput());
assertThat(result.stderr(), containsString("No such job 'aProject'"));
}

@Test public void deleteJobShouldSucceed() throws Exception {

j.createFreeStyleProject("aProject");

final CLICommandInvoker.Result result = command
.authorizedTo(Job.READ, Job.DELETE, Jenkins.READ)
.invokeWithArgs("aProject");

assertThat(result, succeededSilently());
assertThat(j.jenkins.getItem("aProject"), nullValue());
}

@Test public void deleteJobShouldFailIfJobDoesNotExist() {

final CLICommandInvoker.Result result = command
.authorizedTo(Job.READ, Job.DELETE, Jenkins.READ)
.invokeWithArgs("never_created");

assertThat(result, failedWith(-1));
assertThat(result, hasNoStandardOutput());
assertThat(result.stderr(), containsString("No such job 'never_created'"));
}

@Test public void deleteJobManyShouldSucceed() throws Exception {

j.createFreeStyleProject("aProject1");
j.createFreeStyleProject("aProject2");
j.createFreeStyleProject("aProject3");

final CLICommandInvoker.Result result = command
.authorizedTo(Job.READ, Job.DELETE, Jenkins.READ)
.invokeWithArgs("aProject1", "aProject2", "aProject3");

assertThat(result, succeededSilently());
assertThat(j.jenkins.getItem("aProject1"), nullValue());
assertThat(j.jenkins.getItem("aProject2"), nullValue());
assertThat(j.jenkins.getItem("aProject3"), nullValue());
}

@Test public void deleteJobManyShouldFailIfAJobDoesNotExist() throws Exception {

j.createFreeStyleProject("aProject1");
j.createFreeStyleProject("aProject2");

final CLICommandInvoker.Result result = command
.authorizedTo(Job.READ, Job.DELETE, Jenkins.READ)
.invokeWithArgs("aProject1", "aProject2", "never_created");

assertThat(result, failedWith(-1));
assertThat(result, hasNoStandardOutput());
assertThat(result.stderr(), containsString("No such job 'never_created'"));

assertThat(j.jenkins.getItem("aProject1"), nullValue());
assertThat(j.jenkins.getItem("aProject2"), nullValue());
assertThat(j.jenkins.getItem("never_created"), nullValue());
}

@Test public void deleteJobManyShouldSucceedEvenAJobIsSpecifiedTwice() throws Exception {

j.createFreeStyleProject("aProject1");
j.createFreeStyleProject("aProject2");

final CLICommandInvoker.Result result = command
.authorizedTo(Job.READ, Job.DELETE, Jenkins.READ)
.invokeWithArgs("aProject1", "aProject2", "aProject1");

assertThat(result, succeededSilently());
assertThat(j.jenkins.getItem("aProject1"), nullValue());
assertThat(j.jenkins.getItem("aProject2"), nullValue());
}
}

0 comments on commit c05b80f

Please sign in to comment.