]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6381 add java WS to install a plugin 239/head
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Tue, 21 Apr 2015 13:14:48 +0000 (15:14 +0200)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 23 Apr 2015 13:56:07 +0000 (15:56 +0200)
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstallPluginsWsAction.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstallPluginsWsActionTest.java [new file with mode: 0644]

index 08be0f8b8b562977be8f7ff2aa85cd7c01d20806..3d1f3456f2f401c6894c250435c48cb091a47dcf 100644 (file)
@@ -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 (file)
index 0000000..117c84f
--- /dev/null
@@ -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 (file)
index 0000000..5eaa844
--- /dev/null
@@ -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();
+  }
+}