Merge branch 'master' of https://github.com/spring-cloud/spring-cloud-config
This commit is contained in:
@@ -24,14 +24,18 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jgit.api.CloneCommand;
|
||||
import org.eclipse.jgit.api.CheckoutCommand;
|
||||
import org.eclipse.jgit.api.CloneCommand;
|
||||
import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
|
||||
import org.eclipse.jgit.api.FetchCommand;
|
||||
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.ResetCommand;
|
||||
import org.eclipse.jgit.api.ResetCommand.ResetType;
|
||||
import org.eclipse.jgit.api.Status;
|
||||
import org.eclipse.jgit.api.StatusCommand;
|
||||
import org.eclipse.jgit.api.TransportCommand;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.api.errors.RefNotFoundException;
|
||||
@@ -55,6 +59,7 @@ import com.jcraft.jsch.Session;
|
||||
* @author Dave Syer
|
||||
* @author Roy Clarkson
|
||||
* @author Marcos Barbero
|
||||
* @author Daniel Lavoie
|
||||
*/
|
||||
public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
|
||||
implements EnvironmentRepository, SearchPathLocator, InitializingBean {
|
||||
@@ -166,6 +171,14 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
|
||||
Ref ref = checkout(git, label);
|
||||
if (shouldPull(git, ref)) {
|
||||
pull(git, label, ref);
|
||||
|
||||
if (!isClean(git)) {
|
||||
logger.warn("The local repository is dirty. Reseting it to origin/"
|
||||
+ label + ".");
|
||||
|
||||
fetch(git, label, "origin");
|
||||
resetHard(git, label, "refs/remotes/origin/" + label);
|
||||
}
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
@@ -264,6 +277,36 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
|
||||
return isBranch(git, label) && !isLocalBranch(git, label);
|
||||
}
|
||||
|
||||
private void fetch(Git git, String label, String remote) {
|
||||
FetchCommand fetch = git.fetch().setRemote(remote);
|
||||
setTimeout(fetch);
|
||||
try {
|
||||
if (hasText(getUsername())) {
|
||||
setCredentialsProvider(fetch);
|
||||
}
|
||||
|
||||
fetch.call();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
this.logger.warn("Could not fetch remote for " + label + " remote: " + git
|
||||
.getRepository().getConfig().getString("remote", "origin", "url"));
|
||||
}
|
||||
}
|
||||
|
||||
private void resetHard(Git git, String label, String ref) {
|
||||
ResetCommand reset = git.reset();
|
||||
reset.setRef(ref);
|
||||
reset.setMode(ResetType.HARD);
|
||||
try {
|
||||
reset.call();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
this.logger.warn("Could not reset to remote for " + label + " (current ref="
|
||||
+ ref + "), remote: " + git.getRepository().getConfig()
|
||||
.getString("remote", "origin", "url"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assumes we are on a tracking branch (should be safe)
|
||||
*/
|
||||
@@ -369,6 +412,20 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
|
||||
pull.setTimeout(this.timeout);
|
||||
}
|
||||
|
||||
private boolean isClean(Git git) {
|
||||
StatusCommand status = git.status();
|
||||
try {
|
||||
return status.call().isClean();
|
||||
}
|
||||
catch (Exception e) {
|
||||
this.logger
|
||||
.warn("Could not execute status command on local repository. Cause: ("
|
||||
+ e.getClass().getSimpleName() + ") " + e.getMessage());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void trackBranch(Git git, CheckoutCommand checkout, String label) {
|
||||
checkout.setCreateBranch(true).setName(label)
|
||||
.setUpstreamMode(SetupUpstreamMode.TRACK)
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.cloud.config.server.test;
|
||||
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.lib.RepositoryCache.FileKey;
|
||||
import org.eclipse.jgit.util.FS;
|
||||
import org.eclipse.jgit.util.FileUtils;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -24,8 +27,22 @@ import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Daniel Lavoie
|
||||
*/
|
||||
public class ConfigServerTestUtils {
|
||||
public static Repository prepareBareRemote() throws IOException {
|
||||
// Create a folder in the temp folder that will act as the remote repository
|
||||
File remoteDir = File.createTempFile("remote", "");
|
||||
remoteDir.delete();
|
||||
remoteDir.mkdirs();
|
||||
|
||||
// Create a bare repository
|
||||
FileKey fileKey = FileKey.exact(remoteDir, FS.DETECTED);
|
||||
Repository remoteRepo = fileKey.open(false);
|
||||
remoteRepo.create(true);
|
||||
|
||||
return remoteRepo;
|
||||
}
|
||||
|
||||
public static String prepareLocalRepo() throws IOException {
|
||||
return prepareLocalRepo("./", "target/repos", "config-repo", "target/config");
|
||||
|
||||
@@ -26,12 +26,21 @@ import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.ResetCommand.ResetType;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.lib.StoredConfig;
|
||||
import org.eclipse.jgit.util.FileUtils;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
@@ -48,6 +57,7 @@ import org.springframework.util.StreamUtils;
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Roy Clarkson
|
||||
* @author Daniel Lavoie
|
||||
*/
|
||||
public class JGitEnvironmentRepositoryIntegrationTests {
|
||||
|
||||
@@ -108,6 +118,67 @@ public class JGitEnvironmentRepositoryIntegrationTests {
|
||||
environment.getPropertySources().get(0).getSource().get("foo"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a special use case where the remote repository has been updated with a forced
|
||||
* push conflicting with the local repo of the Config Server. The Config Server has to
|
||||
* reset hard on the new reference because a simple pull operation could result in a
|
||||
* conflicting local repository.
|
||||
*/
|
||||
@Test
|
||||
public void pullDirtyRepo() throws Exception {
|
||||
ConfigServerTestUtils.prepareLocalRepo();
|
||||
String uri = ConfigServerTestUtils.copyLocalRepo("config-copy");
|
||||
|
||||
// Create a remote bare repository.
|
||||
Repository remote = ConfigServerTestUtils.prepareBareRemote();
|
||||
|
||||
Git git = Git.open(ResourceUtils.getFile(uri).getAbsoluteFile());
|
||||
StoredConfig config = git.getRepository().getConfig();
|
||||
config.setString("remote", "origin", "url",
|
||||
remote.getDirectory().getAbsolutePath());
|
||||
config.setString("remote", "origin", "fetch",
|
||||
"+refs/heads/*:refs/remotes/origin/*");
|
||||
config.save();
|
||||
|
||||
// Pushes the raw branch to remote repository.
|
||||
git.push().call();
|
||||
|
||||
String commitToRevertBeforePull = git.log().setMaxCount(1).call().iterator()
|
||||
.next().getName();
|
||||
|
||||
this.context = new SpringApplicationBuilder(TestConfiguration.class).web(false)
|
||||
.run("--spring.cloud.config.server.git.uri=" + uri);
|
||||
|
||||
JGitEnvironmentRepository repository = this.context
|
||||
.getBean(JGitEnvironmentRepository.class);
|
||||
|
||||
// Fetches the repository for the first time.
|
||||
repository.getLocations("bar", "test", "raw");
|
||||
|
||||
// Resets to the original commit.
|
||||
git.reset().setMode(ResetType.HARD).setRef("master").call();
|
||||
|
||||
// Generate a conflicting commit who will be forced on the origin.
|
||||
Path applicationFilePath = Paths
|
||||
.get(ResourceUtils.getFile(uri).getAbsoluteFile() + "/application.yml");
|
||||
|
||||
Files.write(applicationFilePath,
|
||||
Arrays.asList("info:", " foo: bar", "raw: false"),
|
||||
StandardCharsets.UTF_8, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
git.add().addFilepattern(".").call();
|
||||
git.commit().setMessage("Conflicting commit.").call();
|
||||
git.push().setForce(true).call();
|
||||
|
||||
// Reset to the raw branch.
|
||||
git.reset().setMode(ResetType.HARD).setRef(commitToRevertBeforePull).call();
|
||||
|
||||
// Triggers the repository refresh.
|
||||
repository.getLocations("bar", "test", "raw");
|
||||
|
||||
Assert.assertTrue("Local repository is not cleaned after retreiving resources.",
|
||||
git.status().call().isClean());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nested() throws IOException {
|
||||
String uri = ConfigServerTestUtils.prepareLocalRepo("another-config-repo");
|
||||
|
||||
Reference in New Issue
Block a user