mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-10 15:35:49 +01:00
cancel all pending installations, if a dependency failed to install
This commit is contained in:
@@ -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 {
|
||||||
|
PendingPluginInstallation pending = installer.install(plugin);
|
||||||
|
pendingInstallations.add(pending);
|
||||||
|
} catch (PluginInstallException ex) {
|
||||||
|
cancelPending(pendingInstallations);
|
||||||
|
throw ex;
|
||||||
}
|
}
|
||||||
AvailablePlugin plugin = getAvailable(name).orElseThrow(() -> NotFoundException.notFound(entity(AvailablePlugin.class, name)));
|
|
||||||
Set<String> dependencies = plugin.getDescriptor().getDependencies();
|
|
||||||
if (dependencies != null) {
|
|
||||||
for (String dependency: dependencies){
|
|
||||||
install(dependency);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user