Add new configuration option to control replication of hidden projects

In some cases we would like to replicate hidden projects to given
remotes. Right now it is not possible to achieve this, all hidden
projects are not replicated.

New remote.NAME.replicateHiddenProjects configuration allow to control
this behavior. By default it is set to 'false' to be consistent with
previous versions.

Change-Id: Ie7d7330ae685e104937037a89141cef2febbf5f1
Signed-off-by: Dariusz Luksza <dariusz@luksza.org>
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 98a642e..8164c09 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java
@@ -199,13 +199,15 @@
     return cnt;
   }
 
-  private boolean isVisible(final Project.NameKey project,
+  private boolean shouldReplicate(final Project.NameKey project,
       ReplicationState... states) {
     try {
       return threadScoper.scope(new Callable<Boolean>() {
         @Override
         public Boolean call() throws NoSuchProjectException {
-          return controlFor(project).isVisible();
+          ProjectControl projectControl = controlFor(project);
+          return projectControl.isReadable() && (!projectControl.isHidden()
+              || config.replicateHiddenProjects());
         }
       }).call();
     } catch (NoSuchProjectException err) {
@@ -221,7 +223,7 @@
   void schedule(Project.NameKey project, String ref, URIish uri,
       ReplicationState state) {
     repLog.info("scheduling replication {}:{} => {}", project, ref, uri);
-    if (!isVisible(project, state)) {
+    if (!shouldReplicate(project, state)) {
       return;
     }
 
@@ -385,7 +387,7 @@
   }
 
   boolean wouldPushProject(Project.NameKey project) {
-    if (!isVisible(project)) {
+    if (!shouldReplicate(project)) {
       return false;
     }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationConfiguration.java b/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationConfiguration.java
index 6beb644..0d7d3ce 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationConfiguration.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationConfiguration.java
@@ -29,6 +29,7 @@
   private final boolean createMissingRepos;
   private final boolean replicatePermissions;
   private final boolean replicateProjectDeletions;
+  private final boolean replicateHiddenProjects;
   private final String remoteNameStyle;
   private final ImmutableList<String> urls;
   private final ImmutableList<String> projects;
@@ -57,6 +58,8 @@
         cfg.getBoolean("remote", name, "replicatePermissions", true);
     replicateProjectDeletions =
         cfg.getBoolean("remote", name, "replicateProjectDeletions", false);
+    replicateHiddenProjects =
+        cfg.getBoolean("remote", name, "replicateHiddenProjects", false);
     remoteNameStyle = MoreObjects.firstNonNull(
         cfg.getString("remote", name, "remoteNameStyle"), "slash");
   }
@@ -109,6 +112,10 @@
     return replicateProjectDeletions;
   }
 
+  public boolean replicateHiddenProjects() {
+    return replicateHiddenProjects;
+  }
+
   public RemoteConfig getRemoteConfig() {
     return remoteConfig;
   }
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index a528565..709d61f 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -262,6 +262,11 @@
 
 	By default, false, do *not* replicate project deletions.
 
+remote.NAME.replicateHiddenProjects
+:	If true, hidden projects will be replicated to the remote site.
+
+	By default, false, do *not* replicate hidden projects.
+
 remote.NAME.mirror
 :	If true, replication will remove remote branches that are absent
 	locally or invisible to the replication (for example read