diff --git a/gradle/changelog/dependent_plugin_uninstallation.yaml b/gradle/changelog/dependent_plugin_uninstallation.yaml new file mode 100644 index 0000000000..e8af43f1df --- /dev/null +++ b/gradle/changelog/dependent_plugin_uninstallation.yaml @@ -0,0 +1,2 @@ +- type: fixed + description: Required plugins can be uninstalled even when dependent plugins are still installed diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java index 00bab2569b..a08cccbc38 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java @@ -390,6 +390,7 @@ public class DefaultPluginManager implements PluginManager { PluginPermissions.write().check(); pendingUninstallQueue.forEach(PendingPluginUninstallation::cancel); pendingInstallQueue.forEach(PendingPluginInstallation::cancel); + pendingUninstallQueue.forEach(pendingPluginUninstallation -> dependencyTracker.addInstalled(pendingPluginUninstallation.getPlugin().getDescriptor())); pendingUninstallQueue.clear(); pendingInstallQueue.clear(); updateMayUninstallFlag(); diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/PendingPluginUninstallation.java b/scm-webapp/src/main/java/sonia/scm/plugin/PendingPluginUninstallation.java index 76b96ac17f..277b5834d8 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/PendingPluginUninstallation.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/PendingPluginUninstallation.java @@ -53,4 +53,8 @@ class PendingPluginUninstallation { throw new PluginFailedToCancelInstallationException("failed to cancel uninstallation", name, ex); } } + + InstalledPlugin getPlugin() { + return plugin; + } } diff --git a/scm-webapp/src/test/java/sonia/scm/plugin/DefaultPluginManagerTest.java b/scm-webapp/src/test/java/sonia/scm/plugin/DefaultPluginManagerTest.java index e4459d11f6..20f4ed63d7 100644 --- a/scm-webapp/src/test/java/sonia/scm/plugin/DefaultPluginManagerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/plugin/DefaultPluginManagerTest.java @@ -57,8 +57,10 @@ import static java.util.Arrays.asList; import static java.util.Collections.emptySet; import static java.util.Collections.singleton; import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.anyOf; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -99,6 +101,9 @@ class DefaultPluginManagerTest { @Captor private ArgumentCaptor contextCaptor; + @Captor + private ArgumentCaptor booleanCaptor; + private DefaultPluginManager manager; @Mock @@ -458,7 +463,7 @@ class DefaultPluginManagerTest { } @Test - void shouldUseDependencyTrackerForUninstall() { + void shouldPreventUninstallationOfRequiredPlugin() { InstalledPlugin mailPlugin = createInstalled("scm-mail-plugin"); InstalledPlugin reviewPlugin = createInstalled("scm-review-plugin"); when(reviewPlugin.getDescriptor().getDependencies()).thenReturn(singleton("scm-mail-plugin")); @@ -553,6 +558,27 @@ class DefaultPluginManagerTest { verify(mailPlugin).setUninstallable(true); } + @Test + void shouldUpdateMayUninstallFlagAfterCancelingUninstallationOfDependentPlugin() { + InstalledPlugin mailPlugin = createInstalled("scm-mail-plugin"); + InstalledPlugin reviewPlugin = createInstalled("scm-review-plugin"); + when(reviewPlugin.getDescriptor().getDependencies()).thenReturn(singleton("scm-mail-plugin")); + + when(loader.getInstalledPlugins()).thenReturn(asList(mailPlugin, reviewPlugin)); + + doNothing().when(mailPlugin).setUninstallable(booleanCaptor.capture()); + + manager.computeInstallationDependencies(); + + manager.uninstall("scm-review-plugin", false); + + manager.cancelPending(); + + List values = booleanCaptor.getAllValues(); + + assertThat(values).containsExactly(false, true, false); + } + @Test void shouldUpdateMayUninstallFlagAfterDependencyIsInstalled() { InstalledPlugin mailPlugin = createInstalled("scm-mail-plugin");