Display plugin description
Show the plugin description coming directly from the Gerrit API
and calculated at build time.
Change-Id: I6ab6d943351195c777b9b4a1c840f1ed2d9a6660
diff --git a/src/main/java/com/googlesource/gerrit/plugins/manager/gson/SmartGson.java b/src/main/java/com/googlesource/gerrit/plugins/manager/gson/SmartGson.java
index 400505d..ba1069a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/manager/gson/SmartGson.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/manager/gson/SmartGson.java
@@ -36,6 +36,10 @@
return SmartJson.of(gson.fromJson(getReader(url), JsonObject.class));
}
+ public SmartJson of(String jsonText) {
+ return SmartJson.of(gson.fromJson(jsonText, JsonObject.class));
+ }
+
public <T> T get(String url, Class<T> classOfT) throws IOException {
try (Reader reader = getReader(url)) {
return gson.fromJson(reader, classOfT);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/manager/gson/SmartJson.java b/src/main/java/com/googlesource/gerrit/plugins/manager/gson/SmartJson.java
index bc2ff06..d0efb56 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/manager/gson/SmartJson.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/manager/gson/SmartJson.java
@@ -49,7 +49,7 @@
}
public Optional<SmartJson> getOptional(String fieldName) {
- if (jsonElem != null && jsonElem.getAsJsonObject().get(fieldName) != null) {
+ if (jsonElem != null && !jsonElem.isJsonNull() && jsonElem.getAsJsonObject().get(fieldName) != null) {
return Optional.of(SmartJson
.of(jsonElem.getAsJsonObject().get(fieldName)));
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/manager/repository/CorePluginsDescriptions.java b/src/main/java/com/googlesource/gerrit/plugins/manager/repository/CorePluginsDescriptions.java
new file mode 100644
index 0000000..3474b19
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/manager/repository/CorePluginsDescriptions.java
@@ -0,0 +1,42 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.manager.repository;
+
+import java.util.HashMap;
+import java.util.Optional;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+@Singleton
+public class CorePluginsDescriptions {
+ private final HashMap<String, String> pluginsDescriptions;
+
+ @Inject
+ public CorePluginsDescriptions() {
+ pluginsDescriptions = new HashMap<>();
+ pluginsDescriptions.put("commit-message-length-validator",
+ "Plugin to validate that commit messages conform to length limits");
+ pluginsDescriptions.put("download-commands", "Adds the standard download schemes and commands");
+ pluginsDescriptions.put("hooks", "Old-style fork+exec hooks");
+ pluginsDescriptions.put("replication", "Copies to other servers using the Git protocol");
+ pluginsDescriptions.put("reviewnotes", "Annotates merged commits using notes on refs/notes/review");
+ pluginsDescriptions.put("singleusergroup", "GroupBackend enabling users to be directly added to access rules");
+ }
+
+ public Optional<String> get(String plugin) {
+ return Optional.ofNullable(pluginsDescriptions.get(plugin));
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/manager/repository/CorePluginsRepository.java b/src/main/java/com/googlesource/gerrit/plugins/manager/repository/CorePluginsRepository.java
index 7ba1518..af92981 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/manager/repository/CorePluginsRepository.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/manager/repository/CorePluginsRepository.java
@@ -42,11 +42,15 @@
private static final Logger log = LoggerFactory
.getLogger(CorePluginsRepository.class);
private static final String GERRIT_VERSION = Version.getVersion();
+
private final SitePaths site;
+ private final CorePluginsDescriptions pluginsDescriptions;
@Inject
- public CorePluginsRepository(SitePaths site) {
+ public CorePluginsRepository(SitePaths site,
+ CorePluginsDescriptions pd) {
this.site = site;
+ this.pluginsDescriptions = pd;
}
static class SelectPluginsFromJar implements Predicate<JarEntry> {
@@ -58,7 +62,7 @@
}
}
- static class ExtractPluginInfoFromJarEntry implements
+ class ExtractPluginInfoFromJarEntry implements
Function<JarEntry, PluginInfo> {
private String gerritWarFilename;
@@ -77,12 +81,14 @@
Manifest manifestJarEntry = getManifestEntry(pluginJar);
if (manifestJarEntry != null) {
Attributes pluginAttributes = manifestJarEntry.getMainAttributes();
+ String pluginName = pluginAttributes.getValue("Gerrit-PluginName");
return new PluginInfo(
- pluginAttributes.getValue("Gerrit-PluginName"),
+ pluginName,
+ pluginsDescriptions.get(pluginName).orElse(""),
pluginAttributes.getValue("Implementation-Version"), "",
pluginUrl.toString());
}
- return new PluginInfo(entryName.getFileName().toString(), "", "",
+ return new PluginInfo(entryName.getFileName().toString(), "", "", "",
pluginUrl.toString());
} catch (IOException e) {
log.error("Unable to open plugin " + pluginUrl, e);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/manager/repository/JenkinsCiPluginsRepository.java b/src/main/java/com/googlesource/gerrit/plugins/manager/repository/JenkinsCiPluginsRepository.java
index 0b609ad..2c5e4db 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/manager/repository/JenkinsCiPluginsRepository.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/manager/repository/JenkinsCiPluginsRepository.java
@@ -43,10 +43,7 @@
@Singleton
public class JenkinsCiPluginsRepository implements PluginsRepository {
- private static final Logger log = LoggerFactory
- .getLogger(JenkinsCiPluginsRepository.class);
-
- private static final Optional<PluginInfo> noPluginInfo = Optional.empty();
+ private static final Logger log = LoggerFactory.getLogger(JenkinsCiPluginsRepository.class);
private final PluginManagerConfig config;
@@ -107,37 +104,27 @@
return plugins;
}
- private Optional<PluginInfo> getPluginInfo(final SmartGson gson, String url)
- throws IOException {
+ private Optional<PluginInfo> getPluginInfo(final SmartGson gson, String url) throws IOException {
SmartJson jobDetails = gson.get(url + "/api/json");
- Optional<SmartJson> lastSuccessfulBuild =
- jobDetails.getOptional("lastSuccessfulBuild");
+ Optional<SmartJson> lastSuccessfulBuild = jobDetails.getOptional("lastSuccessfulBuild");
- return lastSuccessfulBuild.map(
- new Function<SmartJson, Optional<PluginInfo>>() {
- @Override
- public Optional<PluginInfo> apply(SmartJson build) {
- String buildUrl = build.getString("url");
- try {
- return getPluginArtifactInfo(gson, buildUrl);
- } catch (IOException e) {
- log.warn("Cannot retrieve plugin artifact info from {}", buildUrl);
- return noPluginInfo;
- }
- }
- }).orElse(noPluginInfo);
+ return lastSuccessfulBuild.flatMap(new Function<SmartJson, Optional<PluginInfo>>() {
+ @Override
+ public Optional<PluginInfo> apply(SmartJson build) {
+ String buildUrl = build.getString("url");
+ return getPluginArtifactInfo(buildUrl);
+ }
+ });
}
- private Optional<PluginInfo> getPluginArtifactInfo(SmartGson gson, String url)
- throws IOException {
- SmartJson buildExecution = gson.get(url + "/api/json");
- JsonArray artifacts =
- buildExecution.get("artifacts").get().getAsJsonArray();
- if (artifacts.size() == 0) {
+ private Optional<PluginInfo> getPluginArtifactInfo(String url) {
+ Optional<SmartJson> buildExecution = tryGetJson(url + "/api/json");
+ Optional<JsonArray> artifacts = buildExecution.map(json -> json.get("artifacts").get().getAsJsonArray());
+ if (artifacts.orElse(new JsonArray()).size() == 0) {
return Optional.empty();
}
- Optional<SmartJson> artifactJson = findArtifact(artifacts, ".jar");
+ Optional<SmartJson> artifactJson = artifacts.flatMap(a -> findArtifact(a, ".jar"));
if (!artifactJson.isPresent()) {
return Optional.empty();
}
@@ -145,43 +132,64 @@
String pluginPath = artifactJson.get().getString("relativePath");
String[] pluginPathParts = pluginPath.split("/");
- String pluginName =
- isMavenBuild(pluginPathParts)
- ? fixPluginNameForMavenBuilds(pluginPathParts)
- : pluginPathParts[pluginPathParts.length - 2];
+ String pluginName = isMavenBuild(pluginPathParts) ? fixPluginNameForMavenBuilds(pluginPathParts)
+ : pluginNameOfJar(pluginPathParts);
- String pluginUrl =
- String.format("%s/artifact/%s", buildExecution.getString("url"),
- pluginPath);
+ String pluginUrl = String.format("%s/artifact/%s", buildExecution.get().getString("url"), pluginPath);
- String pluginVersion = "";
- Optional<SmartJson> verArtifactJson =
- findArtifact(artifacts, ".jar-version");
- if (verArtifactJson.isPresent()) {
- String versionUrl =
- String.format("%s/artifact/%s", buildExecution.getString("url"),
- verArtifactJson.get().getString("relativePath"));
- try (BufferedReader reader =
- new BufferedReader(new InputStreamReader(
- new URL(versionUrl).openStream()), 4096)) {
- pluginVersion = reader.readLine();
- }
- }
+ Optional<String> pluginVersion = fetchArtifact(buildExecution.get(), artifacts.get(), ".jar-version");
+ Optional<String> pluginDescription = fetchArtifactJson(buildExecution.get(), artifacts.get(), ".json")
+ .flatMap(json -> json.getOptionalString("description"));
- String sha1 = "";
- for (JsonElement elem : buildExecution.get("actions").get()
- .getAsJsonArray()) {
+ for (JsonElement elem : buildExecution.get().get("actions").get().getAsJsonArray()) {
SmartJson elemJson = SmartJson.of(elem);
- Optional<SmartJson> lastBuildRevision =
- elemJson.getOptional("lastBuiltRevision");
+ Optional<SmartJson> lastBuildRevision = elemJson.getOptional("lastBuiltRevision");
if (lastBuildRevision.isPresent()) {
- sha1 = lastBuildRevision.get().getString("SHA1").substring(0, 8);
+ String sha1 = lastBuildRevision.get().getString("SHA1").substring(0, 8);
+ return pluginVersion
+ .map(version -> new PluginInfo(pluginName, pluginDescription.orElse(""), version, sha1, pluginUrl));
}
}
- return Optional.of(new PluginInfo(pluginName, pluginVersion, sha1,
- pluginUrl));
+ return Optional.empty();
+ }
+
+ private Optional<String> fetchArtifact(SmartJson buildExecution, JsonArray artifacts, String artifactSuffix) {
+ StringBuilder artifactBody = new StringBuilder();
+ Optional<SmartJson> verArtifactJson = findArtifact(artifacts, artifactSuffix);
+ if (verArtifactJson.isPresent()) {
+ String versionUrl = String.format("%s/artifact/%s", buildExecution.getString("url"),
+ verArtifactJson.get().getString("relativePath"));
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(versionUrl).openStream()), 4096)) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (artifactBody.length() > 0) {
+ artifactBody.append("\n");
+ }
+ artifactBody.append(line);
+ }
+ } catch(Exception e) {
+ log.error("Unable to fetch artifact from " + versionUrl);
+ return Optional.empty();
+ }
+ }
+ return Optional.of(artifactBody.toString());
+ }
+
+ private Optional<SmartJson> fetchArtifactJson(SmartJson buildExecution, JsonArray artifacts, String artifactSuffix) {
+ Optional<SmartJson> jsonArtifact = findArtifact(artifacts, artifactSuffix);
+ return jsonArtifact.flatMap(artifactJson -> tryGetJson(String.format("%s/artifact/%s",
+ buildExecution.getString("url"), jsonArtifact.get().getString("relativePath"))));
+ }
+
+ private Optional<SmartJson> tryGetJson(String url) {
+ try {
+ return Optional.of(gsonProvider.get().get(url));
+ } catch (IOException e) {
+ log.error("Cannot get JSON from " + url, e);
+ return Optional.empty();
+ }
}
private String fixPluginNameForMavenBuilds(String[] pluginPathParts) {
@@ -193,6 +201,18 @@
.substring(0, versionDelim) : mavenPluginFilename;
}
+ private String pluginNameOfJar(String[] pluginJarParts) {
+ int filePos = pluginJarParts.length-1;
+ int pathPos = filePos - 1;
+
+ if(pluginJarParts[filePos].startsWith(pluginJarParts[pathPos])) {
+ return pluginJarParts[pathPos];
+ }
+
+ int jarExtPos = pluginJarParts[filePos].indexOf(".jar");
+ return pluginJarParts[filePos].substring(0, jarExtPos);
+ }
+
private boolean isMavenBuild(String[] pluginPathParts) {
return pluginPathParts[pluginPathParts.length - 2].equals("target");
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/manager/repository/PluginInfo.java b/src/main/java/com/googlesource/gerrit/plugins/manager/repository/PluginInfo.java
index 32bb47f..51a5471 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/manager/repository/PluginInfo.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/manager/repository/PluginInfo.java
@@ -19,13 +19,15 @@
public class PluginInfo {
public final String id;
public final String name;
+ public final String description;
public final String version;
public final String sha1;
public final String url;
- public PluginInfo(String name, String version, String sha1, String url) {
+ public PluginInfo(String name, String description, String version, String sha1, String url) {
this.id = Url.encode(name);
this.name = name;
+ this.description = description;
this.version = version;
this.sha1 = sha1;
this.url = url;
diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html
index 9ca7d04..a1032aa 100644
--- a/src/main/resources/static/index.html
+++ b/src/main/resources/static/index.html
@@ -39,17 +39,18 @@
<tr>
<th>Plugin Name</th>
<th>Version</th>
- <th>Upgrade / New Version Available</th>
- <th>Latest Commit</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="prop in plugins.list | filter:searchPlugin">
- <td>{{prop.id}}</td>
- <td>{{prop.version}}</td>
- <td>{{prop.update_version}}</td>
- <td>{{prop.sha1}}</td>
+ <td><h4>{{prop.id}}<br/><small>{{prop.description.split('.')[0]}}</small></h4></td>
+ <td>
+ <p>{{prop.version}}</p>
+ <div ng-if="prop.update_version">
+ <span class="glyphicon glyphicon-save"></span><b> {{prop.update_version}}</b>
+ </div>
+ </td>
<td>
<h5>
<span id="installing-{{prop.id}}"
diff --git a/src/main/resources/static/js/plugin-manager.js b/src/main/resources/static/js/plugin-manager.js
index 5862fe4..5345660 100644
--- a/src/main/resources/static/js/plugin-manager.js
+++ b/src/main/resources/static/js/plugin-manager.js
@@ -47,6 +47,7 @@
if (currPluginIdx < 0) {
plugins.list.push({
id : plugin.id,
+ description : plugin.description,
index_url : plugin.index_url,
version : plugin.version,
sha1 : '',
@@ -56,6 +57,7 @@
} else {
plugins.list[currPluginIdx] = {
id : plugin.id,
+ description : plugin.description,
index_url : plugin.index_url,
version : plugin.version,
sha1 : '',
@@ -96,6 +98,7 @@
}
currPlugin.sha1 = plugin.sha1;
currPlugin.url = plugin.url;
+ currPlugin.description = plugin.description;
if (currRow < 0) {
plugins.list.push(currPlugin);