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 d54645f10d..1c636ffb17 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java @@ -193,9 +193,14 @@ public class DefaultPluginManager implements PluginManager { doThrow().violation("plugin is a core plugin and cannot be uninstalled").when(installed.isCore()); dependencyTracker.removeInstalled(installed.getDescriptor()); - installed.setMarkedForUninstall(true); - createMarkerFile(installed, InstalledPlugin.UNINSTALL_MARKER_FILENAME); + try { + createMarkerFile(installed, InstalledPlugin.UNINSTALL_MARKER_FILENAME); + installed.setMarkedForUninstall(true); + } catch (RuntimeException e) { + dependencyTracker.addInstalled(installed.getDescriptor()); + throw e; + } if (restartAfterInstallation) { restart("plugin installation"); diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/PluginDependencyTracker.java b/scm-webapp/src/main/java/sonia/scm/plugin/PluginDependencyTracker.java index a68b391b97..2609522555 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/PluginDependencyTracker.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/PluginDependencyTracker.java @@ -33,6 +33,10 @@ class PluginDependencyTracker { } private void removeDependency(String from, String to) { - plugins.get(to).remove(from); + Collection dependencies = plugins.get(to); + if (dependencies == null) { + throw new NullPointerException("inverse dependencies not found for " + to); + } + dependencies.remove(from); } } 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 057a05eb79..ad196b8ca3 100644 --- a/scm-webapp/src/test/java/sonia/scm/plugin/DefaultPluginManagerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/plugin/DefaultPluginManagerTest.java @@ -358,6 +358,24 @@ class DefaultPluginManagerTest { verify(mailPlugin).setMarkedForUninstall(true); } + @Test + void shouldNotChangeStateWhenUninstallFileCouldNotBeCreated() { + InstalledPlugin mailPlugin = createInstalled("scm-mail-plugin"); + InstalledPlugin reviewPlugin = createInstalled("scm-review-plugin"); + when(reviewPlugin.getDescriptor().getDependencies()).thenReturn(singleton("scm-mail-plugin")); + + when(reviewPlugin.getDirectory()).thenThrow(new PluginException("when the file could not be written an exception like this is thrown")); + + when(loader.getInstalledPlugins()).thenReturn(asList(mailPlugin, reviewPlugin)); + + manager.computeInstallationDependencies(); + + assertThrows(PluginException.class, () -> manager.uninstall("scm-review-plugin", false)); + + verify(mailPlugin, never()).setMarkedForUninstall(true); + assertThrows(ScmConstraintViolationException.class, () -> manager.uninstall("scm-mail-plugin", false)); + } + @Test void shouldThrowExceptionWhenUninstallingCorePlugin(@TempDirectory.TempDir Path temp) { InstalledPlugin mailPlugin = createInstalled("scm-mail-plugin");