cancel all pending installations, if a dependency failed to install

This commit is contained in:
Sebastian Sdorra
2019-08-21 08:42:57 +02:00
parent 7ef4b30027
commit de7d18e026
2 changed files with 60 additions and 11 deletions

View File

@@ -43,6 +43,7 @@ import sonia.scm.NotFoundException;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import javax.inject.Inject; import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@@ -99,7 +100,7 @@ public class DefaultPluginManager implements PluginManager {
} }
private <T extends Plugin> Predicate<T> filterByName(String name) { private <T extends Plugin> Predicate<T> filterByName(String name) {
return (plugin) -> name.equals(plugin.getDescriptor().getInformation().getName()); return plugin -> name.equals(plugin.getDescriptor().getInformation().getName());
} }
private boolean isNotInstalled(AvailablePlugin availablePlugin) { private boolean isNotInstalled(AvailablePlugin availablePlugin) {
@@ -108,18 +109,42 @@ public class DefaultPluginManager implements PluginManager {
@Override @Override
public void install(String name) { public void install(String name) {
if (getInstalled(name).isPresent()){ List<AvailablePlugin> plugins = collectPluginsToInstall(name);
LOG.info("plugin {} is already installed, skipping installation", name); List<PendingPluginInstallation> pendingInstallations = new ArrayList<>();
return; for (AvailablePlugin plugin : plugins) {
} try {
AvailablePlugin plugin = getAvailable(name).orElseThrow(() -> NotFoundException.notFound(entity(AvailablePlugin.class, name))); PendingPluginInstallation pending = installer.install(plugin);
Set<String> dependencies = plugin.getDescriptor().getDependencies(); pendingInstallations.add(pending);
if (dependencies != null) { } catch (PluginInstallException ex) {
for (String dependency: dependencies){ cancelPending(pendingInstallations);
install(dependency); throw ex;
} }
} }
}
installer.install(plugin); private void cancelPending(List<PendingPluginInstallation> pendingInstallations) {
pendingInstallations.forEach(PendingPluginInstallation::cancel);
}
private List<AvailablePlugin> collectPluginsToInstall(String name) {
List<AvailablePlugin> plugins = new ArrayList<>();
collectPluginsToInstall(plugins, name);
return plugins;
}
private void collectPluginsToInstall(List<AvailablePlugin> plugins, String name) {
if (!getInstalled(name).isPresent()) {
AvailablePlugin plugin = getAvailable(name).orElseThrow(() -> NotFoundException.notFound(entity(AvailablePlugin.class, name)));
Set<String> dependencies = plugin.getDescriptor().getDependencies();
if (dependencies != null) {
for (String dependency: dependencies){
collectPluginsToInstall(plugins, dependency);
}
}
plugins.add(plugin);
} else {
LOG.info("plugin {} is already installed, skipping installation", name);
}
} }
} }

View File

@@ -13,6 +13,7 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
@@ -153,6 +154,29 @@ class DefaultPluginManagerTest {
verify(installer).install(review); verify(installer).install(review);
} }
@Test
void shouldRollbackOnFailedInstallation() {
AvailablePlugin review = createAvailable("scm-review-plugin");
when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin"));
AvailablePlugin mail = createAvailable("scm-mail-plugin");
when(mail.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-notification-plugin"));
AvailablePlugin notification = createAvailable("scm-notification-plugin");
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail, notification));
PendingPluginInstallation pendingNotification = mock(PendingPluginInstallation.class);
doReturn(pendingNotification).when(installer).install(notification);
PendingPluginInstallation pendingMail = mock(PendingPluginInstallation.class);
doReturn(pendingMail).when(installer).install(mail);
doThrow(new PluginChecksumMismatchException("checksum does not match")).when(installer).install(review);
assertThrows(PluginInstallException.class, () -> manager.install("scm-review-plugin"));
verify(pendingNotification).cancel();
verify(pendingMail).cancel();
}
private AvailablePlugin createAvailable(String name) { private AvailablePlugin createAvailable(String name) {
PluginInformation information = new PluginInformation(); PluginInformation information = new PluginInformation();
information.setName(name); information.setName(name);