Merge "Add adminUrl to replication for repository creation"
diff --git a/Documentation/config-replication.txt b/Documentation/config-replication.txt
index 76b7fff..81fda98 100644
--- a/Documentation/config-replication.txt
+++ b/Documentation/config-replication.txt
@@ -93,6 +93,19 @@
 See link:http://www.kernel.org/pub/software/scm/git/docs/git-push.html#URLS[GIT URLS]
 for details on Git URL syntax.
 
+[[remote.name.url]]remote.<name>.adminUrl::
++
+Address of the alternative remote server only for repository creation.  Multiple URLs may
+be specified within a single remote block, listing different
+destinations which share the same settings.
++
+The adminUrl can be used as a ssh alternative to the url option, but only related to repository creation.
+If not specified, the repository creation tries to follow the default way through the url value specified.
++
+It is useful when remote.<name>.url protocols does not allow repository creation
+although their usage are mandatory in the local environment.
+In that case, an alternative ssh url could be specified to repository creation.
+
 [[remote.name.receivepack]]remote.<name>.receivepack::
 +
 Path of the `git-receive-pack` executable on the remote system, if
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java
index 9126947..9db9e44 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java
@@ -122,7 +122,12 @@
   private static String replace(final String pat, final String key,
       final String val) {
     final int n = pat.indexOf("${" + key + "}");
-    return pat.substring(0, n) + val + pat.substring(n + 3 + key.length());
+
+    if (n != -1) {
+      return pat.substring(0, n) + val + pat.substring(n + 3 + key.length());
+    } else {
+      return null;
+    }
   }
 
   private List<ReplicationConfig> allConfigs(final SitePaths site)
@@ -162,7 +167,8 @@
         }
       }
 
-      // In case if refspec destination for push is not set then we assume it is equal to source
+      // In case if refspec destination for push is not set then we assume it is
+      // equal to source
       for (RefSpec ref : c.getPushRefSpecs()) {
         if (ref.getDestination() == null) {
           ref.setDestination(ref.getSource());
@@ -208,9 +214,39 @@
 
     for (ReplicationConfig config : configs) {
       List<URIish> uriList = config.getURIs(projectName, "*");
+      String[] adminUrls = config.getAdminUrls();
+      boolean adminURLUsed = false;
 
-      for (URIish uri : uriList) {
-        replicateProject(uri, head);
+      for (String url : adminUrls) {
+        URIish adminURI = null;
+        try {
+          if (url != null && !url.isEmpty()) {
+            adminURI = new URIish(url);
+          }
+        } catch (URISyntaxException e) {
+          log.error("The URL '" + url + "' is invalid");
+        }
+
+        if (adminURI != null) {
+          final String replacedPath =
+              replace(adminURI.getPath(), "name", projectName.get());
+          if (replacedPath != null) {
+            adminURI = adminURI.setPath(replacedPath);
+            if (usingSSH(adminURI)) {
+              replicateProject(adminURI, head);
+              adminURLUsed = true;
+            } else {
+              log.error("The adminURL '" + url
+                  + "' is non-SSH which is not allowed");
+            }
+          }
+        }
+      }
+
+      if (!adminURLUsed) {
+        for (URIish uri : uriList) {
+          replicateProject(uri, head);
+        }
       }
     }
   }
@@ -296,6 +332,7 @@
 
   static class ReplicationConfig {
     private final RemoteConfig remote;
+    private final String[] adminUrls;
     private final int delay;
     private final int retryDelay;
     private final WorkQueue.Executor pool;
@@ -325,6 +362,8 @@
         authGroups = ReplicationUser.EVERYTHING_VISIBLE;
       }
 
+      adminUrls = cfg.getStringList("remote", rc.getName(), "adminUrl");
+
       final ReplicationUser remoteUser =
           replicationUserFactory.create(authGroups);
 
@@ -492,13 +531,21 @@
       final List<URIish> r = new ArrayList<URIish>(remote.getURIs().size());
       for (URIish uri : remote.getURIs()) {
         if (matches(uri, urlMatch)) {
-          uri = uri.setPath(replace(uri.getPath(), "name", project.get()));
-          r.add(uri);
+          final String replacedPath =
+              replace(uri.getPath(), "name", project.get());
+          if (replacedPath != null) {
+            uri = uri.setPath(replacedPath);
+            r.add(uri);
+          }
         }
       }
       return r;
     }
 
+    String[] getAdminUrls() {
+      return this.adminUrls;
+    }
+
     private boolean matches(URIish uri, final String urlMatch) {
       if (urlMatch == null || urlMatch.equals("") || urlMatch.equals("*")) {
         return true;