Merge branch 'stable-3.5'

* stable-3.5:
  Don't depend on update ACL to create a branch

Change-Id: I89696dd0a6d94619b6d3817842c19e60b461fdef
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitiles/GerritGitilesAccess.java b/src/main/java/com/googlesource/gerrit/plugins/gitiles/GerritGitilesAccess.java
index d89b748..86a9088 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitiles/GerritGitilesAccess.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitiles/GerritGitilesAccess.java
@@ -14,6 +14,8 @@
 
 package com.googlesource.gerrit.plugins.gitiles;
 
+import static com.google.gerrit.extensions.client.ProjectState.HIDDEN;
+
 import com.google.common.collect.Maps;
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.entities.Project;
@@ -123,7 +125,9 @@
     }
     Map<String, RepositoryDescription> result = Maps.newLinkedHashMap();
     for (Map.Entry<String, ProjectInfo> e : projects.entrySet()) {
-      result.put(e.getKey(), toDescription(e.getKey(), e.getValue()));
+      if (!e.getValue().state.equals(HIDDEN)) {
+        result.put(e.getKey(), toDescription(e.getKey(), e.getValue()));
+      }
     }
     return Collections.unmodifiableMap(result);
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitiles/HttpModule.java b/src/main/java/com/googlesource/gerrit/plugins/gitiles/HttpModule.java
index a2d5c94..567c05a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitiles/HttpModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitiles/HttpModule.java
@@ -17,7 +17,7 @@
 import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gitiles.BranchRedirectFilter;
+import com.google.gitiles.BranchRedirect;
 import com.google.gitiles.GitilesAccess;
 import com.google.gitiles.GitilesServlet;
 import com.google.gitiles.GitilesUrls;
@@ -119,7 +119,7 @@
         null,
         null,
         null,
-        new BranchRedirectFilter());
+        new BranchRedirect());
   }
 
   @Provides
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitiles/PluginModule.java b/src/main/java/com/googlesource/gerrit/plugins/gitiles/PluginModule.java
index 5aab4cd..97ab188 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitiles/PluginModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitiles/PluginModule.java
@@ -43,17 +43,24 @@
 import java.net.URL;
 import java.net.UnknownHostException;
 import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
 import javax.servlet.http.HttpServletRequest;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.transport.resolver.RepositoryResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 class PluginModule extends LifecycleModule {
   private final boolean noWebLinks;
+  private final String cloneUrlType;
+  private static final Logger log = LoggerFactory.getLogger(Module.class);
 
   @Inject
   PluginModule(PluginConfigFactory configFactory) {
     Config config = configFactory.getGlobalPluginConfig("gitiles");
     this.noWebLinks = config.getBoolean("gerrit", null, "noWebLinks", false);
+    this.cloneUrlType = config.getString("gerrit", null, "cloneUrlType");
   }
 
   @Override
@@ -72,6 +79,82 @@
     listener().to(Lifecycle.class);
   }
 
+  private Optional<String> getSshCloneUrl(URL gerritUrl, List<String> advertisedSshAddresses) {
+    try {
+      if (!advertisedSshAddresses.isEmpty()) {
+        String addr = advertisedSshAddresses.get(0);
+        int index = addr.indexOf(":");
+        String port = "";
+        if (index != -1) {
+          port = addr.substring(index);
+        }
+        if (addr.startsWith("*:") || "".equals(addr)) {
+          if (gerritUrl != null && gerritUrl.getHost() != null) {
+            addr = gerritUrl.getHost();
+          } else {
+            addr = getLocalHostName();
+          }
+        } else {
+          if (index != -1) {
+            addr = addr.substring(0, index);
+          }
+        }
+        return Optional.of("ssh://" + addr + port + "/");
+      }
+    } catch (UnknownHostException e) {
+      log.error("Unable to get SSH clone url.", e);
+      return Optional.empty();
+    }
+    return Optional.empty();
+  }
+
+  private Optional<String> getHttpCloneUrl(Config gerritConfig) {
+    Optional<String> httpUrl =
+        Optional.ofNullable(gerritConfig.getString("gerrit", null, "gitHttpUrl"));
+    if (httpUrl.isEmpty()) {
+      return getDefaultCloneUrl(gerritConfig);
+    }
+    return httpUrl;
+  }
+
+  private Optional<String> getGitCloneUrl(Config gerritConfig) {
+    Optional<String> gitUrl =
+        Optional.ofNullable(gerritConfig.getString("gerrit", null, "canonicalGitUrl"));
+    if (gitUrl.isEmpty()) {
+      return getDefaultCloneUrl(gerritConfig);
+    }
+    return gitUrl;
+  }
+
+  private Optional<String> getDefaultCloneUrl(Config gerritConfig) {
+    return Optional.ofNullable(gerritConfig.getString("gerrit", null, "canonicalWebUrl"));
+  }
+
+  private Optional<String> getUserConfig(
+      Config gerritConfig, URL u, @SshAdvertisedAddresses List<String> advertisedSshAddresses) {
+    Optional<String> gitUrl = Optional.empty();
+    // Try to use user's config first.
+    if (this.cloneUrlType != null) {
+      switch (this.cloneUrlType) {
+        case "ssh":
+          gitUrl = getSshCloneUrl(u, advertisedSshAddresses);
+          break;
+        case "http":
+          gitUrl = getHttpCloneUrl(gerritConfig);
+          break;
+        case "git":
+          gitUrl = getGitCloneUrl(gerritConfig);
+          break;
+      }
+      if (gitUrl.isEmpty()) {
+        log.info(
+            "Failed to use clone url type configuration."
+                + " Using default type (prefer SSH, then HTTP, then Git).");
+      }
+    }
+    return gitUrl;
+  }
+
   @Provides
   GitilesUrls getGitilesUrls(
       @GerritServerConfig Config gerritConfig,
@@ -88,37 +171,22 @@
       hostName = "Gerrit";
     }
 
-    // Arbitrarily prefer SSH, then HTTP, then git.
-    // TODO: Use user preferences.
-    String gitUrl;
-    if (!advertisedSshAddresses.isEmpty()) {
-      String addr = advertisedSshAddresses.get(0);
-      int index = addr.indexOf(":");
-      String port = "";
-      if (index != -1) {
-        port = addr.substring(index);
-      }
-      if (addr.startsWith("*:") || "".equals(addr)) {
-        if (u != null && u.getHost() != null) {
-          addr = u.getHost();
-        } else {
-          addr = getLocalHostName();
-        }
-      } else {
-        if (index != -1) {
-          addr = addr.substring(0, index);
-        }
-      }
-      gitUrl = "ssh://" + addr + port + "/";
-    } else {
-      gitUrl = gerritConfig.getString("gerrit", null, "gitHttpUrl");
-      if (gitUrl == null) {
-        gitUrl = gerritConfig.getString("gerrit", null, "canonicalGitUrl");
-      }
-    }
-    if (gitUrl == null) {
-      throw new ProvisionException("Unable to determine any canonical git URL from gerrit.config");
-    }
+    // If no config is set, or we can't get the chosen type of URL determined in the config,
+    // arbitrarily prefer SSH, then HTTP, then git.
+    String gitUrl =
+        Stream.of(
+                getUserConfig(gerritConfig, u, advertisedSshAddresses),
+                getSshCloneUrl(u, advertisedSshAddresses),
+                getHttpCloneUrl(gerritConfig),
+                getGitCloneUrl(gerritConfig))
+            .filter(Optional::isPresent)
+            .map(Optional::get)
+            .findFirst()
+            .orElseThrow(
+                () ->
+                    new ProvisionException(
+                        "Unable to determine any canonical git URL from gerrit.config"));
+
     return new DefaultUrls(hostName, gitUrl, gerritUrl);
   }
 
diff --git a/src/main/resources/+Documentation/config.md b/src/main/resources/+Documentation/config.md
index 562603b..49d6c01 100644
--- a/src/main/resources/+Documentation/config.md
+++ b/src/main/resources/+Documentation/config.md
@@ -64,3 +64,16 @@
 
 Note: If using this setting you possibly want to set Gerrit's auth.cookiePath to "/"
 if it's not running in document root already.
+
+The flag `gerrit.cloneUrlType` can be set to either `ssh`, `http`, or `git`. This
+will determine which protocol to be used to display repos' clone url to the user:
+`git` will use value of `gerrit.canonicalGitUrl` and `http` will use the value of
+`gerrit.gitHttpUrl`. If those values are not set then http/git format will fall
+back to `gerrit.canonicalWebUrl`.
+If it's not set, or it fails to get the set type of URL, it will automatically prefer
+SSH, then HTTP, then Git.
+
+```
+  [gerrit]
+    cloneUrlType = http
+```
diff --git a/src/test/java/com/googlesource/gerrit/plugins/gitiles/ListProjectsAccessTest.java b/src/test/java/com/googlesource/gerrit/plugins/gitiles/ListProjectsAccessTest.java
index f6d9998..1dd4d2b 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/gitiles/ListProjectsAccessTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/gitiles/ListProjectsAccessTest.java
@@ -16,6 +16,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow;
+import static com.google.gerrit.extensions.client.ProjectState.HIDDEN;
 import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
 import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
 
@@ -27,6 +28,7 @@
 import com.google.gerrit.entities.Permission;
 import com.google.gerrit.entities.Project;
 import com.google.gerrit.extensions.api.projects.BranchInput;
+import com.google.gerrit.extensions.api.projects.ConfigInput;
 import com.google.gerrit.testing.ConfigSuite;
 import com.google.gerrit.util.http.testutil.FakeHttpServletRequest;
 import java.util.stream.Collectors;
@@ -94,6 +96,16 @@
         .containsExactly(ImmutableSet.of("refs/heads/visible"));
   }
 
+  @Test
+  public void listRepositories_hiddenShouldNotBeVisible() throws Exception {
+    assertThat(access().listRepositories(null, ImmutableSet.of()).keySet()).contains(project.get());
+    ConfigInput ci = new ConfigInput();
+    ci.state = HIDDEN;
+    gApi.projects().name(project.get()).config(ci);
+    assertThat(access().listRepositories(null, ImmutableSet.of()).keySet())
+        .doesNotContain(project.get());
+  }
+
   private GerritGitilesAccess access() {
     return plugin
         .getSysInjector()