@@ -30,7 +30,6 @@ import java.io.File; | |||
import java.io.IOException; | |||
import java.util.Arrays; | |||
import java.util.Optional; | |||
import java.util.Random; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.TemporaryFolder; | |||
@@ -39,11 +38,11 @@ import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.server.ws.WebService.Action; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.core.platform.PluginInfo; | |||
import org.sonar.core.plugin.PluginType; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.plugin.PluginDto.Type; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.plugins.PluginFilesAndMd5.FileAndMd5; | |||
import org.sonar.core.plugin.PluginType; | |||
import org.sonar.server.plugins.ServerPlugin; | |||
import org.sonar.server.plugins.ServerPluginRepository; | |||
import org.sonar.server.plugins.UpdateCenterMatrixFactory; | |||
@@ -86,14 +85,14 @@ public class InstalledActionIT { | |||
@DataProvider | |||
public static Object[][] editionBundledLicenseValues() { | |||
return new Object[][] { | |||
{"sonarsource"}, | |||
{"SonarSource"}, | |||
{"SonaRSOUrce"}, | |||
{"SONARSOURCE"}, | |||
{"commercial"}, | |||
{"Commercial"}, | |||
{"COMMERCIAL"}, | |||
{"COmmERCiaL"}, | |||
{"sonarsource", "SONARSOURCE"}, | |||
{"SonarSource", "SONARSOURCE"}, | |||
{"SonaRSOUrce", "SonarSource"}, | |||
{"SONARSOURCE", "SonarSource"}, | |||
{"commercial", "SONARSOURCE"}, | |||
{"Commercial", "SONARSOURCE"}, | |||
{"COMMERCIAL", "SonarSource"}, | |||
{"COmmERCiaL", "SonarSource"}, | |||
}; | |||
} | |||
@@ -203,6 +202,7 @@ public class InstalledActionIT { | |||
assertThat(json.get("organizationUrl")).isNull(); | |||
assertThat(json.get("homepageUrl")).isNull(); | |||
assertThat(json.get("issueTrackerUrl")).isNull(); | |||
assertThat(json.get("requiredForLanguage")).isNull(); | |||
} | |||
private ServerPlugin newInstalledPlugin(PluginInfo plugin) throws IOException { | |||
@@ -226,6 +226,7 @@ public class InstalledActionIT { | |||
.setHomepageUrl("homepage_url") | |||
.setIssueTrackerUrl("issueTracker_url") | |||
.setImplementationBuild("sou_rev_sha1") | |||
.addRequiredForLanguage("bar") | |||
.setSonarLintSupported(true)); | |||
when(serverPluginRepository.getPlugins()).thenReturn(singletonList(plugin)); | |||
db.pluginDbTester().insertPlugin( | |||
@@ -236,29 +237,31 @@ public class InstalledActionIT { | |||
String response = tester.newRequest().execute().getInput(); | |||
verifyNoMoreInteractions(updateCenterMatrixFactory); | |||
assertJson(response).isSimilarTo( | |||
"{" + | |||
" \"plugins\":" + | |||
" [" + | |||
" {" + | |||
" \"key\": \"foo\"," + | |||
" \"name\": \"plugName\"," + | |||
" \"description\": \"desc_it\"," + | |||
" \"version\": \"1.0\"," + | |||
" \"license\": \"license_hey\"," + | |||
" \"organizationName\": \"org_name\"," + | |||
" \"organizationUrl\": \"org_url\",\n" + | |||
" \"editionBundled\": false," + | |||
" \"homepageUrl\": \"homepage_url\"," + | |||
" \"issueTrackerUrl\": \"issueTracker_url\"," + | |||
" \"implementationBuild\": \"sou_rev_sha1\"," + | |||
" \"sonarLintSupported\": true," + | |||
" \"filename\": \"" + plugin.getJar().getFile().getName() + "\"," + | |||
" \"hash\": \"" + plugin.getJar().getMd5() + "\"," + | |||
" \"updatedAt\": 100" + | |||
" }" + | |||
" ]" + | |||
"}"); | |||
String expected = String.format(""" | |||
{ | |||
"plugins": | |||
[ | |||
{ | |||
"key": "foo", | |||
"name": "plugName", | |||
"description": "desc_it", | |||
"version": "1.0", | |||
"license": "license_hey", | |||
"organizationName": "org_name", | |||
"organizationUrl": "org_url", | |||
"editionBundled": false, | |||
"homepageUrl": "homepage_url", | |||
"issueTrackerUrl": "issueTracker_url", | |||
"implementationBuild": "sou_rev_sha1", | |||
"sonarLintSupported": true, | |||
"filename": "%s", | |||
"hash": "%s", | |||
"updatedAt": 100, | |||
"requiredForLanguages": ["bar"] | |||
} | |||
] | |||
}""", plugin.getJar().getFile().getName(), plugin.getJar().getMd5()); | |||
assertJson(response).isSimilarTo(expected); | |||
} | |||
@Test | |||
@@ -362,10 +365,8 @@ public class InstalledActionIT { | |||
@Test | |||
@UseDataProvider("editionBundledLicenseValues") | |||
public void commercial_plugins_from_SonarSource_has_flag_editionBundled_true_based_on_jar_info(String license) throws Exception { | |||
public void commercial_plugins_from_SonarSource_has_flag_editionBundled_true_based_on_jar_info(String license, String organization) throws Exception { | |||
String jarFilename = getClass().getSimpleName() + "/" + "some.jar"; | |||
Random random = new Random(); | |||
String organization = random.nextBoolean() ? "SonarSource" : "SONARSOURCE"; | |||
String pluginKey = "plugKey"; | |||
File jar = new File(getClass().getResource(jarFilename).toURI()); | |||
when(serverPluginRepository.getPlugins()).thenReturn(asList( |
@@ -33,12 +33,12 @@ 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.platform.PluginInfo; | |||
import org.sonar.core.plugin.PluginType; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.permission.GlobalPermission; | |||
import org.sonar.db.plugin.PluginDto; | |||
import org.sonar.db.plugin.PluginDto.Type; | |||
import org.sonar.core.plugin.PluginType; | |||
import org.sonar.server.plugins.ServerPlugin; | |||
import org.sonar.server.plugins.ServerPluginRepository; | |||
import org.sonar.server.plugins.UpdateCenterMatrixFactory; | |||
@@ -84,6 +84,7 @@ public class InstalledAction implements PluginsWsAction { | |||
"Requires authentication.") | |||
.setSince("5.2") | |||
.setChangelog( | |||
new Change("10.4", "The response field 'requiredForLanguages' is added for plugins that support it"), | |||
new Change("9.8", "The 'documentationPath' field is deprecated"), | |||
new Change("9.7", "Authentication check added"), | |||
new Change("8.0", "The 'documentationPath' field is added"), |
@@ -94,6 +94,7 @@ public class PluginWSCommons { | |||
ofNullable(pluginInfo.getIssueTrackerUrl()).ifPresent(builder::setIssueTrackerUrl); | |||
ofNullable(pluginInfo.getImplementationBuild()).ifPresent(builder::setImplementationBuild); | |||
ofNullable(pluginInfo.getDocumentationPath()).ifPresent(builder::setDocumentationPath); | |||
builder.addAllRequiredForLanguages(pluginInfo.getRequiredForLanguages()); | |||
return builder.build(); | |||
} | |||
@@ -109,9 +110,9 @@ public class PluginWSCommons { | |||
static List<Require> buildRequires(PluginUpdate pluginUpdate) { | |||
return pluginUpdate.getRelease().getOutgoingDependencies().stream().map( | |||
org.sonar.updatecenter.common.Release::getArtifact) | |||
.filter(release -> release instanceof Plugin) | |||
.map(artifact -> (Plugin) artifact) | |||
org.sonar.updatecenter.common.Release::getArtifact) | |||
.filter(Plugin.class::isInstance) | |||
.map(Plugin.class::cast) | |||
.map(artifact -> { | |||
Require.Builder builder = Require.newBuilder() | |||
.setKey(artifact.getKey()); |
@@ -16,7 +16,8 @@ | |||
"hash": "abcdef123456", | |||
"sonarLintSupported": false, | |||
"documentationPath": "static/documentation.md", | |||
"updatedAt": 123456789 | |||
"updatedAt": 123456789, | |||
"requiredForLanguages": [] | |||
}, | |||
{ | |||
"key": "java", | |||
@@ -34,7 +35,11 @@ | |||
"hash": "abcdef123456", | |||
"sonarLintSupported": true, | |||
"documentationPath": "static/documentation.md", | |||
"updatedAt": 123456789 | |||
"updatedAt": 123456789, | |||
"requiredForLanguages": [ | |||
"java", | |||
"xml" | |||
] | |||
}, | |||
{ | |||
"key": "scmsvn", | |||
@@ -51,7 +56,8 @@ | |||
"filename": "sonar-scm-svn-plugin-1.0.jar", | |||
"hash": "abcdef123456", | |||
"sonarLintSupported": false, | |||
"updatedAt": 123456789 | |||
"updatedAt": 123456789, | |||
"requiredForLanguages": [] | |||
} | |||
] | |||
} |
@@ -36,9 +36,9 @@ 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.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.updatecenter.common.PluginManifest; | |||
import org.sonar.updatecenter.common.Version; | |||
@@ -100,6 +100,8 @@ public class PluginInfo implements Comparable<PluginInfo> { | |||
private final Set<RequiredPlugin> requiredPlugins = new HashSet<>(); | |||
private final Set<String> requiredForLanguages = new HashSet<>(); | |||
public PluginInfo(String key) { | |||
requireNonNull(key, "Plugin key is missing from manifest"); | |||
this.key = key; | |||
@@ -210,6 +212,10 @@ public class PluginInfo implements Comparable<PluginInfo> { | |||
return requiredPlugins; | |||
} | |||
public Set<String> getRequiredForLanguages() { | |||
return requiredForLanguages; | |||
} | |||
public PluginInfo setName(@Nullable String name) { | |||
this.name = (name != null ? name : this.key); | |||
return this; | |||
@@ -299,6 +305,11 @@ public class PluginInfo implements Comparable<PluginInfo> { | |||
return this; | |||
} | |||
public PluginInfo addRequiredForLanguage(String lang) { | |||
this.requiredForLanguages.add(lang); | |||
return this; | |||
} | |||
/** | |||
* Find out if this plugin is compatible with a given version of Sonar Plugin API. | |||
* The version of plugin api embedded in SQ must be greater than or equal to the minimal version | |||
@@ -406,6 +417,12 @@ public class PluginInfo implements Comparable<PluginInfo> { | |||
.filter(t -> !"license".equals(t.key)) | |||
.forEach(this::addRequiredPlugin); | |||
} | |||
String[] requiredForLanguagesFromManifest = manifest.getRequiredForLanguages(); | |||
if (requiredForLanguagesFromManifest != null) { | |||
Arrays.stream(requiredForLanguagesFromManifest) | |||
.forEach(this::addRequiredForLanguage); | |||
} | |||
} | |||
private static String getDocumentationPath(File file) { |
@@ -190,6 +190,7 @@ public class PluginInfoTest { | |||
assertThat(pluginInfo.getMinimalSonarPluginApiVersion()).isNull(); | |||
assertThat(pluginInfo.getRequiredPlugins()).isEmpty(); | |||
assertThat(pluginInfo.isSonarLintSupported()).isFalse(); | |||
assertThat(pluginInfo.getRequiredForLanguages()).isEmpty(); | |||
} | |||
@Test | |||
@@ -210,6 +211,7 @@ public class PluginInfoTest { | |||
manifest.setIssueTrackerUrl("http://jira.com"); | |||
manifest.setRequirePlugins(new String[] {"java:2.0", "pmd:1.3"}); | |||
manifest.setSonarLintSupported(true); | |||
manifest.setRequiredForLanguages(new String[]{"java", "xml"}); | |||
File jarFile = temp.newFile(); | |||
PluginInfo pluginInfo = PluginInfo.create(jarFile, manifest); | |||
@@ -225,6 +227,7 @@ public class PluginInfoTest { | |||
assertThat(pluginInfo.getMinimalSonarPluginApiVersion().getName()).isEqualTo("4.5.1"); | |||
assertThat(pluginInfo.getRequiredPlugins()).extracting("key").containsOnly("java", "pmd"); | |||
assertThat(pluginInfo.isSonarLintSupported()).isTrue(); | |||
assertThat(pluginInfo.getRequiredForLanguages()).containsOnly("java", "xml"); | |||
} | |||
@Test |
@@ -124,6 +124,7 @@ message PluginDetails { | |||
optional string documentationPath = 16; | |||
optional int64 updatedAt = 17; | |||
optional string type = 18; | |||
repeated string requiredForLanguages = 19; | |||
} | |||
// WS api/plugins/pending |