Delete import refs on completion of a project import

After an import is completed the refs in the 'refs/imports/' namespace
are not needed anymore. They rather disturb when an imported project
is copied or imported into another server, because then we have the
old import refs under 'refs/imports/imports/' in the new project.

Explain in the documentation that refs are fetched into the
'refs/imports/' namespace and that the complete import command deletes
them.

Change-Id: I7ebce7dc7631de9e2356605d0f6e97fda1a4c367
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImport.java b/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImport.java
index ee21a91..1f116ee 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImport.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImport.java
@@ -26,17 +26,23 @@
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.account.CapabilityControl;
 import com.google.gerrit.server.config.ConfigResource;
+import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.project.ProjectResource;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
 import com.googlesource.gerrit.plugins.importer.CompleteProjectImport.Input;
 
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.internal.storage.file.LockFile;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.util.FS;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Map;
 
 @RequiresCapability(ImportCapability.ID)
 class CompleteProjectImport implements RestModifyView<ImportProjectResource, Input> {
@@ -44,16 +50,23 @@
   }
 
   private final ProjectsCollection projects;
+  private final GitRepositoryManager repoManager;
 
   @Inject
-  CompleteProjectImport(ProjectsCollection projects) {
+  CompleteProjectImport(
+      ProjectsCollection projects,
+      GitRepositoryManager repoManager) {
     this.projects = projects;
+    this.repoManager = repoManager;
   }
 
   @Override
-  public Response<?> apply(ImportProjectResource rsrc, Input input) throws ResourceConflictException {
+  public Response<?> apply(ImportProjectResource rsrc, Input input)
+      throws ResourceConflictException, RepositoryNotFoundException,
+      IOException {
     LockFile lock = lockForDelete(rsrc.getName());
     try {
+      deleteImportRefs(rsrc.getName());
       rsrc.getImportStatus().delete();
       return Response.none();
     } finally {
@@ -77,6 +90,32 @@
     }
   }
 
+  private void deleteImportRefs(Project.NameKey project)
+      throws RepositoryNotFoundException, IOException {
+    Repository repo = repoManager.openRepository(project);
+    try {
+      Map<String, Ref> refs = repo.getRefDatabase().getRefs(
+          ConfigureRepositoryStep.R_IMPORTS);
+      for (Ref ref : refs.values()) {
+        RefUpdate ru = repo.updateRef(ref.getName());
+        ru.setForceUpdate(true);
+        RefUpdate.Result result = ru.delete();
+        switch (result) {
+          case NEW:
+          case NO_CHANGE:
+          case FAST_FORWARD:
+          case FORCED:
+            break;
+          default:
+            throw new IOException(String.format(
+                "Failed to delete %s, RefUpdate.Result = %s", ref, result));
+        }
+      }
+    } finally {
+      repo.close();
+    }
+  }
+
   public static class OnProjects implements
       RestModifyView<ProjectResource, Input>, UiAction<ProjectResource> {
     private final ProjectsCollection projectsCollection;
@@ -97,7 +136,8 @@
 
     @Override
     public Response<?> apply(ProjectResource rsrc, Input input)
-        throws ResourceNotFoundException, ResourceConflictException {
+        throws ResourceNotFoundException, ResourceConflictException,
+        RepositoryNotFoundException, IOException {
       ImportProjectResource projectResource =
           projectsCollection.parse(new ConfigResource(),
               IdString.fromDecoded(rsrc.getName()));
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImportCommand.java b/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImportCommand.java
index 4a7ea73..02ff97f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImportCommand.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImportCommand.java
@@ -15,15 +15,16 @@
 package com.googlesource.gerrit.plugins.importer;
 
 import com.google.gerrit.extensions.annotations.RequiresCapability;
-import com.google.gerrit.extensions.restapi.ResourceConflictException;
-import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.sshd.CommandMetaData;
 import com.google.gerrit.sshd.SshCommand;
 import com.google.inject.Inject;
 
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.kohsuke.args4j.Argument;
 
+import java.io.IOException;
+
 @RequiresCapability(ImportCapability.ID)
 @CommandMetaData(name = "complete-project", description = "Completes project import")
 class CompleteProjectImportCommand extends SshCommand {
@@ -39,8 +40,8 @@
   private ProjectsCollection projects;
 
   @Override
-  protected void run() throws ResourceConflictException,
-      ResourceNotFoundException, UnloggedFailure {
+  protected void run() throws UnloggedFailure, RepositoryNotFoundException,
+      IOException {
     try {
       ImportProjectResource rsrc = projects.parse(project);
       completeProjectImport.apply(rsrc, new CompleteProjectImport.Input());
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
index 83b06b8..c2b2841 100644
--- a/src/main/resources/Documentation/about.md
+++ b/src/main/resources/Documentation/about.md
@@ -126,7 +126,9 @@
 A project import consists of the following steps:
 
 * creation of the Git repository and project in the target Gerrit server
-* fetch all refs from the source Gerrit server
+* fetch all refs from the source Gerrit server under the
+  'refs/imports/' namespace
+* create the refs for all branches and tags
 * [optional] reparent project in the target Gerrit server
 * replay all changes (changes in the target Gerrit server get new
   numeric ID's)
@@ -192,10 +194,11 @@
 <a id="complete-project-import">
 #### Complete Project Import
 
-Completing the project import deletes the [import file](#import-file)
-for that project. Afterwards it's not possible to resume the project
-import anymore. Also the project doesn't appear in the list of imported
-projects anymore.
+Completing the project import deletes all refs under the
+'refs/imports/' namespace. In addition the [import file](#import-file)
+for the project is deleted. Afterwards it's not possible to resume the
+project import anymore. Also the project doesn't appear in the list of
+imported projects anymore.
 
 <a id="project-copy">
 ### Project Copy