diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java index 29ec937d..5ba854ed 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java @@ -20,15 +20,18 @@ import static org.springframework.util.StringUtils.hasText; import java.io.File; import java.io.IOException; +import java.util.HashSet; import java.util.List; +import java.util.Set; -import org.eclipse.jgit.api.CheckoutCommand; import org.eclipse.jgit.api.CloneCommand; +import org.eclipse.jgit.api.CheckoutCommand; import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.ListBranchCommand; import org.eclipse.jgit.api.ListBranchCommand.ListMode; import org.eclipse.jgit.api.PullCommand; +import org.eclipse.jgit.api.Status; import org.eclipse.jgit.api.TransportCommand; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.RefNotFoundException; @@ -51,6 +54,7 @@ import com.jcraft.jsch.Session; * * @author Dave Syer * @author Roy Clarkson + * @author Marcos Barbero */ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository implements EnvironmentRepository, SearchPathLocator, InitializingBean { @@ -76,6 +80,12 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository private String defaultLabel = DEFAULT_LABEL; + /** + * Flag to indicate that the repository should force pull. If true discard any local + * changes and take from remote repository. + */ + private boolean forcePull; + public JGitEnvironmentRepository(ConfigurableEnvironment environment) { super(environment); } @@ -112,6 +122,14 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository this.defaultLabel = defaultLabel; } + public boolean isForcePull() { + return forcePull; + } + + public void setForcePull(boolean forcePull) { + this.forcePull = forcePull; + } + @Override public synchronized Locations getLocations(String application, String profile, String label) { @@ -204,9 +222,35 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository return checkout.call(); } - private boolean shouldPull(Git git, Ref ref) throws GitAPIException { - return git.status().call().isClean() && ref != null && git.getRepository() - .getConfig().getString("remote", "origin", "url") != null; + /* for testing */ boolean shouldPull(Git git, Ref ref) throws GitAPIException { + boolean shouldPull; + Status gitStatus = git.status().call(); + if (this.isForcePull() && !gitStatus.isClean()) { + shouldPull = true; + logDirty(gitStatus); + } + else { + shouldPull = gitStatus.isClean() && ref != null && git.getRepository() + .getConfig().getString("remote", "origin", "url") != null; + } + return shouldPull; + } + + @SuppressWarnings("unchecked") + private void logDirty(Status status) { + Set dirties = dirties(status.getAdded(), status.getChanged(), + status.getRemoved(), status.getMissing(), status.getModified(), + status.getConflicting(), status.getUntracked()); + this.logger.warn(String.format("Dirty files found: %s", dirties)); + } + + @SuppressWarnings("unchecked") + private Set dirties(Set... changes) { + Set dirties = new HashSet<>(); + for (Set files : changes) { + dirties.addAll(files); + } + return dirties; } private boolean shouldTrack(Git git, String label) throws GitAPIException { diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryTests.java index 2bfa8b3e..966cfd32 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryTests.java @@ -16,9 +16,28 @@ package org.springframework.cloud.config.server.environment; +import java.io.File; +import java.io.IOException; + +import org.eclipse.jgit.api.CloneCommand; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.Status; +import org.eclipse.jgit.api.StatusCommand; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.util.FileUtils; +import org.junit.Before; +import org.junit.Test; +import org.springframework.cloud.config.environment.Environment; +import org.springframework.cloud.config.server.test.ConfigServerTestUtils; +import org.springframework.core.env.StandardEnvironment; + +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; @@ -27,18 +46,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import java.io.File; -import java.io.IOException; - -import org.eclipse.jgit.api.CloneCommand; -import org.eclipse.jgit.api.Git; -import org.eclipse.jgit.util.FileUtils; -import org.junit.Before; -import org.junit.Test; -import org.springframework.cloud.config.environment.Environment; -import org.springframework.cloud.config.server.test.ConfigServerTestUtils; -import org.springframework.core.env.StandardEnvironment; - /** * @author Dave Syer * @@ -227,6 +234,87 @@ public class JGitEnvironmentRepositoryTests { verify(mockGit, times(0)).fetch(); } + @Test + public void shouldPullForcepullNotClean() throws Exception { + Git git = mock(Git.class); + StatusCommand statusCommand = mock(StatusCommand.class); + Status status = mock(Status.class); + + when(git.status()).thenReturn(statusCommand); + when(statusCommand.call()).thenReturn(status); + when(status.isClean()).thenReturn(false); + + JGitEnvironmentRepository repo = new JGitEnvironmentRepository( + this.environment); + repo.setForcePull(true); + + boolean shouldPull = repo.shouldPull(git, null); + + assertThat("shouldPull was false", shouldPull, is(true)); + } + + @Test + public void shouldPullForcepullClean() throws Exception { + Git git = mock(Git.class); + StatusCommand statusCommand = mock(StatusCommand.class); + Status status = mock(Status.class); + + when(git.status()).thenReturn(statusCommand); + when(statusCommand.call()).thenReturn(status); + when(status.isClean()).thenReturn(true); + + JGitEnvironmentRepository repo = new JGitEnvironmentRepository( + this.environment); + repo.setForcePull(true); + + boolean shouldPull = repo.shouldPull(git, null); + + assertThat("shouldPull was true", shouldPull, is(false)); + } + + @Test + public void shouldPullNotClean() throws Exception { + Git git = mock(Git.class); + StatusCommand statusCommand = mock(StatusCommand.class); + Status status = mock(Status.class); + Ref ref = mock(Ref.class); + + when(git.status()).thenReturn(statusCommand); + when(statusCommand.call()).thenReturn(status); + when(status.isClean()).thenReturn(false); + + JGitEnvironmentRepository repo = new JGitEnvironmentRepository( + this.environment); + + boolean shouldPull = repo.shouldPull(git, ref); + + assertThat("shouldPull was true", shouldPull, is(false)); + } + + @Test + public void shouldPullClean() throws Exception { + Git git = mock(Git.class); + StatusCommand statusCommand = mock(StatusCommand.class); + Status status = mock(Status.class); + Ref ref = mock(Ref.class); + Repository repository = mock(Repository.class); + StoredConfig storedConfig = mock(StoredConfig.class); + + when(git.status()).thenReturn(statusCommand); + when(git.getRepository()).thenReturn(repository); + when(repository.getConfig()).thenReturn(storedConfig); + when(storedConfig.getString("remote", "origin", "url")).thenReturn("http://example/git"); + when(statusCommand.call()).thenReturn(status); + when(status.isClean()).thenReturn(true); + + JGitEnvironmentRepository repo = new JGitEnvironmentRepository( + this.environment); + + boolean shouldPull = repo.shouldPull(git, ref); + + assertThat("shouldPull was false", shouldPull, is(true)); + } + class MockGitFactory extends JGitEnvironmentRepository.JGitFactory { private Git mockGit;