diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PendingPluginResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PendingPluginResource.java index 47e3d2f9f6..14280d5d85 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PendingPluginResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PendingPluginResource.java @@ -61,16 +61,24 @@ public class PendingPluginResource { Stream updatePlugins = installed .stream() .filter(i -> contains(pending, i)); + Stream uninstallPlugins = installed + .stream() + .filter(InstalledPlugin::isMarkedForUninstall); Links.Builder linksBuilder = linkingTo().self(resourceLinks.pendingPluginCollection().self()); - if (!pending.isEmpty()) { + List installDtos = newPlugins.map(mapper::mapAvailable).collect(toList()); + List updateDtos = updatePlugins.map(i -> mapper.mapInstalled(i, pending)).collect(toList()); + List uninstallDtos = uninstallPlugins.map(i -> mapper.mapInstalled(i, pending)).collect(toList()); + + if (!installDtos.isEmpty() || !updateDtos.isEmpty() || !uninstallDtos.isEmpty()) { linksBuilder.single(link("install", resourceLinks.pendingPluginCollection().installPending())); } Embedded.Builder embedded = Embedded.embeddedBuilder(); - embedded.with("new", newPlugins.map(mapper::mapAvailable).collect(toList())); - embedded.with("update", updatePlugins.map(i -> mapper.mapInstalled(i, pending)).collect(toList())); + embedded.with("new", installDtos); + embedded.with("update", updateDtos); + embedded.with("uninstall", uninstallDtos); return Response.ok(new HalRepresentation(linksBuilder.build(), embedded.build())).build(); } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java index d4b8a5bf5a..49f9c30e0b 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java @@ -30,6 +30,7 @@ import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; import static java.net.URI.create; +import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -123,7 +124,6 @@ class PendingPluginResourceTest { assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); assertThat(response.getContentAsString()).contains("\"new\":[{\"name\":\"pending-available-plugin\""); assertThat(response.getContentAsString()).contains("\"install\":{\"href\":\"/v2/plugins/pending/install\"}"); - System.out.println(response.getContentAsString()); } @Test @@ -140,7 +140,21 @@ class PendingPluginResourceTest { assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); assertThat(response.getContentAsString()).contains("\"update\":[{\"name\":\"available-plugin\""); assertThat(response.getContentAsString()).contains("\"install\":{\"href\":\"/v2/plugins/pending/install\"}"); - System.out.println(response.getContentAsString()); + } + + @Test + void shouldGetPendingUninstallPluginListWithInstallLink() throws URISyntaxException, UnsupportedEncodingException { + when(pluginManager.getAvailable()).thenReturn(emptyList()); + InstalledPlugin installedPlugin = createInstalledPlugin("uninstalled-plugin"); + when(installedPlugin.isMarkedForUninstall()).thenReturn(true); + when(pluginManager.getInstalled()).thenReturn(singletonList(installedPlugin)); + + MockHttpRequest request = MockHttpRequest.get("/v2/plugins/pending"); + dispatcher.invoke(request, response); + + assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); + assertThat(response.getContentAsString()).contains("\"uninstall\":[{\"name\":\"uninstalled-plugin\""); + assertThat(response.getContentAsString()).contains("\"install\":{\"href\":\"/v2/plugins/pending/install\"}"); } @Test