@@ -3,6 +3,7 @@
|
||||
:githubmaster: {github}/tree/master
|
||||
:docslink: {githubmaster}/docs/src/main/asciidoc
|
||||
:toc:
|
||||
:nofooter:
|
||||
|
||||
include::intro.adoc[]
|
||||
|
||||
@@ -31,8 +32,8 @@ public class ConfigServer {
|
||||
|
||||
Like all Spring Boot apps it runs on port 8080 by default, but you
|
||||
can switch it to the conventional port 8888 in various ways. The
|
||||
easiest, which also sets a default configuration repository,
|
||||
is by launching it with `spring.config.name=configserver` (there
|
||||
easiest, which also sets a default configuration repository,
|
||||
is by launching it with `spring.config.name=configserver` (there
|
||||
is a `configserver.yml` in the Config Server jar). Another is
|
||||
to use your own `application.properties`, e.g.
|
||||
|
||||
@@ -46,12 +47,12 @@ spring.cloud.config.server.git.uri: file://${user.home}/config-repo
|
||||
where `${user.home}/config-repo` is a git repository containing
|
||||
YAML and properties files.
|
||||
|
||||
NOTE: in Windows you need an extra "/" in the file URL if it is
|
||||
NOTE: in Windows you need an extra "/" in the file URL if it is
|
||||
absolute with a drive prefix, e.g. `file:///${user.home}/config-repo`.
|
||||
|
||||
[TIP]
|
||||
====
|
||||
Here's a recipe for creating the git repository in the example
|
||||
Here's a recipe for creating the git repository in the example
|
||||
above:
|
||||
|
||||
----
|
||||
@@ -66,7 +67,7 @@ $ git commit -m "Add application.properties"
|
||||
====
|
||||
|
||||
WARNING: using the local filesystem for your git repository is
|
||||
intended for testing only. Use a server to host your
|
||||
intended for testing only. Use a server to host your
|
||||
configuration repositories in production.
|
||||
|
||||
WARNING: the initial clone of your configuration repository will
|
||||
@@ -87,7 +88,7 @@ Server? The strategy that governs this behaviour is the
|
||||
|
||||
* `{application}` maps to "spring.application.name" on the client side;
|
||||
|
||||
* `{profile}` maps to "spring.profiles.active" on the client (comma separated list); and
|
||||
* `{profile}` maps to "spring.profiles.active" on the client (comma separated list); and
|
||||
|
||||
* `{label}` which is a server side feature labelling a "versioned" set of config files.
|
||||
|
||||
@@ -112,7 +113,7 @@ spring:
|
||||
----
|
||||
|
||||
(as usual with a Spring Boot application, these properties could also
|
||||
be set as environment variables or command line arguments).
|
||||
be set as environment variables or command line arguments).
|
||||
|
||||
If the repository is file-based, the server will create an
|
||||
`Environment` from `application.yml` (shared between all clients), and
|
||||
@@ -265,7 +266,7 @@ In this example the server searches for config files in the top level
|
||||
and in the "foo/" sub-directory and also any sub-directory whose name
|
||||
begins with "bar".
|
||||
|
||||
By default the server clones remote repositories when configuration
|
||||
By default the server clones remote repositories when configuration
|
||||
is first requested. The server can be configured to clone the repositories
|
||||
at startup. For example at the top level:
|
||||
|
||||
@@ -289,11 +290,11 @@ spring:
|
||||
team-c:
|
||||
pattern: team-c-*
|
||||
uri: http://git/team-a/config-repo.git
|
||||
|
||||
|
||||
----
|
||||
|
||||
In this example the server clones team-a's config-repo on startup before it
|
||||
accepts any requests. All other repositories will not be cloned until
|
||||
In this example the server clones team-a's config-repo on startup before it
|
||||
accepts any requests. All other repositories will not be cloned until
|
||||
configuration from the repository is requested.
|
||||
|
||||
NOTE: Setting a repository to be cloned when the Config Server starts up can
|
||||
@@ -305,7 +306,7 @@ not detect an error until an application requests configuration from that
|
||||
configuration source.
|
||||
|
||||
To use HTTP basic authentication on the remote repository add the
|
||||
"username" and "password" properties separately (not in the URL),
|
||||
"username" and "password" properties separately (not in the URL),
|
||||
e.g.
|
||||
|
||||
[source,yaml]
|
||||
@@ -352,8 +353,8 @@ spring:
|
||||
----
|
||||
|
||||
searches the repository for files in the same name as the directory
|
||||
(as well as the top level). Wildcards are also valid in a search
|
||||
path with placeholders (any matching directory is included in the
|
||||
(as well as the top level). Wildcards are also valid in a search
|
||||
path with placeholders (any matching directory is included in the
|
||||
search).
|
||||
|
||||
==== Version Control Backend Filesystem Use
|
||||
@@ -367,7 +368,7 @@ Git, but just loads the config files from the local classpath or file
|
||||
system (any static URL you want to point to with
|
||||
"spring.cloud.config.server.native.searchLocations"). To use the
|
||||
native profile just launch the Config Server with
|
||||
"spring.profiles.active=native".
|
||||
"spring.profiles.active=native".
|
||||
|
||||
NOTE: Remember to use the `file:` prefix for file resources (the
|
||||
default without a prefix is usually the classpath). Just as with any
|
||||
@@ -383,7 +384,7 @@ property sources present in the server are removed before being sent
|
||||
to the client.
|
||||
|
||||
TIP: A filesystem backend is great for getting started quickly and
|
||||
for testing. To use it in production you need to be sure that the
|
||||
for testing. To use it in production you need to be sure that the
|
||||
file system is reliable, and shared across all instances of the
|
||||
Config Server.
|
||||
|
||||
@@ -622,7 +623,7 @@ You can disable the Health Indicator by setting `spring.cloud.config.server.heal
|
||||
You are free to secure your Config Server in any way that makes sense
|
||||
to you (from physical network security to OAuth2 bearer
|
||||
tokens), and Spring Security and Spring Boot make it easy to do pretty
|
||||
much anything.
|
||||
much anything.
|
||||
|
||||
To use the default Spring Boot configured HTTP Basic security, just
|
||||
include Spring Security on the classpath (e.g. through
|
||||
@@ -699,14 +700,14 @@ are special characters ('+' is particularly tricky).
|
||||
|
||||
Take the encrypted value and add the `{cipher}` prefix before you put
|
||||
it in the YAML or properties file, and before you commit and push it
|
||||
to a remote, potentially insecure store.
|
||||
to a remote, potentially insecure store.
|
||||
|
||||
The `/encrypt` and `/decrypt` endpoints also both accept paths of the
|
||||
form `/*/{name}/{profiles}` which can be used to control cryptography
|
||||
per application (name) and profile when clients call into the main
|
||||
Environment resource.
|
||||
|
||||
NOTE: to control the cryptography in this granular way you must also
|
||||
NOTE: to control the cryptography in this granular way you must also
|
||||
provide a `@Bean` of type `TextEncryptorLocator` that creates a
|
||||
different encryptor per name and profiles. The one that is provided
|
||||
by default does not do this (so all encryptions use the same key).
|
||||
@@ -747,8 +748,8 @@ PEM-encoded text value (in `encrypt.key`), or via a keystore (e.g. as
|
||||
created by the `keytool` utility that comes with the JDK). The
|
||||
keystore properties are `encrypt.keyStore.\*` with `*` equal to
|
||||
|
||||
* `location` (a `Resource` location),
|
||||
* `password` (to unlock the keystore) and
|
||||
* `location` (a `Resource` location),
|
||||
* `password` (to unlock the keystore) and
|
||||
* `alias` (to identify which key in the store is to be
|
||||
used).
|
||||
|
||||
@@ -1082,7 +1083,7 @@ an Exception.
|
||||
=== Config Client Retry
|
||||
|
||||
If you expect that the config server may occasionally be unavailable when
|
||||
your app starts, you can ask it to keep trying after a failure. First you need
|
||||
your app starts, you can ask it to keep trying after a failure. First you need
|
||||
to set `spring.cloud.config.failFast=true`, and then you need to add
|
||||
`spring-retry` and `spring-boot-starter-aop` to your classpath. The default
|
||||
behaviour is to retry 6 times with an initial backoff interval of 1000ms and an
|
||||
@@ -1105,10 +1106,10 @@ All of them can be overridden by setting `spring.cloud.config.\*`
|
||||
(where `*` is "name", "profile" or "label"). The "label" is useful for
|
||||
rolling back to previous versions of configuration; with the default
|
||||
Config Server implementation it can be a git label, branch name or
|
||||
commit id. Label can also be provided as a comma-separated list, in
|
||||
commit id. Label can also be provided as a comma-separated list, in
|
||||
which case the items in the list are tried on-by-one until one succeeds.
|
||||
This can be useful when working on a feature branch, for instance,
|
||||
when you might want to align the config label with your branch, but
|
||||
when you might want to align the config label with your branch, but
|
||||
make it optional (e.g. `spring.cloud.config.label=myfeature,develop`).
|
||||
|
||||
=== Security
|
||||
|
||||
35
mvnw
vendored
35
mvnw
vendored
@@ -46,15 +46,6 @@ if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
fi
|
||||
|
||||
VERSION=$(awk '/<parent/ {l=4}; (l-- > 0) {$0=$0} 1' `dirname $0`/pom.xml| grep '<version' | head -1 | sed -e 's/.*>\(.*\)<.*/\1/')
|
||||
if echo $VERSION | egrep -q 'M|RC'; then
|
||||
echo Activating \"milestone\" profile for version=\"$VERSION\"
|
||||
echo $MAVEN_ARGS | grep -q milestone || MAVEN_ARGS="$MAVEN_ARGS -Pmilestone"
|
||||
else
|
||||
echo Deactivating \"milestone\" profile for version=\"$VERSION\"
|
||||
echo $MAVEN_ARGS | grep -q milestone && MAVEN_ARGS=$(echo $MAVEN_ARGS | sed -e 's/-Pmilestone//')
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
@@ -66,27 +57,27 @@ case "`uname`" in
|
||||
#
|
||||
# Look for the Apple JDKs first to preserve the existing behaviour, and then look
|
||||
# for the new JDKs provided by Oracle.
|
||||
#
|
||||
#
|
||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
|
||||
fi
|
||||
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
||||
fi
|
||||
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then
|
||||
#
|
||||
# Oracle JDKs
|
||||
#
|
||||
export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then
|
||||
#
|
||||
@@ -228,16 +219,30 @@ concat_lines() {
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
VERSION=$(exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
-Dexec.executable="echo" -Dexec.args='${project.version}' ${WRAPPER_LAUNCHER} -q --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec )
|
||||
|
||||
if echo $VERSION | egrep -q 'M|RC'; then
|
||||
echo Activating \"milestone\" profile for version=\"$VERSION\"
|
||||
echo $MAVEN_ARGS | grep -q milestone || MAVEN_ARGS="$MAVEN_ARGS -Pmilestone"
|
||||
else
|
||||
echo Deactivating \"milestone\" profile for version=\"$VERSION\"
|
||||
echo $MAVEN_ARGS | grep -q milestone && MAVEN_ARGS=$(echo $MAVEN_ARGS | sed -e 's/-Pmilestone//')
|
||||
fi
|
||||
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} ${MAVEN_ARGS} "$@"
|
||||
|
||||
|
||||
@@ -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