Add branch protection check during the project import

When importing a GitHub repository into Gerrit, if the repository has
branch protection enabled, it would be impossible for Gerrit to push to
it. Call the GitHubApi to check if the repository contains protected
branches, if yes block import and give warning to the user.

Bug: Issue 14017
Change-Id: I34cf4f8fbec0b929577bc45005d5b4e9f8498a8a
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceHttpModule.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceHttpModule.java
index 12acdb2..4e6448b 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceHttpModule.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceHttpModule.java
@@ -24,6 +24,7 @@
 import com.googlesource.gerrit.plugins.github.git.GitCloneStep;
 import com.googlesource.gerrit.plugins.github.git.GitHubRepository;
 import com.googlesource.gerrit.plugins.github.git.GitImporter;
+import com.googlesource.gerrit.plugins.github.git.ProtectedBranchesCheckStep;
 import com.googlesource.gerrit.plugins.github.git.PullRequestImportJob;
 import com.googlesource.gerrit.plugins.github.git.ReplicateProjectStep;
 import com.googlesource.gerrit.plugins.github.notification.WebhookServlet;
@@ -51,6 +52,10 @@
 
     install(
         new FactoryModuleBuilder()
+            .implement(ProtectedBranchesCheckStep.class, ProtectedBranchesCheckStep.class)
+            .build(ProtectedBranchesCheckStep.Factory.class));
+    install(
+        new FactoryModuleBuilder()
             .implement(GitCloneStep.class, GitCloneStep.class)
             .build(GitCloneStep.Factory.class));
     install(
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/AbstractCloneJob.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/AbstractCloneJob.java
index 4421841..753575f 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/AbstractCloneJob.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/AbstractCloneJob.java
@@ -26,6 +26,9 @@
 
   protected String getErrorDescription(Throwable exception) {
     LOG.error("Job " + this + " FAILED", exception);
+    if (exception instanceof ProtectedBranchFoundException) {
+      return exception.getMessage();
+    }
     if (GitException.class.isAssignableFrom(exception.getClass())) {
       return ((GitException) exception).getErrorDescription();
     } else if (ProvisionException.class.isAssignableFrom(exception.getClass())) {
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitImporter.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitImporter.java
index 0176091..66a7b5c 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitImporter.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitImporter.java
@@ -26,18 +26,21 @@
   public static class Provider extends HttpSessionProvider<GitImporter> {}
 
   private static final Logger log = LoggerFactory.getLogger(GitImporter.class);
+  private final ProtectedBranchesCheckStep.Factory protectedBranchesCheckFactory;
   private final GitCloneStep.Factory cloneFactory;
   private final CreateProjectStep.Factory projectFactory;
   private final ReplicateProjectStep.Factory replicateFactory;
 
   @Inject
   public GitImporter(
+      ProtectedBranchesCheckStep.Factory protectedBranchesCheckFactory,
       GitCloneStep.Factory cloneFactory,
       CreateProjectStep.Factory projectFactory,
       ReplicateProjectStep.Factory replicateFactory,
       JobExecutor executor,
       IdentifiedUser user) {
     super(executor, user);
+    this.protectedBranchesCheckFactory = protectedBranchesCheckFactory;
     this.cloneFactory = cloneFactory;
     this.projectFactory = projectFactory;
     this.replicateFactory = replicateFactory;
@@ -45,12 +48,21 @@
 
   public void clone(int idx, String organisation, String repository, String description) {
     try {
+      ProtectedBranchesCheckStep protectedBranchesCheckStep =
+          protectedBranchesCheckFactory.create(organisation, repository);
       GitCloneStep cloneStep = cloneFactory.create(organisation, repository);
       CreateProjectStep projectStep =
           projectFactory.create(organisation, repository, description, user.getUserName().get());
       ReplicateProjectStep replicateStep = replicateFactory.create(organisation, repository);
       GitImportJob gitCloneJob =
-          new GitImportJob(idx, organisation, repository, cloneStep, projectStep, replicateStep);
+          new GitImportJob(
+              idx,
+              organisation,
+              repository,
+              protectedBranchesCheckStep,
+              cloneStep,
+              projectStep,
+              replicateStep);
       log.debug("New Git clone job created: " + gitCloneJob);
       schedule(idx, gitCloneJob);
     } catch (Throwable e) {
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchFoundException.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchFoundException.java
new file mode 100644
index 0000000..221152f
--- /dev/null
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchFoundException.java
@@ -0,0 +1,22 @@
+// Copyright (C) 2021 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;
+
+public class ProtectedBranchFoundException extends Exception {
+
+  public ProtectedBranchFoundException(String msg) {
+    super(msg);
+  }
+}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchesCheckStep.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchesCheckStep.java
new file mode 100644
index 0000000..5b2f763
--- /dev/null
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchesCheckStep.java
@@ -0,0 +1,67 @@
+// Copyright (C) 2021 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.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+import com.googlesource.gerrit.plugins.github.GitHubConfig;
+import java.util.Collection;
+import java.util.List;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.kohsuke.github.GHBranch;
+
+public class ProtectedBranchesCheckStep extends ImportStep {
+
+  public interface Factory {
+    ProtectedBranchesCheckStep create(
+        @Assisted("organisation") String organisation, @Assisted("name") String repository);
+  }
+
+  @Inject
+  public ProtectedBranchesCheckStep(
+      GitHubConfig config,
+      GitHubRepository.Factory gitHubRepoFactory,
+      @Assisted("organisation") String organisation,
+      @Assisted("name") String repository) {
+    super(config.gitHubUrl, organisation, repository, gitHubRepoFactory);
+  }
+
+  @Override
+  public void doImport(ProgressMonitor progress) throws Exception {
+    Collection<GHBranch> branches = getRepository().getBranches().values();
+    progress.beginTask("Checking branch protection", branches.size());
+    List<String> protectedBranchNames = Lists.newLinkedList();
+    for (GHBranch branch : branches) {
+      if (branch.isProtected()) {
+        protectedBranchNames.add(branch.getName());
+      }
+      progress.update(1);
+    }
+    progress.endTask();
+    if (!protectedBranchNames.isEmpty()) {
+      throw new ProtectedBranchFoundException(
+          String.format(
+              "Cannot import project with protected branches, you should remove protection from:%s",
+              Joiner.on(",").join(protectedBranchNames)));
+    }
+  }
+
+  @Override
+  public boolean rollback() {
+    return true;
+  }
+}