未验证 提交 2776f4dc 编写于 作者: D Daniel Beck 提交者: GitHub

[JENKINS-62332] Show when a plugin version newer than offered exists (#4742)

* [JENKINS-62332] Show when a plugin version newer than offered exists

* Add more obvious label/tag to entries that cannot be installed

Also link to plugin documentation from the detail message

* Also show the list if there are any unavailable updates
Co-authored-by: NDaniel Beck <daniel-beck@users.noreply.github.com>
上级 56086162
......@@ -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());
......
......@@ -1060,6 +1060,24 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas
return new ArrayList<>(pluginMap.values());
}
@Restricted(NoExternalUse.class)
public List<Plugin> getPluginsWithUnavailableUpdates() {
Map<String,Plugin> 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<Plugin> unavailable = new ArrayList<>(pluginMap.values());
return unavailable;
}
/**
* Ensure that all UpdateSites are up to date, without requiring a user to
* browse to the instance.
......
......@@ -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;
......
......@@ -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
......@@ -72,8 +72,9 @@ THE SOFTWARE.
<th>${%Released}</th>
<j:if test="${isUpdates}"><th>${%Installed}</th></j:if>
</tr>
<j:set var="unavailableList" value="${app.updateCenter.pluginsWithUnavailableUpdates}"/>
<j:choose>
<j:when test="${!empty(list)}">
<j:when test="${!empty(list) or (isUpdates and !empty(unavailableList))}">
<j:set var="cache" value="${it.createCache()}"/>
<j:if test="${filtered == 'true'}">
<tr id="hidden-by-default-instructions">
......@@ -165,6 +166,11 @@ THE SOFTWARE.
${%adoptThisPlugin}
</div>
</j:if>
<j:if test="${it.hasLatestVersionNewerThanOffered(p)}">
<div class="alert alert-info">
${%newerVersionExists(p.latest)}
</div>
</j:if>
</td>
<td class="pane"><st:out value="${p.version}" /></td>
<td class="pane" data="${p.releaseTimestamp.time}">
......@@ -187,6 +193,55 @@ THE SOFTWARE.
</j:if>
</tr>
</j:forEach>
<j:if test="${isUpdates}">
<!-- TODO this might be nicer by going through the root list element and populating it in index.jelly -->
<j:forEach var="p" items="${unavailableList}">
<j:if test="${!list.contains(p)}"><!-- only show entries for plugins not already in the real updates list -->
<tr class="unavailable">
<l:isAdmin>
<td><!-- install --></td>
</l:isAdmin>
<td class="pane" data="${h.xmlEscape(p.displayName)}" data-id="${h.xmlEscape(p.name+':'+p.version)}">
<div>
<a href="${p.wiki}" target="_blank"><st:out value="${p.displayName}"/></a>
<span class="unavailable-label">${%unavailable}</span>
</div>
<j:if test="${!p.categories.isEmpty()}">
<div class="plugin-manager__categories">
<j:forEach var="label" items="${p.categories}">
<j:if test="${!it.isMetaLabel(label)}">
<a href="?filter=${app.updateCenter.getCategoryDisplayName(label)}"
class="plugin-manager__category-label">
${app.updateCenter.getCategoryDisplayName(label)}
</a>
</j:if>
</j:forEach>
</div>
</j:if>
<j:if test="${p.excerpt!=null}">
<div class="excerpt"><j:out value="${p.excerpt}" /></div>
</j:if>
<j:if test="${it.hasLatestVersionNewerThanOffered(p)}">
<div class="alert alert-info">
${%newerVersionEntry(p.wiki)}
</div>
</j:if>
</td>
<td>${p.latest}</td>
<td><!-- timestamp --></td>
<td class="pane">
<j:choose><j:when test="${p.installed.active}">
<st:out value="${p.installed.version}" />
</j:when><j:otherwise>
<span title="${%Inactive}">
(<st:out value="${p.installed.version}" />)
</span>
</j:otherwise></j:choose>
</td>
</tr>
</j:if>
</j:forEach>
</j:if>
</j:when>
<j:otherwise>
<tr>
......
......@@ -51,6 +51,14 @@ ago={0} ago
adoptThisPlugin=\
<strong>This plugin is up for adoption!</strong> We are looking for new maintainers. \
Visit our <a href="https://jenkins.io/doc/developer/plugin-governance/adopt-a-plugin/" target="_blank">Adopt a Plugin</a> 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 <a href="{0}" target="_blank">plugin documentation</a> for information about its requirements.
unavailable=Unavailable
loading=Plugin list is loading...
instructions=Use the search field above to search for available plugins.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册