summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdwin Kempin <edwin.kempin@sap.com>2013-09-12 15:24:56 +0200
committerOswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>2015-02-10 21:05:17 +0000
commit70371bc583fa0387e66ec42d6504641e2f5d7779 (patch)
tree5de8833789bc7d18057015eed1c3b8c6ec5b6c60
parente5cb89869362bc0d75b786561c77952f3f5896d9 (diff)
Create missing repositories on the remote site
If during the replication of a ref it is found that the repository is missing on the remote site automatically create it on the remote site. E.g. a repository can be missing on the remote site if the remote site was not available at the moment when a new project was created and hence the repository for the new project could not be created on the remote site. This feature can also help to simplify the setup of a new remote site. Whether missing repositories should be created or not can be configured per destination. By default missing repositories are created. This is a change of the current behaviour but for most configurations it makes sense that the missing repositories are created which is why this should be the default. Change-Id: I4e587cdfca09445c9b1c528b2f1edae0944aec68 Signed-off-by: Edwin Kempin <edwin.kempin@sap.com> (cherry picked from commit a9fcff5c4d0d99d7bc209431377bdba01ee04c2c) Reviewed-by: Ismo Haataja <ismo.haataja@digia.com> Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java9
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java34
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java16
-rw-r--r--src/main/resources/Documentation/config.md10
4 files changed, 61 insertions, 8 deletions
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java
index 65e9631..1054aed 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java
@@ -81,13 +81,14 @@ class Destination {
private final PushOne.Factory opFactory;
private final ProjectControl.Factory projectControlFactory;
private final GitRepositoryManager gitManager;
+ private final boolean createMissingRepos;
private final boolean replicatePermissions;
private final String remoteNameStyle;
private volatile WorkQueue.Executor pool;
private final PerThreadRequestScope.Scoper threadScoper;
protected static enum RetryReason {
- TRANSPORT_ERROR, COLLISION;
+ TRANSPORT_ERROR, COLLISION, REPOSITORY_MISSING;
}
Destination(final Injector injector,
@@ -106,6 +107,8 @@ class Destination {
poolThreads = Math.max(0, getInt(rc, cfg, "threads", 1));
poolName = "ReplicateTo-" + rc.getName();
+ createMissingRepos =
+ cfg.getBoolean("remote", rc.getName(), "createMissingRepositories", true);
replicatePermissions =
cfg.getBoolean("remote", rc.getName(), "replicatePermissions", true);
remoteNameStyle = Objects.firstNonNull(
@@ -438,6 +441,10 @@ class Destination {
return false;
}
+ boolean isCreateMissingRepos() {
+ return createMissingRepos;
+ }
+
boolean isReplicatePermissions() {
return replicatePermissions;
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java b/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java
index 596d4ac..897d120 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java
@@ -21,6 +21,7 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
+import com.google.gerrit.extensions.events.NewProjectCreatedListener;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.git.ChangeCache;
@@ -91,6 +92,7 @@ class PushOne implements ProjectRunnable {
private final TagCache tagCache;
private final PerThreadRequestScope.Scoper threadScoper;
private final ChangeCache changeCache;
+ private final ReplicationQueue replicationQueue;
private final Project.NameKey projectName;
private final URIish uri;
@@ -112,6 +114,7 @@ class PushOne implements ProjectRunnable {
final TagCache tc,
final PerThreadRequestScope.Scoper ts,
final ChangeCache cc,
+ final ReplicationQueue rq,
@Assisted final Project.NameKey d,
@Assisted final URIish u) {
gitManager = grm;
@@ -122,6 +125,7 @@ class PushOne implements ProjectRunnable {
tagCache = tc;
threadScoper = ts;
changeCache = cc;
+ replicationQueue = rq;
projectName = d;
uri = u;
}
@@ -268,7 +272,18 @@ class PushOne implements ProjectRunnable {
log.error("Cannot replicate " + projectName + "; " + e.getMessage());
} catch (NoRemoteRepositoryException e) {
- wrappedLog.error("Cannot replicate to " + uri + "; repository not found", getStatesAsArray());
+ if (pool.isCreateMissingRepos()) {
+ try {
+ createRepository();
+ log.warn("Missing repository created; retry replication to " + uri);
+ pool.reschedule(this, Destination.RetryReason.REPOSITORY_MISSING);
+ } catch (IOException ioe) {
+ wrappedLog.error("Cannot replicate to " + uri + "; failed to create missing repository",
+ ioe, getStatesAsArray());
+ }
+ } else {
+ wrappedLog.error("Cannot replicate to " + uri + "; repository not found", getStatesAsArray());
+ }
} catch (NotSupportedException e) {
wrappedLog.error("Cannot replicate to " + uri, e, getStatesAsArray());
@@ -301,6 +316,23 @@ class PushOne implements ProjectRunnable {
}
}
+ private void createRepository() throws IOException {
+ final Ref head = git.getRef(Constants.HEAD);
+ NewProjectCreatedListener.Event event =
+ new NewProjectCreatedListener.Event() {
+ @Override
+ public String getProjectName() {
+ return projectName.get();
+ }
+
+ @Override
+ public String getHeadName() {
+ return head != null ? head.getName() : null;
+ }
+ };
+ replicationQueue.onNewProjectCreated(event);
+ }
+
private void runImpl() throws IOException {
Transport tn = Transport.open(git, uri);
PushResult res;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java
index a39d61c..502994a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java
@@ -319,9 +319,11 @@ class ReplicationQueue implements
try {
repo.create(true /* bare */);
- RefUpdate u = repo.updateRef(Constants.HEAD);
- u.disableRefLog();
- u.link(head);
+ if (head != null) {
+ RefUpdate u = repo.updateRef(Constants.HEAD);
+ u.disableRefLog();
+ u.link(head);
+ }
} finally {
repo.close();
}
@@ -333,9 +335,11 @@ class ReplicationQueue implements
private static void createRemoteSsh(URIish uri, String head) {
String quotedPath = QuotedString.BOURNE.quote(uri.getPath());
String cmd = "mkdir -p " + quotedPath
- + "&& cd " + quotedPath
- + "&& git init --bare"
- + "&& git symbolic-ref HEAD " + QuotedString.BOURNE.quote(head);
+ + " && cd " + quotedPath
+ + " && git init --bare";
+ if (head != null) {
+ cmd = cmd + " && git symbolic-ref HEAD " + QuotedString.BOURNE.quote(head);
+ }
OutputStream errStream = newErrorBufferStream();
try {
RemoteSession ssh = connect(uri);
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 5205025..e22409a 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -205,6 +205,16 @@ remote.NAME.authGroup
By default, replicates without group control, i.e. replicates
everything to all remotes.
+remote.NAME.createMissingRepositories
+: If true, a repository is automatically created on the remote site
+ if during the replication of a ref it is found to be missing.
+ E.g. a repository can be missing on the remote site if the remote
+ site was not available at the moment when a new project was created
+ and hence the repository for the new project could not be created on
+ the remote site.
+
+ By default, true, missing repositories are created.
+
remote.NAME.replicatePermissions
: If true, permissions-only projects and the refs/meta/config
branch will also be replicated to the remote site. These