diff --git a/core/src/main/java/hudson/PluginManager.java b/core/src/main/java/hudson/PluginManager.java index 856e2f6301..bdacd598fe 100644 --- a/core/src/main/java/hudson/PluginManager.java +++ b/core/src/main/java/hudson/PluginManager.java @@ -2266,6 +2266,14 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas return Arrays.asList(categories).contains("adopt-this-plugin"); } + @Restricted(DoNotUse.class) // Used from table.jelly + public boolean hasLatestVersionNewerThanOffered(UpdateSite.Plugin plugin) { + if (plugin.latest == null) { + return false; + } + return !plugin.latest.equalsIgnoreCase(plugin.version); // we can assume that any defined 'latest' will be newer than the actual offered version + } + @Restricted(DoNotUse.class) // Used from table.jelly public boolean hasAdoptThisPluginLabel(PluginWrapper plugin) { final UpdateSite.Plugin pluginMeta = Jenkins.get().getUpdateCenter().getPlugin(plugin.getShortName()); diff --git a/core/src/main/java/hudson/model/UpdateCenter.java b/core/src/main/java/hudson/model/UpdateCenter.java index 84994570cb..3f28de0507 100644 --- a/core/src/main/java/hudson/model/UpdateCenter.java +++ b/core/src/main/java/hudson/model/UpdateCenter.java @@ -1060,6 +1060,24 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas return new ArrayList<>(pluginMap.values()); } + @Restricted(NoExternalUse.class) + public List getPluginsWithUnavailableUpdates() { + Map pluginMap = new LinkedHashMap<>(); + for (PluginWrapper wrapper : Jenkins.get().getPluginManager().getPlugins()) { + for (UpdateSite site : sites) { + UpdateSite.Plugin plugin = site.getPlugin(wrapper.getShortName()); + final Plugin existing = pluginMap.get(plugin.name); + if (existing == null) { // TODO better support for overlapping update sites + if (plugin.latest != null && !plugin.latest.equalsIgnoreCase(plugin.version) && !plugin.latest.equalsIgnoreCase(wrapper.getVersion())) { + pluginMap.put(plugin.name, plugin); + } + } + } + } + final ArrayList unavailable = new ArrayList<>(pluginMap.values()); + return unavailable; + } + /** * Ensure that all UpdateSites are up to date, without requiring a user to * browse to the instance. diff --git a/core/src/main/java/hudson/model/UpdateSite.java b/core/src/main/java/hudson/model/UpdateSite.java index c1a79c9512..7a15a896dd 100644 --- a/core/src/main/java/hudson/model/UpdateSite.java +++ b/core/src/main/java/hudson/model/UpdateSite.java @@ -1047,6 +1047,13 @@ public class UpdateSite { @Restricted(NoExternalUse.class) public final Double popularity; + /** + * The latest existing version of this plugin. May be different from the version being offered by the + * update site, which will result in a notice on the UI. + */ + @Restricted(NoExternalUse.class) + public String latest; + @DataBoundConstructor public Plugin(String sourceId, JSONObject o) { super(sourceId, o, UpdateSite.this.url); @@ -1055,6 +1062,7 @@ public class UpdateSite { this.excerpt = get(o,"excerpt"); this.compatibleSinceVersion = Util.intern(get(o,"compatibleSinceVersion")); this.minimumJavaVersion = Util.intern(get(o, "minimumJavaVersion")); + this.latest = get(o, "latest"); this.requiredCore = Util.intern(get(o,"requiredCore")); final String releaseTimestamp = get(o, "releaseTimestamp"); Date date = null; diff --git a/core/src/main/resources/hudson/PluginManager/_table.css b/core/src/main/resources/hudson/PluginManager/_table.css index f3751b13ff..6395636564 100644 --- a/core/src/main/resources/hudson/PluginManager/_table.css +++ b/core/src/main/resources/hudson/PluginManager/_table.css @@ -84,3 +84,23 @@ time { .hidden { display: none; } + +#plugins tr.unavailable { + background-color: #f4f4f4; +} +tr.unavailable span.unavailable-label { + display: inline-block; + border: 1px solid #666; + background-color: #fcc; + color: #333; + border-radius: 4px; + font-size: 0.75rem; + font-weight: 500; + padding: 0 0.5rem; + margin: 0.25rem 0.5rem; + text-decoration: none; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + text-transform: uppercase; +} \ No newline at end of file diff --git a/core/src/main/resources/hudson/PluginManager/table.jelly b/core/src/main/resources/hudson/PluginManager/table.jelly index aa63130e4e..e66edecd33 100644 --- a/core/src/main/resources/hudson/PluginManager/table.jelly +++ b/core/src/main/resources/hudson/PluginManager/table.jelly @@ -72,8 +72,9 @@ THE SOFTWARE. ${%Released} ${%Installed} + - + @@ -165,6 +166,11 @@ THE SOFTWARE. ${%adoptThisPlugin} + +
+ ${%newerVersionExists(p.latest)} +
+
@@ -187,6 +193,55 @@ THE SOFTWARE. + + + + + + + + + +
+ + ${%unavailable} +
+ + + + +
+
+ +
+ ${%newerVersionEntry(p.wiki)} +
+
+ + ${p.latest} + + + + + + + () + + + + +
+
+
diff --git a/core/src/main/resources/hudson/PluginManager/table.properties b/core/src/main/resources/hudson/PluginManager/table.properties index d9fe7d043f..75df8c7994 100644 --- a/core/src/main/resources/hudson/PluginManager/table.properties +++ b/core/src/main/resources/hudson/PluginManager/table.properties @@ -51,6 +51,14 @@ ago={0} ago adoptThisPlugin=\ This plugin is up for adoption! We are looking for new maintainers. \ Visit our Adopt a Plugin initiative for more information. +newerVersionExists=\ + A newer version than being offered for installation exists (version {0}). \ + This is typically the case when plugin requirements, e.g. a recent version of Jenkins, are not satisfied. +newerVersionEntry=\ + This version of the plugin exists but it is not being offered as an update. \ + This is typically the case when plugin requirements, e.g. a recent version of Jenkins, are not satisfied. \ + See the plugin documentation for information about its requirements. +unavailable=Unavailable loading=Plugin list is loading... instructions=Use the search field above to search for available plugins.