diff --git a/core/src/main/java/hudson/PluginManager.java b/core/src/main/java/hudson/PluginManager.java index d666fc2070..0aeebaf52f 100644 --- a/core/src/main/java/hudson/PluginManager.java +++ b/core/src/main/java/hudson/PluginManager.java @@ -91,6 +91,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; @@ -1253,6 +1254,13 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas return Collections.unmodifiableList(plugins); } + @Restricted(NoExternalUse.class) // used by jelly + public List getPluginsSortedByTitle() { + return plugins.stream() + .sorted(Comparator.comparing(PluginWrapper::getDisplayName, String.CASE_INSENSITIVE_ORDER)) + .collect(Collectors.toUnmodifiableList()); + } + public List getFailedPlugins() { return failedPlugins; } diff --git a/core/src/main/resources/hudson/PluginManager/installed.jelly b/core/src/main/resources/hudson/PluginManager/installed.jelly index 8013742cf7..5729a7d3f9 100644 --- a/core/src/main/resources/hudson/PluginManager/installed.jelly +++ b/core/src/main/resources/hudson/PluginManager/installed.jelly @@ -85,7 +85,7 @@ THE SOFTWARE. - + diff --git a/test/src/test/java/hudson/PluginManagerTest.java b/test/src/test/java/hudson/PluginManagerTest.java index c2fc5dd872..cd4dddd87e 100644 --- a/test/src/test/java/hudson/PluginManagerTest.java +++ b/test/src/test/java/hudson/PluginManagerTest.java @@ -29,6 +29,7 @@ import static java.nio.file.attribute.PosixFilePermission.OWNER_READ; import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE; import static org.awaitility.Awaitility.await; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInRelativeOrder; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; @@ -81,6 +82,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import javax.servlet.ServletException; import jenkins.ClassLoaderReflectionToolkit; import jenkins.RestartRequiredException; @@ -626,6 +628,17 @@ public class PluginManagerTest { assertTrue(ExtensionList.lookup(GlobalConfiguration.class).stream().anyMatch(gc -> "io.jenkins.plugins.MyGlobalConfiguration".equals(gc.getClass().getName()))); } + @Test @Issue("JENKINS-64840") + @WithPlugin({"mandatory-depender-0.0.2.hpi", "dependee-0.0.2.hpi", "depender-0.0.2.hpi"}) + public void getPluginsSortedByTitle() throws Exception { + List installedPlugins = r.jenkins.getPluginManager().getPluginsSortedByTitle() + .stream() + .map(PluginWrapper::getDisplayName) + .collect(Collectors.toUnmodifiableList()); + + assertThat(installedPlugins, containsInRelativeOrder("dependee", "depender", "mandatory-depender")); + } + @Issue("JENKINS-62622") @Test @WithPlugin("legacy.hpi")