From: Sébastien Lesaint Date: Thu, 23 Apr 2015 07:00:01 +0000 (+0200) Subject: SONAR-6385 add WS to list SonarQube upgrades X-Git-Tag: 5.2-RC1~2120 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=refs%2Fpull%2F256%2Fhead;p=sonarqube.git SONAR-6385 add WS to list SonarQube upgrades --- 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 16aa1ea53ff..e0c14535118 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 @@ -19,13 +19,7 @@ */ package org.sonar.server.platform; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Properties; - -import javax.annotation.Nullable; - +import com.google.common.collect.Lists; import org.sonar.api.config.EmailSettings; import org.sonar.api.issue.action.Actions; import org.sonar.api.platform.ComponentContainer; @@ -214,6 +208,7 @@ import org.sonar.server.platform.ws.ServerWs; import org.sonar.server.platform.ws.SystemInfoWsAction; import org.sonar.server.platform.ws.SystemRestartWsAction; import org.sonar.server.platform.ws.SystemWs; +import org.sonar.server.platform.ws.UpgradesSystemWsAction; import org.sonar.server.plugins.InstalledPluginReferentialFactory; import org.sonar.server.plugins.PluginDownloader; import org.sonar.server.plugins.ServerExtensionInstaller; @@ -392,7 +387,11 @@ import org.sonar.server.view.index.ViewIndexer; import org.sonar.server.ws.ListingWs; import org.sonar.server.ws.WebServiceEngine; -import com.google.common.collect.Lists; +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Properties; class ServerComponents { @@ -883,6 +882,7 @@ class ServerComponents { pico.addSingletons(Arrays.asList( SystemRestartWsAction.class, SystemInfoWsAction.class, + UpgradesSystemWsAction.class, SystemWs.class, SystemMonitor.class, SonarQubeMonitor.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/UpgradesSystemWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/UpgradesSystemWsAction.java new file mode 100644 index 00000000000..d3c9d4fea27 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/UpgradesSystemWsAction.java @@ -0,0 +1,156 @@ +/* + * 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.platform.ws; + +import java.util.List; + +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; +import org.sonar.api.utils.text.JsonWriter; +import org.sonar.server.plugins.UpdateCenterMatrixFactory; +import org.sonar.updatecenter.common.Plugin; +import org.sonar.updatecenter.common.Release; +import org.sonar.updatecenter.common.SonarUpdate; +import org.sonar.updatecenter.common.UpdateCenter; + +import com.google.common.io.Resources; + +/** + * Implementation of the {@code upgrades} action for the System WebService. + */ +public class UpgradesSystemWsAction implements SystemWsAction { + + private static final boolean DO_NOT_FORCE_REFRESH = false; + private static final String ARRAY_UPGRADES = "upgrades"; + private static final String PROPERTY_NAME = "name"; + private static final String PROPERTY_UPDATE_CENTER_REFRESH = "updateCenterRefresh"; + private static final String PROPERTY_VERSION = "version"; + private static final String PROPERTY_DESCRIPTION = "description"; + private static final String PROPERTY_RELEASE_DATE = "releaseDate"; + private static final String PROPERTY_CHANGE_LOG_URL = "changeLogUrl"; + private static final String PROPERTY_DOWNLOAD_URL = "downloadUrl"; + private static final String OBJECT_PLUGINS = "plugins"; + private static final String ARRAY_REQUIRE_UPDATE = "requireUpdate"; + private static final String PROPERTY_KEY = "key"; + private static final String ARRAY_INCOMPATIBLE = "incompatible"; + + private final UpdateCenterMatrixFactory updateCenterFactory; + + public UpgradesSystemWsAction(UpdateCenterMatrixFactory updateCenterFactory) { + this.updateCenterFactory = updateCenterFactory; + } + + @Override + public void define(WebService.NewController controller) { + controller.createAction("upgrades") + .setDescription("Lists available upgrades for the SonarQube instance (if any) and for each one, " + + "lists incompatible plugins and plugins requiring upgrade." + + "
" + + "Plugin information is retrieved from Update Center. Date and time at which Update Center was last refreshed " + + "is provided in the response.") + .setHandler(this) + .setResponseExample(Resources.getResource(this.getClass(), "example-updates_plugins.json")); + } + + @Override + public void handle(Request request, Response response) throws Exception { + JsonWriter jsonWriter = response.newJsonWriter().setSerializeEmptys(false); + + jsonWriter.beginObject(); + UpdateCenter updateCenter = updateCenterFactory.getUpdateCenter(DO_NOT_FORCE_REFRESH); + writeUpgrades(jsonWriter, updateCenter); + jsonWriter.propDateTime(PROPERTY_UPDATE_CENTER_REFRESH, updateCenter.getDate()); + jsonWriter.endObject(); + + jsonWriter.close(); + } + + private void writeUpgrades(JsonWriter jsonWriter, UpdateCenter updateCenter) { + jsonWriter.name(ARRAY_UPGRADES).beginArray(); + + for (SonarUpdate sonarUpdate : updateCenter.findSonarUpdates()) { + writeUpgrade(jsonWriter, sonarUpdate); + } + + jsonWriter.endArray(); + } + + private void writeUpgrade(JsonWriter jsonWriter, SonarUpdate sonarUpdate) { + jsonWriter.beginObject(); + + writeMetadata(jsonWriter, sonarUpdate.getRelease()); + + writePlugins(jsonWriter, sonarUpdate); + + jsonWriter.endObject(); + } + + private void writeMetadata(JsonWriter jsonWriter, Release release) { + jsonWriter.prop(PROPERTY_VERSION, release.getVersion().getName()); + jsonWriter.prop(PROPERTY_DESCRIPTION, release.getDescription()); + jsonWriter.propDate(PROPERTY_RELEASE_DATE, release.getDate()); + jsonWriter.prop(PROPERTY_CHANGE_LOG_URL, release.getChangelogUrl()); + jsonWriter.prop(PROPERTY_DOWNLOAD_URL, release.getDownloadUrl()); + } + + private void writePlugins(JsonWriter jsonWriter, SonarUpdate sonarUpdate) { + jsonWriter.name(OBJECT_PLUGINS).beginObject(); + + writePluginsToUpdate(jsonWriter, sonarUpdate.getPluginsToUpgrade()); + + writeIncompatiblePlugins(jsonWriter, sonarUpdate.getIncompatiblePlugins()); + + jsonWriter.endObject(); + } + + private void writePluginsToUpdate(JsonWriter jsonWriter, List pluginsToUpgrade) { + jsonWriter.name(ARRAY_REQUIRE_UPDATE).beginArray(); + for (Release release : pluginsToUpgrade) { + jsonWriter.beginObject(); + + Plugin plugin = (Plugin) release.getArtifact(); + writePlugin(jsonWriter, plugin); + jsonWriter.prop(PROPERTY_VERSION, release.getVersion().toString()); + + jsonWriter.endObject(); + } + + jsonWriter.endArray(); + } + + private void writePlugin(JsonWriter jsonWriter, Plugin plugin) { + jsonWriter.prop(PROPERTY_KEY, plugin.getKey()); + jsonWriter.prop(PROPERTY_NAME, plugin.getName()); + jsonWriter.prop(PROPERTY_DESCRIPTION, plugin.getDescription()); + } + + private void writeIncompatiblePlugins(JsonWriter jsonWriter, List incompatiblePlugins) { + jsonWriter.name(ARRAY_INCOMPATIBLE).beginArray(); + + for (Plugin incompatiblePlugin : incompatiblePlugins) { + jsonWriter.beginObject(); + writePlugin(jsonWriter, incompatiblePlugin); + jsonWriter.endObject(); + } + + jsonWriter.endArray(); + } +} diff --git a/server/sonar-server/src/main/resources/org/sonar/server/platform/ws/example-updates_plugins.json b/server/sonar-server/src/main/resources/org/sonar/server/platform/ws/example-updates_plugins.json new file mode 100644 index 00000000000..d9438402d0c --- /dev/null +++ b/server/sonar-server/src/main/resources/org/sonar/server/platform/ws/example-updates_plugins.json @@ -0,0 +1,29 @@ +{ + "upgrades": [ + { + "version": "5.1", + "description": "New overall layout, merge Issues Drilldown [...]", + "releaseDate": "2015-04-02", + "changeLogUrl": "http://jira.codehaus.org/secure/ReleaseNote.jspa?projectId=11694&version=20666", + "downloadUrl": "http://dist.sonar.codehaus.org/sonarqube-5.1.zip", + "plugins": { + "requireUpdate": [ + { + "key": "views", + "name": "Views", + "description": "Create aggregation trees to group projects. Projects can for instance be grouped by applications, applications by team, teams by department.", + "version": "2.8" + } + ], + "incompatible": [ + { + "key": "branding", + "name": "Branding", + "description": "Allows to add your own logo to the SonarQube UI." + } + ] + } + } + ], + "updateCenterRefresh": "2015-04-24T16:08:36+0200" +} \ No newline at end of file diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/UpgradesSystemWsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/UpgradesSystemWsActionTest.java new file mode 100644 index 00000000000..73a2dd04b5e --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/UpgradesSystemWsActionTest.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.platform.ws; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.WebService; +import org.sonar.api.utils.DateUtils; +import org.sonar.server.plugins.UpdateCenterMatrixFactory; +import org.sonar.server.ws.WsTester; +import org.sonar.updatecenter.common.Plugin; +import org.sonar.updatecenter.common.Release; +import org.sonar.updatecenter.common.Sonar; +import org.sonar.updatecenter.common.SonarUpdate; +import org.sonar.updatecenter.common.UpdateCenter; +import org.sonar.updatecenter.common.Version; + +import static com.google.common.collect.ImmutableList.of; +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.when; +import static org.sonar.test.JsonAssert.assertJson; + +public class UpgradesSystemWsActionTest { + private static final String DUMMY_CONTROLLER_KEY = "dummy"; + private static final String JSON_EMPTY_UPGRADE_LIST = + "{" + + " \"upgrades\":" + "[]" + + "}"; + + private UpdateCenterMatrixFactory updateCenterFactory = mock(UpdateCenterMatrixFactory.class); + private UpdateCenter updateCenter = mock(UpdateCenter.class); + private UpgradesSystemWsAction underTest = new UpgradesSystemWsAction(updateCenterFactory); + + private Request request = mock(Request.class); + private WsTester.TestResponse response = new WsTester.TestResponse(); + + @Before + public void wireMocks() throws Exception { + when(updateCenterFactory.getUpdateCenter(anyBoolean())).thenReturn(updateCenter); + when(updateCenter.getDate()).thenReturn(DateUtils.parseDateTime("2015-04-24T16:08:36+0200")); + } + + @Test + public void action_updates_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("upgrades"); + + WebService.Action action = controller.actions().iterator().next(); + assertThat(action.isPost()).isFalse(); + assertThat(action.description()).isNotEmpty(); + assertThat(action.responseExample()).isNotNull(); + + assertThat(action.params()).isEmpty(); + } + + @Test + public void empty_array_is_returned_when_there_is_no_upgrade_available() throws Exception { + underTest.handle(request, response); + + assertJson(response.outputAsString()).setStrictArrayOrder(true).isSimilarTo(JSON_EMPTY_UPGRADE_LIST); + } + + @Test + public void verify_JSON_response_against_example() throws Exception { + SonarUpdate sonarUpdate = createSonar_51_update(); + when(updateCenter.findSonarUpdates()).thenReturn(of(sonarUpdate)); + + underTest.handle(request, response); + + assertJson(response.outputAsString()).setStrictArrayOrder(true) + .isSimilarTo(getClass().getResource("example-updates_plugins.json")); + } + + private static SonarUpdate createSonar_51_update() { + Plugin brandingPlugin = new Plugin("branding") + .setCategory("Integration") + .setName("Branding") + .setDescription("Allows to add your own logo to the SonarQube UI.") + .setHomepageUrl("http://docs.codehaus.org/display/SONAR/Branding+Plugin") + .setLicense("GNU LGPL 3") + .setOrganization("SonarSource") + .setOrganizationUrl("http://www.sonarsource.com") + .setIssueTrackerUrl("http://jira.codehaus.org/browse/SONARPLUGINS/component/14663") + .setSourcesUrl("https://github.com/SonarCommunity/sonar-branding"); + Plugin viewsPlugin = new Plugin("views") + .setName("Views") + .setCategory("Governance") + .setDescription("Create aggregation trees to group projects. Projects can for instance be grouped by applications, applications by team, teams by department.") + .setHomepageUrl("http://redirect.sonarsource.com/plugins/views.html") + .setLicense("Commercial") + .setOrganization("SonarSource") + .setOrganizationUrl("http://dist.sonarsource.com/SonarSource_Terms_And_Conditions.pdf") + .setTermsConditionsUrl("http://dist.sonarsource.com/SonarSource_Terms_And_Conditions.pdf") + .setIssueTrackerUrl("http://jira.sonarsource.com/browse/VIEWS"); + + SonarUpdate sonarUpdate = new SonarUpdate( + new Release(new Sonar(), Version.create("5.1")) + .setDate(DateUtils.parseDate("2015-04-02")) + .setDescription("New overall layout, merge Issues Drilldown [...]") + .setDownloadUrl("http://dist.sonar.codehaus.org/sonarqube-5.1.zip") + .setChangelogUrl("http://jira.codehaus.org/secure/ReleaseNote.jspa?projectId=11694&version=20666") + ); + + sonarUpdate.addIncompatiblePlugin(brandingPlugin); + sonarUpdate.addPluginToUpgrade(new Release(viewsPlugin, Version.create("2.8"))); + + return sonarUpdate; + } +}