diff --git a/core/src/main/java/hudson/cli/AddJobToViewCommand.java b/core/src/main/java/hudson/cli/AddJobToViewCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..a34ae3b627f3d18b7798d6bd3a49556285f68f15 --- /dev/null +++ b/core/src/main/java/hudson/cli/AddJobToViewCommand.java @@ -0,0 +1,68 @@ +/* + * The MIT License + * + * Copyright (c) 2014 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 java.util.List; + +import hudson.Extension; +import hudson.model.TopLevelItem; +import hudson.model.DirectlyModifiableView; +import hudson.model.View; + +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.CmdLineException; + +/** + * @author ogondza + * @since TODO + */ +@Extension +public class AddJobToViewCommand extends CLICommand { + + @Argument(usage="Name of the view", required=true, index=0) + private View view; + + @Argument(usage="Job names", required=true, index=1) + private List jobs; + + @Override + public String getShortDescription() { + return Messages.AddJobToViewCommand_ShortDescription(); + } + + @Override + 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" + ); + + for (TopLevelItem job: jobs) { + ((DirectlyModifiableView) view).add(job); + } + + return 0; + } +} diff --git a/core/src/main/java/hudson/cli/RemoveJobFromViewCommand.java b/core/src/main/java/hudson/cli/RemoveJobFromViewCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..fe01cfa18a50f6ae188baca8d65871ac90874435 --- /dev/null +++ b/core/src/main/java/hudson/cli/RemoveJobFromViewCommand.java @@ -0,0 +1,68 @@ +/* + * The MIT License + * + * Copyright (c) 2014 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 java.util.List; + +import hudson.Extension; +import hudson.model.TopLevelItem; +import hudson.model.DirectlyModifiableView; +import hudson.model.View; + +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.CmdLineException; + +/** + * @author ogondza + * @since TODO + */ +@Extension +public class RemoveJobFromViewCommand extends CLICommand { + + @Argument(usage="Name of the view", required=true, index=0) + private View view; + + @Argument(usage="Job names", required=true, index=1) + private List jobs; + + @Override + public String getShortDescription() { + return Messages.RemoveJobFromViewCommand_ShortDescription(); + } + + @Override + 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" + ); + + for (TopLevelItem job: jobs) { + ((DirectlyModifiableView) view).remove(job); + } + + return 0; + } +} diff --git a/core/src/main/resources/hudson/cli/Messages.properties b/core/src/main/resources/hudson/cli/Messages.properties index f831782c13306f95d5ba68ac26590482a28dafdb..2abac75d8121a2f3fc0da43cade756e433ffcf7f 100644 --- a/core/src/main/resources/hudson/cli/Messages.properties +++ b/core/src/main/resources/hudson/cli/Messages.properties @@ -6,6 +6,8 @@ InstallPluginCommand.NoUpdateCenterDefined=Note that no update center is defined InstallPluginCommand.NoUpdateDataRetrieved=No update center data is retrieved yet from: {0} InstallPluginCommand.NotAValidSourceName={0} is neither a valid file, URL, nor a plugin artifact name in the update center +AddJobToViewCommand.ShortDescription=\ + Adds jobs to view. BuildCommand.ShortDescription=\ Builds a job, and optionally waits until its completion. ConsoleCommand.ShortDescription=Retrieves console output of a build. @@ -47,6 +49,8 @@ SetBuildDescriptionCommand.ShortDescription=\ SetBuildParameterCommand.ShortDescription=Update/set the build parameter of the current build in progress. SetBuildResultCommand.ShortDescription=\ Sets the result of the current build. Works only if invoked from within a build. +RemoveJobFromViewCommand.ShortDescription=\ + Removes jobs from view. VersionCommand.ShortDescription=\ Outputs the current version. GetJobCommand.ShortDescription=\ diff --git a/test/src/test/java/hudson/cli/ViewManipulationTest.java b/test/src/test/java/hudson/cli/ViewManipulationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b77ea0854e4aa32238b916cf4f4a7e1c85b5cb82 --- /dev/null +++ b/test/src/test/java/hudson/cli/ViewManipulationTest.java @@ -0,0 +1,117 @@ +/* + * The MIT License + * + * Copyright (c) 2014 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 static org.junit.Assert.*; +import static hudson.cli.CLICommandInvoker.Matcher.*; +import static org.hamcrest.Matchers.*; + +import jenkins.model.Jenkins; +import hudson.cli.CLICommandInvoker.Result; +import hudson.model.FreeStyleProject; +import hudson.model.Job; +import hudson.model.ListView; +import hudson.model.View; + +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +public class ViewManipulationTest { + + @Rule public final JenkinsRule j = new JenkinsRule(); + + private Result res; + + @Test + public void addJobToView() throws Exception { + ListView view = new ListView("a_view"); + j.jenkins.addView(view); + FreeStyleProject inView = j.createFreeStyleProject("in_view"); + FreeStyleProject inView2 = j.createFreeStyleProject("in_view2"); + FreeStyleProject notInView = j.createFreeStyleProject("not_in_view"); + + res = add().invokeWithArgs("a_view", "in_view", "in_view2"); + assertThat(res, succeededSilently()); + + assertTrue(view.contains(inView)); + assertTrue(view.contains(inView2)); + assertFalse(view.contains(notInView)); + } + + @Test + public void removeJobFromView() throws Exception { + ListView view = new ListView("a_view"); + j.jenkins.addView(view); + FreeStyleProject inView = j.createFreeStyleProject("in_view"); + FreeStyleProject removed = j.createFreeStyleProject("removed"); + FreeStyleProject removed2 = j.createFreeStyleProject("removed2"); + view.add(inView); + view.add(removed); + view.add(removed2); + + res = remove().invokeWithArgs("a_view", "removed", "removed2"); + assertThat(res, succeededSilently()); + + assertTrue(view.contains(inView)); + assertFalse(view.contains(removed)); + assertFalse(view.contains(removed2)); + } + + @Test + public void failIfTheViewIsNotDirectlyModifiable() throws Exception { + 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")); + + res = remove().invokeWithArgs("All", "a_project"); + assertThat(res, failedWith(-1)); + assertThat(res.stderr(), containsString("'All' view can not be modified directly")); + } + + @Test + public void failIfUserNotAuthorizedToConfigure() throws Exception { + ListView view = new ListView("a_view"); + j.jenkins.addView(view); + 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")); + + 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")); + } + + private CLICommandInvoker add() { + return new CLICommandInvoker(j, new AddJobToViewCommand()); + } + + private CLICommandInvoker remove() { + return new CLICommandInvoker(j, new RemoveJobFromViewCommand()); + } +}