diff options
author | Jacek <52388493+jacek-poreda-sonarsource@users.noreply.github.com> | 2019-07-31 16:48:16 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-08-07 20:21:22 +0200 |
commit | 24b51a56601c053a0faa14a789415007eaafd81e (patch) | |
tree | dd8305720c5f5363de15beb547fc6770e84bedf7 | |
parent | 72ce45299de3dacbebe6b10cba25d6e973b9801a (diff) | |
download | sonarqube-24b51a56601c053a0faa14a789415007eaafd81e.tar.gz sonarqube-24b51a56601c053a0faa14a789415007eaafd81e.zip |
SONAR-12351 list plugins with documentation (#1963)
9 files changed, 61 insertions, 10 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledAction.java index 9962261ff24..7b0688bf94f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledAction.java @@ -76,7 +76,8 @@ public class InstalledAction implements PluginsWsAction { new Change("6.6", "The 'fileHash' field is added"), new Change("6.6", "The 'sonarLintSupported' field is added"), new Change("6.6", "The 'updatedAt' field is added"), - new Change("7.0", "The fields 'compressedHash' and 'compressedFilename' are added")) + new Change("7.0", "The fields 'compressedHash' and 'compressedFilename' are added"), + new Change("8.0", "The 'documentationPath' field is added")) .setHandler(this) .setResponseExample(Resources.getResource(this.getClass(), "example-installed_plugins.json")); diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingAction.java index d36988bc201..1c849b45358 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingAction.java @@ -28,6 +28,7 @@ import java.util.Collection; import java.util.Map; import java.util.Set; import javax.annotation.Nonnull; +import org.sonar.api.server.ws.Change; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; @@ -77,6 +78,7 @@ public class PendingAction implements PluginsWsAction { .setDescription("Get the list of plugins which will either be installed or removed at the next startup of the SonarQube instance, sorted by plugin name.<br/>" + "Require 'Administer System' permission.") .setSince("5.2") + .setChangelog(new Change("8.0", "The 'documentationPath' field is added")) .setHandler(this) .setResponseExample(getResource(this.getClass(), "example-pending_plugins.json")); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PluginWSCommons.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PluginWSCommons.java index 7281f7f1c9f..a9320dcc867 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PluginWSCommons.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PluginWSCommons.java @@ -53,6 +53,7 @@ public class PluginWSCommons { private static final String PROPERTY_NAME = "name"; private static final String PROPERTY_HASH = "hash"; private static final String PROPERTY_FILENAME = "filename"; + private static final String PROPERTY_DOCUMENTATION_PATH = "documentationPath"; private static final String PROPERTY_SONARLINT_SUPPORTED = "sonarLintSupported"; private static final String PROPERTY_DESCRIPTION = "description"; private static final String PROPERTY_LICENSE = "license"; @@ -109,6 +110,7 @@ public class PluginWSCommons { json.prop(PROPERTY_HOMEPAGE_URL, pluginInfo.getHomepageUrl()); json.prop(PROPERTY_ISSUE_TRACKER_URL, pluginInfo.getIssueTrackerUrl()); json.prop(PROPERTY_IMPLEMENTATION_BUILD, pluginInfo.getImplementationBuild()); + json.prop(PROPERTY_DOCUMENTATION_PATH, pluginInfo.getDocumentationPath()); if (pluginDto != null) { json.prop(PROPERTY_UPDATED_AT, pluginDto.getUpdatedAt()); } diff --git a/server/sonar-server/src/main/resources/org/sonar/server/plugins/ws/example-installed_plugins.json b/server/sonar-server/src/main/resources/org/sonar/server/plugins/ws/example-installed_plugins.json index e961781b3ab..19934ee780a 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/plugins/ws/example-installed_plugins.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/plugins/ws/example-installed_plugins.json @@ -15,6 +15,7 @@ "filename": "sonar-scm-git-plugin-1.0.jar", "hash": "abcdef123456", "sonarLintSupported": false, + "documentationPath": "static/documentation.md", "updatedAt": 123456789 }, { @@ -32,6 +33,7 @@ "filename": "sonar-java-plugin-3.0.jar", "hash": "abcdef123456", "sonarLintSupported": true, + "documentationPath": "static/documentation.md", "updatedAt": 123456789 }, { diff --git a/server/sonar-server/src/main/resources/org/sonar/server/plugins/ws/example-pending_plugins.json b/server/sonar-server/src/main/resources/org/sonar/server/plugins/ws/example-pending_plugins.json index e0c27a41ab3..9bb8f01b8a1 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/plugins/ws/example-pending_plugins.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/plugins/ws/example-pending_plugins.json @@ -11,7 +11,8 @@ "organizationUrl": "http://www.sonarsource.com", "homepageUrl": "https://redirect.sonarsource.com/plugins/scmcvs.html", "issueTrackerUrl": "http://jira.codehaus.org/browse/SONARSCCVS", - "implementationBuild": "f9735104bfa053abc50edad720c79d89a4f5cd72" + "implementationBuild": "f9735104bfa053abc50edad720c79d89a4f5cd72", + "documentationPath": "static/documentation.md" } ], "updating": [ @@ -41,7 +42,8 @@ "organizationUrl": "http://www.sonarsource.com", "homepageUrl": "https://redirect.sonarsource.com/plugins/scmgit.html/sonar-scm-git-plugin", "issueTrackerUrl": "https://jira.sonarsource.com/browse/SONARSCGIT", - "implementationBuild": "a713dd64daf8719ba4e7f551f9a1966c62690c17" + "implementationBuild": "a713dd64daf8719ba4e7f551f9a1966c62690c17", + "documentationPath": "static/documentation.md" } ] } diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledActionTest.java index 1f675ed53d4..c562dab62cd 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledActionTest.java @@ -197,6 +197,7 @@ public class InstalledActionTest { .setHomepageUrl("homepage_url") .setIssueTrackerUrl("issueTracker_url") .setImplementationBuild("sou_rev_sha1") + .setDocumentationPath("static/documentation.md") .setSonarLintSupported(true)); when(pluginFileSystem.getInstalledFiles()).thenReturn(singletonList(plugin)); @@ -224,6 +225,7 @@ public class InstalledActionTest { " \"issueTrackerUrl\": \"issueTracker_url\"," + " \"implementationBuild\": \"sou_rev_sha1\"," + " \"sonarLintSupported\": true," + + " \"documentationPath\": \"static/documentation.md\"," + " \"filename\": \"" + plugin.getLoadedJar().getFile().getName() + "\"," + " \"hash\": \"" + plugin.getLoadedJar().getMd5() + "\"," + " \"updatedAt\": 100" + @@ -376,7 +378,7 @@ public class InstalledActionTest { @DataProvider public static Object[][] editionBundledLicenseValues() { - return new Object[][] { + return new Object[][]{ {"sonarsource"}, {"SonarSource"}, {"SonaRSOUrce"}, diff --git a/sonar-core/src/main/java/org/sonar/core/platform/PluginInfo.java b/sonar-core/src/main/java/org/sonar/core/platform/PluginInfo.java index 5cbefd71c65..0abe8adc81f 100644 --- a/sonar-core/src/main/java/org/sonar/core/platform/PluginInfo.java +++ b/sonar-core/src/main/java/org/sonar/core/platform/PluginInfo.java @@ -27,12 +27,16 @@ import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.HashSet; +import java.util.Optional; import java.util.Set; +import java.util.jar.JarFile; import java.util.regex.Pattern; +import java.util.zip.ZipEntry; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.apache.commons.lang.StringUtils; import org.sonar.api.utils.MessageException; +import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.updatecenter.common.PluginManifest; import org.sonar.updatecenter.common.Version; @@ -40,6 +44,7 @@ import org.sonar.updatecenter.common.Version; import static java.util.Objects.requireNonNull; public class PluginInfo implements Comparable<PluginInfo> { + private static final Logger LOGGER = Loggers.get(PluginInfo.class); private static final Joiner SLASH_JOINER = Joiner.on(" / ").skipNulls(); @@ -140,6 +145,9 @@ public class PluginInfo implements Comparable<PluginInfo> { @CheckForNull private boolean sonarLintSupported; + @CheckForNull + private String documentationPath; + private final Set<RequiredPlugin> requiredPlugins = new HashSet<>(); public PluginInfo(String key) { @@ -234,6 +242,10 @@ public class PluginInfo implements Comparable<PluginInfo> { return sonarLintSupported; } + public String getDocumentationPath() { + return documentationPath; + } + @CheckForNull public String getBasePlugin() { return basePlugin; @@ -263,6 +275,11 @@ public class PluginInfo implements Comparable<PluginInfo> { return this; } + public PluginInfo setDocumentationPath(@Nullable String documentationPath) { + this.documentationPath = documentationPath; + return this; + } + /** * Required */ @@ -313,7 +330,7 @@ public class PluginInfo implements Comparable<PluginInfo> { public PluginInfo setBasePlugin(@Nullable String s) { if ("l10nen".equals(s)) { - Loggers.get(PluginInfo.class).info("Plugin [{}] defines 'l10nen' as base plugin. " + + LOGGER.info("Plugin [{}] defines 'l10nen' as base plugin. " + "This metadata can be removed from manifest of l10n plugins since version 5.2.", key); basePlugin = null; } else { @@ -411,6 +428,7 @@ public class PluginInfo implements Comparable<PluginInfo> { info.setName(manifest.getName()); info.setMainClass(manifest.getMainClass()); info.setVersion(Version.create(manifest.getVersion())); + info.setDocumentationPath(getDocumentationPath(jarFile)); // optional fields info.setDescription(manifest.getDescription()); @@ -437,4 +455,16 @@ public class PluginInfo implements Comparable<PluginInfo> { } return info; } + + private static String getDocumentationPath(File file) { + try (JarFile jarFile = new JarFile(file)) { + return Optional.ofNullable(jarFile.getEntry("static/documentation.md")) + .map(ZipEntry::getName) + .orElse(null); + } catch (IOException e) { + LOGGER.warn("Could not retrieve documentation path from " + file, e); + } + return null; + } + } diff --git a/sonar-core/src/test/java/org/sonar/core/platform/PluginInfoTest.java b/sonar-core/src/test/java/org/sonar/core/platform/PluginInfoTest.java index a3027ce0c4a..805dd988ad3 100644 --- a/sonar-core/src/test/java/org/sonar/core/platform/PluginInfoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/platform/PluginInfoTest.java @@ -210,7 +210,7 @@ public class PluginInfoTest { manifest.setOrganization("SonarSource"); manifest.setOrganizationUrl("http://sonarsource.com"); manifest.setIssueTrackerUrl("http://jira.com"); - manifest.setRequirePlugins(new String[] {"java:2.0", "pmd:1.3"}); + manifest.setRequirePlugins(new String[]{"java:2.0", "pmd:1.3"}); manifest.setSonarLintSupported(true); File jarFile = temp.newFile(); @@ -237,7 +237,7 @@ public class PluginInfoTest { manifest.setVersion("1.0"); manifest.setName("Java"); manifest.setMainClass("org.foo.FooPlugin"); - manifest.setRequirePlugins(new String[] {"license:" + version}); + manifest.setRequirePlugins(new String[]{"license:" + version}); File jarFile = temp.newFile(); PluginInfo pluginInfo = PluginInfo.create(jarFile, manifest); @@ -252,7 +252,7 @@ public class PluginInfoTest { manifest.setVersion("1.0"); manifest.setName("Java"); manifest.setMainClass("org.foo.FooPlugin"); - manifest.setRequirePlugins(new String[] {"java:2.0", "license:" + version, "pmd:1.3"}); + manifest.setRequirePlugins(new String[]{"java:2.0", "license:" + version, "pmd:1.3"}); File jarFile = temp.newFile(); PluginInfo pluginInfo = PluginInfo.create(jarFile, manifest); @@ -261,7 +261,7 @@ public class PluginInfoTest { @DataProvider public static Object[][] licenseVersions() { - return new Object[][] { + return new Object[][]{ {"0.3"}, {"7.2.0.1253"} }; @@ -273,11 +273,21 @@ public class PluginInfoTest { PluginInfo checkstyleInfo = PluginInfo.create(checkstyleJar); assertThat(checkstyleInfo.getName()).isEqualTo("Checkstyle"); + assertThat(checkstyleInfo.getDocumentationPath()).isNull(); assertThat(checkstyleInfo.getMinimalSqVersion()).isEqualTo(Version.create("2.8")); } @Test - public void test_toString() throws Exception { + public void create_from_file_with_documentation() { + File jarWithDocs = FileUtils.toFile(getClass().getResource("/org/sonar/core/platform/jar_with_documentation.jar")); + PluginInfo checkstyleInfo = PluginInfo.create(jarWithDocs); + + assertThat(checkstyleInfo.getDocumentationPath()).isNotBlank(); + assertThat(checkstyleInfo.getDocumentationPath()).isEqualTo("static/documentation.md"); + } + + @Test + public void test_toString() { PluginInfo pluginInfo = new PluginInfo("java").setVersion(Version.create("1.1")); assertThat(pluginInfo.toString()).isEqualTo("[java / 1.1]"); diff --git a/sonar-core/src/test/resources/org/sonar/core/platform/jar_with_documentation.jar b/sonar-core/src/test/resources/org/sonar/core/platform/jar_with_documentation.jar Binary files differnew file mode 100644 index 00000000000..bed32916585 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/platform/jar_with_documentation.jar |