aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>2015-04-21 15:14:48 +0200
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>2015-04-23 15:56:07 +0200
commit0551314b3594aac3f2ec9690999db7a413f5bb89 (patch)
tree0f49ac5a4379315f3242563920d260d90d31d7da
parent95e69a01662afe0ec65636ba4c5afeada4cb51e8 (diff)
downloadsonarqube-0551314b3594aac3f2ec9690999db7a413f5bb89.tar.gz
sonarqube-0551314b3594aac3f2ec9690999db7a413f5bb89.zip
SONAR-6381 add java WS to install a plugin
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstallPluginsWsAction.java105
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstallPluginsWsActionTest.java135
3 files changed, 242 insertions, 0 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
index 08be0f8b8b5..3d1f3456f2f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
@@ -217,6 +217,7 @@ import org.sonar.server.plugins.ServerPluginRepository;
import org.sonar.server.plugins.UpdateCenterClient;
import org.sonar.server.plugins.UpdateCenterMatrixFactory;
import org.sonar.server.plugins.ws.AvailablePluginsWsAction;
+import org.sonar.server.plugins.ws.InstallPluginsWsAction;
import org.sonar.server.plugins.ws.InstalledPluginsWsAction;
import org.sonar.server.plugins.ws.PendingPluginsWsAction;
import org.sonar.server.plugins.ws.PluginWSCommons;
@@ -892,6 +893,7 @@ class ServerComponents {
pico.addSingleton(AvailablePluginsWsAction.class);
pico.addSingleton(UpdatesPluginsWsAction.class);
pico.addSingleton(PendingPluginsWsAction.class);
+ pico.addSingleton(InstallPluginsWsAction.class);
pico.addSingleton(UpdatePluginsWsAction.class);
pico.addSingleton(PluginsWs.class);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstallPluginsWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstallPluginsWsAction.java
new file mode 100644
index 00000000000..117c84f7251
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstallPluginsWsAction.java
@@ -0,0 +1,105 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.plugins.ws;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.server.plugins.PluginDownloader;
+import org.sonar.server.plugins.UpdateCenterMatrixFactory;
+import org.sonar.server.user.UserSession;
+import org.sonar.updatecenter.common.PluginUpdate;
+
+import javax.annotation.Nullable;
+
+import static java.lang.String.format;
+
+/**
+ * Implementation of the {@code install} action for the Plugins WebService.
+ */
+public class InstallPluginsWsAction implements PluginsWsAction {
+
+ private static final String PARAM_KEY = "key";
+ private static final PluginUpdate MISSING_PLUGIN = null;
+
+ private final UpdateCenterMatrixFactory updateCenterFactory;
+ private final PluginDownloader pluginDownloader;
+
+ public InstallPluginsWsAction(UpdateCenterMatrixFactory updateCenterFactory,
+ PluginDownloader pluginDownloader) {
+ this.updateCenterFactory = updateCenterFactory;
+ this.pluginDownloader = pluginDownloader;
+ }
+
+ @Override
+ public void define(WebService.NewController controller) {
+ WebService.NewAction action = controller.createAction("install")
+ .setPost(true)
+ .setDescription("Installs the latest version of a plugin specified by its key." +
+ "<br/>" +
+ "Requires user to be authenticated with Administer System permissions")
+ .setHandler(this);
+
+ action.createParam(PARAM_KEY).setRequired(true)
+ .setDescription("The key identifying the plugin to install");
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ UserSession.get().checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN);
+ String key = request.mandatoryParam(PARAM_KEY);
+ PluginUpdate pluginUpdate = findAvailablePluginByKey(key);
+ pluginDownloader.download(key, pluginUpdate.getRelease().getVersion());
+ response.noContent();
+ }
+
+ private PluginUpdate findAvailablePluginByKey(String key) {
+ PluginUpdate pluginUpdate = Iterables.find(
+ updateCenterFactory.getUpdateCenter(false).findAvailablePlugins(),
+ hasKey(key),
+ MISSING_PLUGIN
+ );
+ if (pluginUpdate == MISSING_PLUGIN) {
+ throw new IllegalArgumentException(
+ format("No plugin with key '%s' or plugin '%s' is already installed in latest version", key, key));
+ }
+ return pluginUpdate;
+ }
+
+ private static PluginKeyPredicate hasKey(String key) {
+ return new PluginKeyPredicate(key);
+ }
+
+ private static class PluginKeyPredicate implements Predicate<PluginUpdate> {
+ private final String key;
+
+ public PluginKeyPredicate(String key) {
+ this.key = key;
+ }
+
+ @Override
+ public boolean apply(@Nullable PluginUpdate input) {
+ return input != null && key.equals(input.getPlugin().getKey());
+ }
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstallPluginsWsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstallPluginsWsActionTest.java
new file mode 100644
index 00000000000..5eaa8440e1a
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstallPluginsWsActionTest.java
@@ -0,0 +1,135 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.plugins.ws;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.plugins.PluginDownloader;
+import org.sonar.server.plugins.UpdateCenterMatrixFactory;
+import org.sonar.server.user.MockUserSession;
+import org.sonar.server.ws.WsTester;
+import org.sonar.updatecenter.common.Plugin;
+import org.sonar.updatecenter.common.PluginUpdate;
+import org.sonar.updatecenter.common.Release;
+import org.sonar.updatecenter.common.UpdateCenter;
+import org.sonar.updatecenter.common.Version;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class InstallPluginsWsActionTest {
+ private static final String DUMMY_CONTROLLER_KEY = "dummy";
+ private static final String CONTROLLER_KEY = "api/plugins";
+ private static final String ACTION_KEY = "install";
+ private static final String KEY_PARAM = "key";
+ private static final String PLUGIN_KEY = "pluginKey";
+
+ private UpdateCenterMatrixFactory updateCenterFactory = mock(UpdateCenterMatrixFactory.class);
+ private UpdateCenter updateCenter = mock(UpdateCenter.class);
+ private PluginDownloader pluginDownloader = mock(PluginDownloader.class);
+ private InstallPluginsWsAction underTest = new InstallPluginsWsAction(updateCenterFactory, pluginDownloader);
+
+ private WsTester wsTester = new WsTester(new PluginsWs(underTest));
+ private WsTester.TestRequest invalidRequest = wsTester.newPostRequest(CONTROLLER_KEY, ACTION_KEY);
+ private WsTester.TestRequest validRequest = wsTester.newPostRequest(CONTROLLER_KEY, ACTION_KEY)
+ .setParam(KEY_PARAM, PLUGIN_KEY);
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Before
+ public void wireMocks() throws Exception {
+ when(updateCenterFactory.getUpdateCenter(anyBoolean())).thenReturn(updateCenter);
+
+ MockUserSession.set().setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+ }
+
+ @Test
+ public void user_must_have_system_admin_permission() throws Exception {
+ expectedException.expect(ForbiddenException.class);
+ expectedException.expectMessage("Insufficient privileges");
+
+ // no permission on user
+ MockUserSession.set().setGlobalPermissions();
+
+ validRequest.execute();
+ }
+
+ @Test
+ public void action_install_is_defined() throws Exception {
+ WsTester wsTester = new WsTester();
+ WebService.NewController newController = wsTester.context().createController(DUMMY_CONTROLLER_KEY);
+
+ underTest.define(newController);
+ newController.done();
+
+ WebService.Controller controller = wsTester.controller(DUMMY_CONTROLLER_KEY);
+ assertThat(controller.actions()).extracting("key").containsExactly(ACTION_KEY);
+
+ WebService.Action action = controller.actions().iterator().next();
+ assertThat(action.isPost()).isTrue();
+ assertThat(action.description()).isNotEmpty();
+ assertThat(action.responseExample()).isNull();
+
+ assertThat(action.params()).hasSize(1);
+ WebService.Param keyParam = action.param(KEY_PARAM);
+ assertThat(keyParam).isNotNull();
+ assertThat(keyParam.isRequired()).isTrue();
+ assertThat(keyParam.description()).isNotNull();
+ }
+
+ @Test
+ public void IAE_is_raised_when_key_param_is_not_provided() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Parameter 'key' is missing");
+
+ invalidRequest.execute();
+ }
+
+ @Test
+ public void IAE_is_raised_when_there_is_no_available_plugin_for_the_key() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("No plugin with key 'pluginKey'");
+
+ validRequest.execute();
+ }
+
+ @Test
+ public void if_plugin_is_found_available_download_is_triggered_with_latest_version_from_updatecenter() throws Exception {
+ Version version = Version.create("1.0");
+ when(updateCenter.findAvailablePlugins()).thenReturn(ImmutableList.of(
+ PluginUpdate.createWithStatus(new Release(new Plugin(PLUGIN_KEY), version), PluginUpdate.Status.COMPATIBLE)
+ ));
+
+ WsTester.Result result = validRequest.execute();
+
+ verify(pluginDownloader).download(PLUGIN_KEY, version);
+ result.assertNoContent();
+ }
+}