[fix] only 500 changes are imported.

Via rest api the number of changes returned for a rest query for
changes is limited. The default limit is 500 changes.
Up to now we rely on that default, hence not all changes are imported.

Now we fetch all changes. The number of changes returned by the rest
call is counted. In case more changes are indicated we fetch another
bundle providing the appropriate offset of changes already imported.
This continues until all changes are imported.

Change-Id: I6a8fb85832e20d3f8e26f757b4163f6440b7ad1d
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/GerritApi.java b/src/main/java/com/googlesource/gerrit/plugins/importer/GerritApi.java
index 631acb7..f4d3bda 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/GerritApi.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/GerritApi.java
@@ -51,7 +51,7 @@
   public ProjectInfo getProject(String projectName) throws BadRequestException,
       IOException;
 
-  public List<ChangeInfo> queryChanges(String projectName)
+  public List<ChangeInfo> queryChanges(String projectName, int start, int limit)
       throws BadRequestException, IOException;
 
   public GroupInfo getGroup(String groupName) throws BadRequestException,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/LocalApi.java b/src/main/java/com/googlesource/gerrit/plugins/importer/LocalApi.java
index 5f8cff1..f214b74 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/LocalApi.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/LocalApi.java
@@ -15,6 +15,7 @@
 package com.googlesource.gerrit.plugins.importer;
 
 import com.google.common.collect.Iterables;
+import com.google.gerrit.extensions.api.changes.Changes.QueryRequest;
 import com.google.gerrit.extensions.client.ListChangesOption;
 import com.google.gerrit.extensions.common.ChangeInfo;
 import com.google.gerrit.extensions.common.CommentInfo;
@@ -91,19 +92,26 @@
   }
 
   @Override
-  public List<ChangeInfo> queryChanges(String projectName) throws IOException,
+  public List<ChangeInfo> queryChanges(String projectName, int start,
+      int limit) throws IOException,
       BadRequestException {
     try {
-      return gApi.changes()
-          .query("project:" + projectName)
+
+      QueryRequest query = gApi.changes()
+          .query("project:" + projectName);
+      query
+          .withStart(start)
           .withOptions(
               ListChangesOption.DETAILED_LABELS,
               ListChangesOption.DETAILED_ACCOUNTS,
               ListChangesOption.MESSAGES,
               ListChangesOption.CURRENT_REVISION,
               ListChangesOption.ALL_REVISIONS,
-              ListChangesOption.ALL_COMMITS)
-          .get();
+              ListChangesOption.ALL_COMMITS);
+      if(limit > 0) {
+        query.withLimit(limit);
+      }
+      return query.get();
     } catch (RestApiException e) {
       throw new BadRequestException(e.getMessage());
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/RemoteApi.java b/src/main/java/com/googlesource/gerrit/plugins/importer/RemoteApi.java
index fa746c5..05e757e 100755
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/RemoteApi.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/RemoteApi.java
@@ -57,10 +57,11 @@
   }
 
   @Override
-  public List<ChangeInfo> queryChanges(String projectName) throws IOException,
-      BadRequestException {
+  public List<ChangeInfo> queryChanges(String projectName,
+      int start, int limit) throws IOException, BadRequestException {
     String endPoint =
-        "/changes/?q=project:" + projectName +
+        "/changes/?S=" +
+        start + ((limit > 0) ? "&n=" + limit : "") + "&q=project:" + projectName +
         "&O=" + Integer.toHexString(ListChangesOption.toBits(
             EnumSet.of(
                 ListChangesOption.DETAILED_LABELS,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayChangesStep.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayChangesStep.java
index 603b034..8971baf 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayChangesStep.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayChangesStep.java
@@ -16,6 +16,7 @@
 
 import com.google.common.collect.Iterators;
 import com.google.gerrit.common.Nullable;
+import com.google.gerrit.common.data.GlobalCapability;
 import com.google.gerrit.common.errors.NoSuchAccountException;
 import com.google.gerrit.extensions.client.ChangeStatus;
 import com.google.gerrit.extensions.common.ChangeInfo;
@@ -129,23 +130,36 @@
   void replay() throws IOException, OrmException,
       NoSuchAccountException, NoSuchChangeException, RestApiException,
       ValidationException {
-    List<ChangeInfo> changes = api.queryChanges(srcProject.get());
-
-    pm.beginTask("Replay Changes", changes.size());
-    RevWalk rw = new RevWalk(repo);
-    try {
-      for (ChangeInfo c : changes) {
-        try {
-          replayChange(rw, c);
-        } catch (Exception e) {
-          log.error(String.format("Failed to replay change %s.",
-              Url.decode(c.id)), e);
-          throw e;
-        }
-        pm.update(1);
+    int start = 0;
+    int limit = GlobalCapability.DEFAULT_MAX_QUERY_LIMIT;
+    pm.beginTask("Replay Changes", ProgressMonitor.UNKNOWN);
+    for(;;) {
+      List<ChangeInfo> changes = api.queryChanges(srcProject.get(),
+          start, limit);
+      if(changes.isEmpty()) {
+        break;
       }
-    } finally {
-      rw.close();
+      start += changes.size();
+      RevWalk rw = new RevWalk(repo);
+      try {
+        ChangeInfo last = null;
+        for (ChangeInfo c : changes) {
+          try {
+            replayChange(rw, c);
+          } catch (Exception e) {
+            log.error(String.format("Failed to replay change %s.",
+                Url.decode(c.id)), e);
+            throw e;
+          }
+          last = c;
+          pm.update(1);
+        }
+        if(!Boolean.TRUE.equals(last._moreChanges)) {
+          break;
+        }
+      } finally {
+        rw.close();
+      }
     }
     pm.endTask();
   }