Make it possible to re-create missing SourceChange events

This change add the flag fillGaps for the createSccs and createScss
endpoints. With this flag you can re-create missing events. Traversing
from the root of the commit tree every missing event is re-created
until the specified commit or tip of the specified branch is reached.

Solves: Jira GER-1545
Change-Id: I2c3d5067c0e080b04c8890ceff18b4f6534ec274
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/CreateSccs.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/CreateSccs.java
index eee7d68..92f8af0 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/CreateSccs.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/CreateSccs.java
@@ -34,7 +34,9 @@
 @Singleton
 @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
 public class CreateSccs implements RestModifyView<BranchResource, CreateSccs.Input> {
-  static class Input {}
+  static class Input {
+    boolean fillGaps;
+  }
 
   private final EiffelEventParsingQueue queue;
   private final Provider<InternalChangeQuery> queryProvider;
@@ -49,7 +51,11 @@
   public Response<?> apply(BranchResource resource, CreateSccs.Input input)
       throws AuthException, BadRequestException, ResourceConflictException, Exception {
     if (resource.getRef().startsWith(RefNames.REFS_HEADS)) {
-      queue.scheduleSccCreation(resource.getName(), resource.getRef());
+      if (input.fillGaps) {
+        queue.scheduleMissingSccCreation(resource.getName(), resource.getRef());
+      } else {
+        queue.scheduleSccCreation(resource.getName(), resource.getRef());
+      }
       return EventCreationResponse.scc(resource);
     }
     PatchSet.Id maybePatchSet = PatchSet.Id.fromRef(resource.getRef());
@@ -60,8 +66,13 @@
               .findFirst()
               .map(c -> c.change().getDest().branch());
       if (targetBranch.isPresent()) {
-        queue.scheduleSccCreation(
-            resource.getName(), targetBranch.get(), resource.getRevision().get());
+        if (input.fillGaps) {
+          queue.scheduleMissingSccCreation(
+              resource.getName(), targetBranch.get(), resource.getRevision().get());
+        } else {
+          queue.scheduleSccCreation(
+              resource.getName(), targetBranch.get(), resource.getRevision().get());
+        }
         return EventCreationResponse.scc(resource, targetBranch.get());
       }
       throw new BadRequestException(
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/CreateScss.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/CreateScss.java
index 53a966f..69c2c1e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/CreateScss.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/CreateScss.java
@@ -30,7 +30,9 @@
 @Singleton
 @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
 public class CreateScss implements RestModifyView<BranchResource, CreateScss.Input> {
-  static class Input {}
+  static class Input {
+    boolean fillGaps;
+  }
 
   private final EiffelEventParsingQueue queue;
 
@@ -43,7 +45,11 @@
   public Response<?> apply(BranchResource resource, CreateScss.Input input)
       throws AuthException, BadRequestException, ResourceConflictException, Exception {
     if (resource.getRef().startsWith(RefNames.REFS_HEADS)) {
-      queue.scheduleScsCreation(resource.getName(), resource.getRef());
+      if (input.fillGaps) {
+        queue.scheduleMissingScsCreation(resource.getName(), resource.getRef());
+      } else {
+        queue.scheduleScsCreation(resource.getName(), resource.getRef());
+      }
       return EventCreationResponse.scs(resource);
     }
     throw new BadRequestException("SCS event creation are only allowed from branches.");
diff --git a/src/main/resources/Documentation/rest-api-events-eiffel-scc-post.md b/src/main/resources/Documentation/rest-api-events-eiffel-scc-post.md
index 3ab1631..054f06e 100644
--- a/src/main/resources/Documentation/rest-api-events-eiffel-scc-post.md
+++ b/src/main/resources/Documentation/rest-api-events-eiffel-scc-post.md
@@ -65,6 +65,34 @@
   }
 ```
 
+#### Re-create missing SCC events for commits reachable from master of project my/project: ####
+```
+  curl -X POST --user janeadmin:secret \
+    -H "content-type:application/json" \
+    http://host:port/a/projects/my%2Fproject/branches/master/@PLUGIN@~createSccs \
+    -d '{"fill_gaps":true}'
+```
+
+__Response:__
+
+```
+  )]}'
+  {
+   "types": [
+     "EiffelSourceChangeCreatedEvent"
+   ],
+   "repo_name": "my/project",
+   "ref": "refs/heads/master",
+   "status": "Event creation scheduled",
+   "branch": "refs/heads/master"
+  }
+```
+
+### Request object ###
+fill_gaps
+: Decide if you should do a backfill or re-create missing events. If this is true you re-create
+missing events.
+
 ### Response object ###
 types
 : The types of events that will be created.
diff --git a/src/main/resources/Documentation/rest-api-events-eiffel-scs-post.md b/src/main/resources/Documentation/rest-api-events-eiffel-scs-post.md
index 6b99eb5..299efca 100644
--- a/src/main/resources/Documentation/rest-api-events-eiffel-scs-post.md
+++ b/src/main/resources/Documentation/rest-api-events-eiffel-scs-post.md
@@ -36,7 +36,7 @@
   {
    "types": [
      "EiffelSourceChangeCreatedEvent",
-     "EiffelSourceChangeSubmittedEvent",
+     "EiffelSourceChangeSubmittedEvent"
    ],
    "repo_name": "my/project",
    "ref": "refs/heads/master",
@@ -45,6 +45,35 @@
   }
 ```
 
+#### Re-create missing SCS events for commits reachable from master of project my/project: ####
+```
+  curl -X POST --user janeadmin:secret \
+    -H "content-type:application/json" \
+    http://host:port/a/projects/my%2Fproject/branches/master/@PLUGIN@~createSccs \
+    -d '{"fill_gaps":true}'
+```
+
+__Response:__
+
+```
+  )]}'
+  {
+   "types": [
+     "EiffelSourceChangeCreatedEvent",
+     "EiffelSourceChangeSubmittedEvent"
+   ],
+   "repo_name": "my/project",
+   "ref": "refs/heads/master",
+   "status": "Event creation scheduled",
+   "branch": "refs/heads/master"
+  }
+```
+
+### Request object ###
+fill_gaps
+: Decide if you should do a backfill or re-create missing events. If this is true you re-create
+missing events.
+
 ### Response object ###
 types
 : The types of events that will be created.