Merge branch 'stable-3.2'

* stable-3.2:
  Set version to 3.2.1
  Fix repositories listing by checking Gerrit repo with Optional
  Bump version to v3.1.4 to match Gerrit
  Adopt new replication configuration structure

Change-Id: I7d8618be9a20f1ebef382190c815af4e57a1ae3b
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceModule.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceModule.java
index 24754a3..9bff585 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceModule.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceModule.java
@@ -18,13 +18,18 @@
 import com.google.gerrit.extensions.restapi.RestApiModule;
 import com.google.gerrit.extensions.webui.TopMenu;
 import com.google.gerrit.server.account.GroupBackend;
+import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.events.EventListener;
 import com.google.gerrit.server.project.ProjectResource;
 import com.google.gson.Gson;
 import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
 import com.google.inject.Scopes;
 import com.google.inject.TypeLiteral;
 import com.google.inject.assistedinject.FactoryModuleBuilder;
+import com.googlesource.gerrit.plugins.github.git.FanoutReplicationConfig;
+import com.googlesource.gerrit.plugins.github.git.FileBasedReplicationConfig;
+import com.googlesource.gerrit.plugins.github.git.ReplicationConfig;
 import com.googlesource.gerrit.plugins.github.group.GitHubGroupBackend;
 import com.googlesource.gerrit.plugins.github.group.GitHubGroupMembership;
 import com.googlesource.gerrit.plugins.github.group.GitHubGroupsCache;
@@ -37,8 +42,17 @@
 import com.googlesource.gerrit.plugins.github.replication.ReplicationStatusFlatFile;
 import com.googlesource.gerrit.plugins.github.replication.ReplicationStatusListener;
 import com.googlesource.gerrit.plugins.github.replication.ReplicationStatusStore;
+import java.nio.file.Files;
 
 public class GuiceModule extends AbstractModule {
+
+  private final SitePaths site;
+
+  @Inject
+  public GuiceModule(SitePaths site) {
+    this.site = site;
+  }
+
   @Override
   protected void configure() {
     bind(new TypeLiteral<UserScopedProvider<GitHubLogin>>() {})
@@ -61,6 +75,12 @@
           }
         });
 
+    if (Files.exists(site.etc_dir.resolve("replication"))) {
+      bind(ReplicationConfig.class).to(FanoutReplicationConfig.class).in(Scopes.SINGLETON);
+    } else {
+      bind(ReplicationConfig.class).to(FileBasedReplicationConfig.class).in(Scopes.SINGLETON);
+    }
+
     bind(ReplicationStatusStore.class).to(ReplicationStatusFlatFile.class).in(Scopes.SINGLETON);
     bind(Gson.class).toProvider(GerritGsonProvider.class);
   }
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/FanoutReplicationConfig.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/FanoutReplicationConfig.java
new file mode 100644
index 0000000..412c2ff
--- /dev/null
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/FanoutReplicationConfig.java
@@ -0,0 +1,65 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.github.git;
+
+import com.google.gerrit.server.config.SitePaths;
+import com.google.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+
+public class FanoutReplicationConfig implements ReplicationConfig {
+  private final SitePaths site;
+  private final FileBasedConfig secureConf;
+
+  @Inject
+  public FanoutReplicationConfig(final SitePaths site) {
+    this.site = site;
+    this.secureConf = new FileBasedConfig(site.secure_config.toFile(), FS.DETECTED);
+  }
+
+  @Override
+  public void addSecureCredentials(String authUsername, String authToken)
+      throws IOException, ConfigInvalidException {
+    secureConf.load();
+    secureConf.setString("remote", authUsername, "username", authUsername);
+    secureConf.setString("remote", authUsername, "password", authToken);
+    secureConf.save();
+  }
+
+  @Override
+  public void addReplicationRemote(String githubUsername, String url, String projectName)
+      throws IOException, ConfigInvalidException {
+
+    FileBasedConfig replicationConf =
+        new FileBasedConfig(
+            new File(site.etc_dir.toFile(), String.format("replication/%s.config", githubUsername)),
+            FS.DETECTED);
+
+    replicationConf.load();
+    replicationConf.setString("remote", null, "url", url);
+    List<String> projects =
+        new ArrayList<>(Arrays.asList(replicationConf.getStringList("remote", null, "projects")));
+    projects.add(projectName);
+    replicationConf.setStringList("remote", null, "projects", projects);
+    replicationConf.setString("remote", null, "push", "refs/*:refs/*");
+    replicationConf.save();
+  }
+}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/FileBasedReplicationConfig.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/FileBasedReplicationConfig.java
new file mode 100644
index 0000000..842bde3
--- /dev/null
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/FileBasedReplicationConfig.java
@@ -0,0 +1,60 @@
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.googlesource.gerrit.plugins.github.git;
+
+import com.google.gerrit.server.config.SitePaths;
+import com.google.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+
+public class FileBasedReplicationConfig implements ReplicationConfig {
+  private final FileBasedConfig secureConf;
+  private final FileBasedConfig replicationConf;
+
+  @Inject
+  public FileBasedReplicationConfig(final SitePaths site) {
+    replicationConf =
+        new FileBasedConfig(new File(site.etc_dir.toFile(), "replication.config"), FS.DETECTED);
+    secureConf = new FileBasedConfig(site.secure_config.toFile(), FS.DETECTED);
+  }
+
+  @Override
+  public synchronized void addSecureCredentials(String authUsername, String authToken)
+      throws IOException, ConfigInvalidException {
+    secureConf.load();
+    secureConf.setString("remote", authUsername, "username", authUsername);
+    secureConf.setString("remote", authUsername, "password", authToken);
+    secureConf.save();
+  }
+
+  @Override
+  public synchronized void addReplicationRemote(String username, String url, String projectName)
+      throws IOException, ConfigInvalidException {
+    replicationConf.load();
+    replicationConf.setString("remote", username, "url", url);
+    List<String> projects =
+        new ArrayList<>(
+            Arrays.asList(replicationConf.getStringList("remote", username, "projects")));
+    projects.add(projectName);
+    replicationConf.setStringList("remote", username, "projects", projects);
+    replicationConf.setString("remote", username, "push", "refs/*:refs/*");
+    replicationConf.save();
+  }
+}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ReplicationConfig.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ReplicationConfig.java
index bd9ee79..8b7712a 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ReplicationConfig.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ReplicationConfig.java
@@ -11,50 +11,17 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
+
 package com.googlesource.gerrit.plugins.github.git;
 
-import com.google.gerrit.server.config.SitePaths;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import java.io.File;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
 import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.eclipse.jgit.storage.file.FileBasedConfig;
-import org.eclipse.jgit.util.FS;
 
-@Singleton
-public class ReplicationConfig {
-  private final FileBasedConfig secureConf;
-  private final FileBasedConfig replicationConf;
+public interface ReplicationConfig {
 
-  @Inject
-  public ReplicationConfig(final SitePaths site) {
-    replicationConf =
-        new FileBasedConfig(new File(site.etc_dir.toFile(), "replication.config"), FS.DETECTED);
-    secureConf = new FileBasedConfig(site.secure_config.toFile(), FS.DETECTED);
-  }
+  void addSecureCredentials(String authUsername, String authToken)
+      throws IOException, ConfigInvalidException;
 
-  public synchronized void addSecureCredentials(String authUsername, String authToken)
-      throws IOException, ConfigInvalidException {
-    secureConf.load();
-    secureConf.setString("remote", authUsername, "username", authUsername);
-    secureConf.setString("remote", authUsername, "password", authToken);
-    secureConf.save();
-  }
-
-  public synchronized void addReplicationRemote(String username, String url, String projectName)
-      throws IOException, ConfigInvalidException {
-    replicationConf.load();
-    replicationConf.setString("remote", username, "url", url);
-    List<String> projects =
-        new ArrayList<>(
-            Arrays.asList(replicationConf.getStringList("remote", username, "projects")));
-    projects.add(projectName);
-    replicationConf.setStringList("remote", username, "projects", projects);
-    replicationConf.setString("remote", username, "push", "refs/*:refs/*");
-    replicationConf.save();
-  }
+  void addReplicationRemote(String username, String url, String projectName)
+      throws IOException, ConfigInvalidException;
 }
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/RepositoriesListController.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/RepositoriesListController.java
index bd069a8..2cf6170 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/RepositoriesListController.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/RepositoriesListController.java
@@ -67,7 +67,7 @@
       if (ghRepository.hasPushAccess() && ghRepository.hasPullAccess()) {
         JsonObject repository = new JsonObject();
         String projectName = organisation + "/" + ghRepository.getName();
-        if (projects.get(Project.NameKey.parse(projectName)) == null) {
+        if (!projects.get(Project.NameKey.parse(projectName)).isPresent()) {
           repository.add("name", new JsonPrimitive(ghRepository.getName()));
           repository.add("organisation", new JsonPrimitive(organisation));
           repository.add(