Use Gerrit API to create a new Project

By using the Gerrit API, when a new repository is imported from GitHub,
all the events happening on Gerrit are honoured as the repo was
created from the UX or CLI.
This allow all the listeners to react and execute the appropriate
actions, including generating stream events and aligning failover nodes.

Change-Id: Ie6763a80cac27e7b44216ca0f423fef4442e7a7a
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java
index 2a56590..dde33ff 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java
@@ -13,13 +13,18 @@
 // limitations under the License.
 package com.googlesource.gerrit.plugins.github.git;
 
+import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 import com.googlesource.gerrit.plugins.github.GitHubConfig;
 import java.io.File;
 import java.io.IOException;
 import org.apache.commons.io.FileUtils;
-import org.eclipse.jgit.api.CloneCommand;
+import org.eclipse.jgit.api.FetchCommand;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -28,6 +33,7 @@
   private static final Logger LOG = LoggerFactory.getLogger(GitImporter.class);
 
   private final File gitDir;
+  private final GerritApi gerritApi;
   private File destinationDirectory;
 
   public interface Factory {
@@ -39,49 +45,46 @@
   public GitCloneStep(
       GitHubConfig gitConfig,
       GitHubRepository.Factory gitHubRepoFactory,
+      GerritApi gerritApi,
       @Assisted("organisation") String organisation,
       @Assisted("name") String repository)
-      throws GitDestinationAlreadyExistsException, GitDestinationNotWritableException {
+      throws GitException {
     super(gitConfig.gitHubUrl, organisation, repository, gitHubRepoFactory);
     LOG.debug("GitHub Clone " + organisation + "/" + repository);
     this.gitDir = gitConfig.gitDir.toFile();
-    this.destinationDirectory = prepareTargetGitDirectory(organisation, repository);
+
+    this.gerritApi = gerritApi;
+    this.destinationDirectory =
+        prepareTargetGitDirectory(gerritApi, gitDir, organisation, repository);
   }
 
-  private File prepareTargetGitDirectory(String organisation, String repository)
-      throws GitDestinationAlreadyExistsException, GitDestinationNotWritableException {
-    File orgDirectory = new File(gitDir, organisation);
-    File destDirectory = new File(orgDirectory, repository + ".git");
-    if (destDirectory.exists() && isNotEmpty(destDirectory)) {
-      throw new GitDestinationAlreadyExistsException(destDirectory);
+  private static File prepareTargetGitDirectory(
+      GerritApi gerritApi, File gitDir, String organisation, String repository)
+      throws GitException {
+    String projectName = organisation + "/" + repository;
+    try {
+      gerritApi.projects().create(projectName).get();
+      return new File(gitDir, projectName + ".git");
+    } catch (ResourceConflictException e) {
+      throw new GitDestinationAlreadyExistsException(projectName);
+    } catch (RestApiException e) {
+      throw new GitException("Unable to create repository " + projectName, e);
     }
-
-    if (!orgDirectory.exists()) {
-      if (!orgDirectory.mkdirs()) {
-        throw new GitDestinationNotWritableException(destDirectory);
-      }
-    }
-
-    return destDirectory;
   }
 
   @Override
-  public void doImport(ProgressMonitor progress)
-      throws GitCloneFailedException, GitDestinationAlreadyExistsException,
-          GitDestinationNotWritableException {
-    CloneCommand clone = new CloneCommand();
-    clone.setCredentialsProvider(getRepository().getCredentialsProvider());
+  public void doImport(ProgressMonitor progress) throws GitCloneFailedException {
     String sourceUri = getSourceUri();
-    clone.setURI(sourceUri);
-    clone.setBare(true);
-    clone.setDirectory(destinationDirectory);
-    if (progress != null) {
-      clone.setProgressMonitor(progress);
-    }
-    try {
+    try (Git git = Git.open(destinationDirectory)) {
+      FetchCommand fetch = git.fetch().setRefSpecs("refs/*:refs/*").setRemote(sourceUri);
+      fetch.setCredentialsProvider(getRepository().getCredentialsProvider());
+      if (progress != null) {
+        fetch.setProgressMonitor(progress);
+      }
       LOG.info(sourceUri + "| Clone into " + destinationDirectory);
-      clone.call();
-    } catch (Throwable e) {
+      fetch.call();
+    } catch (IOException | GitAPIException e) {
+      LOG.error("Unable to fetch from {} into {}", sourceUri, destinationDirectory, e);
       throw new GitCloneFailedException(sourceUri, e);
     }
   }
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitDestinationAlreadyExistsException.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitDestinationAlreadyExistsException.java
index b9088f4..bf0311b 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitDestinationAlreadyExistsException.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitDestinationAlreadyExistsException.java
@@ -13,13 +13,11 @@
 // limitations under the License.
 package com.googlesource.gerrit.plugins.github.git;
 
-import java.io.File;
-
 public class GitDestinationAlreadyExistsException extends GitException {
   private static final long serialVersionUID = -6202681486717426148L;
 
-  public GitDestinationAlreadyExistsException(File destDirectory) {
-    super("Output Git destination " + destDirectory + " already exists and cannot be overwritten");
+  public GitDestinationAlreadyExistsException(String projectName) {
+    super("Git project " + projectName + " already exists");
   }
 
   @Override
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitException.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitException.java
index d73e7e2..c139f8e 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitException.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitException.java
@@ -15,7 +15,7 @@
 
 import java.io.IOException;
 
-public abstract class GitException extends IOException {
+public class GitException extends IOException {
   private static final long serialVersionUID = -1180349547385523064L;
 
   public GitException() {
@@ -34,5 +34,7 @@
     super(message, cause);
   }
 
-  public abstract String getErrorDescription();
+  public String getErrorDescription() {
+    return getMessage();
+  }
 }