diff --git a/docs/src/main/asciidoc/spring-cloud-config.adoc b/docs/src/main/asciidoc/spring-cloud-config.adoc index 13cd7f01..42692967 100644 --- a/docs/src/main/asciidoc/spring-cloud-config.adoc +++ b/docs/src/main/asciidoc/spring-cloud-config.adoc @@ -72,11 +72,15 @@ the repository you can set the "spring.cloud.config.server.git.uri" configuration property in the Config Server (e.g. in `application.yml`). If you set it with a `file:` prefix it should work from a local repository so you can get started quickly and easily -without a server (it doesn't matter if it's not bare because the -Config Server never makes changes to the "remote" repository). To -scale the Config Server up and make it highly available, however, you -would need to have all instances of the server pointing to the same -repository, so only a shared file system would work. +without a server, but in that case the server operates directly on the +local repository without cloning it (it doesn't matter if it's not +bare because the Config Server never makes changes to the "remote" +repository). To scale the Config Server up and make it highly +available, you would need to have all instances of the server pointing +to the same repository, so only a shared file system would work. Even +in that case it is better to use the `ssh:` protocol for a shared +filesystem repository, so that the server can clone it and use a local +working copy as a cache. This repository implementation maps the `{label}` parameter of the HTTP resource to a git label (commit id, branch name or tag). diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerTestUtils.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerTestUtils.java index a892d8ac..421fac69 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerTestUtils.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerTestUtils.java @@ -19,6 +19,7 @@ import java.io.File; import java.io.IOException; import org.eclipse.jgit.util.FileUtils; +import org.springframework.util.FileSystemUtils; /** * @author Dave Syer @@ -27,21 +28,24 @@ import org.eclipse.jgit.util.FileUtils; public class ConfigServerTestUtils { public static String prepareLocalRepo() throws IOException { - return prepareLocalRepo("target/test-classes", "config-repo", "target/config"); + return prepareLocalRepo("target/repos", "config-repo", "target/config"); } public static String prepareLocalRepo(String repoPath) throws IOException { - return prepareLocalRepo("target/test-classes", repoPath, "target/config"); + return prepareLocalRepo("target/repos", repoPath, "target/config"); } public static String prepareLocalRepo(String buildDir, String repoPath, String checkoutDir) throws IOException { + new File(buildDir).mkdirs(); if (!repoPath.startsWith("/")) { repoPath = "/" + repoPath; } if (!repoPath.endsWith("/")) { repoPath = repoPath + "/"; } + File source = new File("src/test/resources" + repoPath); + FileSystemUtils.copyRecursively(source, new File(buildDir + repoPath)); File dotGit = new File(buildDir + repoPath + ".git"); File git = new File(buildDir + repoPath + "git"); if (git.exists()) { @@ -60,4 +64,16 @@ public class ConfigServerTestUtils { return "file:" + buildDir + repoPath; } + public static String copyLocalRepo(String path) throws IOException { + File dest = new File("target/repos/" + path); + FileSystemUtils.deleteRecursively(dest); + FileSystemUtils.copyRecursively(new File("target/repos/config-repo"), dest); + return "file:./target/repos/" + path; + } + + public static boolean deleteLocalRepo(String path) throws IOException { + File dest = new File("target/repos/" + path); + return FileSystemUtils.deleteRecursively(dest); + } + } diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/JGitEnvironmentRepository.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/JGitEnvironmentRepository.java index 2011c97b..881726fa 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/JGitEnvironmentRepository.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/JGitEnvironmentRepository.java @@ -49,7 +49,7 @@ import org.springframework.cloud.config.PropertySource; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.io.UrlResource; import org.springframework.util.Assert; -import org.springframework.util.FileSystemUtils; +import org.springframework.util.StringUtils; import com.jcraft.jsch.Session; @@ -75,10 +75,10 @@ public class JGitEnvironmentRepository implements EnvironmentRepository, Initial private boolean initialized; private String[] searchPaths = new String[0]; - + @Override public void afterPropertiesSet() throws Exception { - Assert.state(uri!=null, "You need to configure a uri for the git repository"); + Assert.state(uri != null, "You need to configure a uri for the git repository"); } public JGitEnvironmentRepository(ConfigurableEnvironment environment) { @@ -220,8 +220,8 @@ public class JGitEnvironmentRepository implements EnvironmentRepository, Initial * Assumes we are on a tracking branch (should be safe) */ private void pull(Git git, String label, Ref ref) { + PullCommand pull = git.pull(); try { - PullCommand pull = git.pull(); if (hasText(username)) { setCredentialsProvider(pull); } @@ -229,7 +229,7 @@ public class JGitEnvironmentRepository implements EnvironmentRepository, Initial } catch (Exception e) { logger.warn("Could not pull remote for " + label + " (current ref=" + ref - + ")"); + + "), remote: " + git.getRepository().getConfig().getString("remote", "origin", "url")); } } @@ -261,7 +261,12 @@ public class JGitEnvironmentRepository implements EnvironmentRepository, Initial private Git copyFromLocalRepository() throws IOException { Git git; - FileSystemUtils.copyRecursively(new UrlResource(uri).getFile(), basedir); + File remote = new UrlResource(StringUtils.cleanPath(uri)).getFile(); + Assert.state(remote.isDirectory(), "No directory at " + uri); + File gitDir = new File(remote, ".git"); + Assert.state(gitDir.exists(), "No .git at " + uri); + Assert.state(gitDir.isDirectory(), "No .git directory at " + uri); + basedir = remote; git = Git.open(basedir); return git; } diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ApplicationTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ApplicationTests.java index 08b0cd61..44a5e84d 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ApplicationTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ApplicationTests.java @@ -19,7 +19,7 @@ import org.springframework.test.context.web.WebAppConfiguration; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = ConfigServerApplication.class) -@IntegrationTest({"server.port:0", "spring.config.name:configserver", "spring.cloud.config.server.git.uri:file:./target/test-classes/config-repo"}) +@IntegrationTest({"server.port:0", "spring.config.name:configserver", "spring.cloud.config.server.git.uri:file:./target/repos/config-repo"}) @WebAppConfiguration @ActiveProfiles("test") public class ApplicationTests { diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/JGitEnvironmentRepositoryIntegrationTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/JGitEnvironmentRepositoryIntegrationTests.java index de0dbbea..54c63c13 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/JGitEnvironmentRepositoryIntegrationTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/JGitEnvironmentRepositoryIntegrationTests.java @@ -19,8 +19,11 @@ package org.springframework.cloud.config.server; import static org.junit.Assert.assertEquals; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.nio.charset.Charset; +import org.eclipse.jgit.api.Git; import org.eclipse.jgit.util.FileUtils; import org.junit.After; import org.junit.Before; @@ -31,6 +34,8 @@ import org.springframework.cloud.config.Environment; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.util.ResourceUtils; +import org.springframework.util.StreamUtils; /** * @author Dave Syer @@ -47,6 +52,7 @@ public class JGitEnvironmentRepositoryIntegrationTests { if (basedir.exists()) { FileUtils.delete(basedir, FileUtils.RECURSIVE); } + ConfigServerTestUtils.deleteLocalRepo("config-copy"); } @After @@ -60,20 +66,42 @@ public class JGitEnvironmentRepositoryIntegrationTests { public void vanilla() throws IOException { String uri = ConfigServerTestUtils.prepareLocalRepo(); context = new SpringApplicationBuilder(TestConfiguration.class).web(false) - //TODO: why didn't .properties() work for me? - .run("--spring.cloud.config.server.git.uri=" + uri); + .properties("spring.cloud.config.server.git.uri:" + uri).run(); + // TODO: why didn't .properties() work for me? + // .run("--spring.cloud.config.server.git.uri=" + uri); EnvironmentRepository repository = context.getBean(EnvironmentRepository.class); repository.findOne("bar", "staging", "master"); Environment environment = repository.findOne("bar", "staging", "master"); assertEquals(2, environment.getPropertySources().size()); } + @Test + public void pull() throws Exception { + ConfigServerTestUtils.prepareLocalRepo(); + String uri = ConfigServerTestUtils.copyLocalRepo("config-copy"); + context = new SpringApplicationBuilder(TestConfiguration.class).web(false).run( + "--spring.cloud.config.server.git.uri=" + uri); + EnvironmentRepository repository = context.getBean(EnvironmentRepository.class); + repository.findOne("bar", "staging", "master"); + Environment environment = repository.findOne("bar", "staging", "master"); + assertEquals("bar", environment.getPropertySources().get(0).getSource() + .get("foo")); + Git git = Git.open(ResourceUtils.getFile(uri).getAbsoluteFile()); + git.checkout().setName("master").call(); + StreamUtils.copy("foo: foo", Charset.defaultCharset(), new FileOutputStream( + ResourceUtils.getFile(uri + "/bar.properties"))); + git.add().addFilepattern("bar.properties").call(); + git.commit().setMessage("Updated for pull").call(); + environment = repository.findOne("bar", "staging", "master"); + assertEquals("foo", environment.getPropertySources().get(0).getSource() + .get("foo")); + } + @Test public void nested() throws IOException { String uri = ConfigServerTestUtils.prepareLocalRepo("another-config-repo"); - context = new SpringApplicationBuilder(TestConfiguration.class) - .web(false) - //TODO: why didn't .properties() work for me? + context = new SpringApplicationBuilder(TestConfiguration.class).web(false) + // TODO: why didn't .properties() work for me? .run("--spring.cloud.config.server.git.uri=" + uri, "--spring.cloud.config.server.git.searchPaths=sub"); EnvironmentRepository repository = context.getBean(EnvironmentRepository.class);