ChangeNotes: add past assignees

To enable finding all users that have been assigned to a change.

Change-Id: Idc2929b198ecb5800a4d32e06d096f586b6460ad
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java
index ae9bb96..19df9eb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java
@@ -395,8 +395,16 @@
   }
 
   /**
-   *
-   * @return a ImmutableSet of all hashtags for this change sorted in alphabetical order.
+   * @return an ImmutableSet of Account.Ids of all users that have been assigned
+   *         to this change.
+   */
+  public ImmutableSet<Account.Id> getPastAssignees() {
+    return state.pastAssignees();
+  }
+
+  /**
+   * @return a ImmutableSet of all hashtags for this change sorted in
+   *         alphabetical order.
    */
   public ImmutableSet<String> getHashtags() {
     return ImmutableSortedSet.copyOf(state.hashtags());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesParser.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
index 89d7e8a..5ca8884 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
@@ -138,6 +138,7 @@
   private Change.Status status;
   private String topic;
   private Optional<Account.Id> assignee;
+  private List<Account.Id> pastAssignees;
   private Set<String> hashtags;
   private Timestamp createdOn;
   private Timestamp lastUpdatedOn;
@@ -186,6 +187,7 @@
       parseNotes();
       allPastReviewers.addAll(reviewers.rowKeySet());
       pruneReviewers();
+
       updatePatchSetStates();
       checkMandatoryFooters();
     }
@@ -213,6 +215,7 @@
         status,
 
         assignee != null ? assignee.orNull() : null,
+        Sets.newLinkedHashSet(Lists.reverse(pastAssignees)),
         hashtags,
         patchSets,
         buildApprovals(),
@@ -480,18 +483,25 @@
 
   private void parseAssignee(ChangeNotesCommit commit)
       throws ConfigInvalidException {
-    if (assignee != null) {
-      return;
+    if (pastAssignees == null) {
+      pastAssignees = Lists.newArrayList();
     }
     String assigneeValue = parseOneFooter(commit, FOOTER_ASSIGNEE);
-    if (assigneeValue == null){
-      //footer not found
-    } else if (assigneeValue.equals("")) {
-      // empty footer found, assignee deleted
-      assignee = Optional.absent();
-    } else {
-      PersonIdent ident = RawParseUtils.parsePersonIdent(assigneeValue);
-      assignee = Optional.fromNullable(noteUtil.parseIdent(ident, id));
+    if (assigneeValue != null) {
+      Optional<Account.Id> parsedAssignee;
+      if (assigneeValue.equals("")) {
+        // Empty footer found, assignee deleted
+        parsedAssignee = Optional.absent();
+      } else {
+        PersonIdent ident = RawParseUtils.parsePersonIdent(assigneeValue);
+        parsedAssignee = Optional.fromNullable(noteUtil.parseIdent(ident, id));
+      }
+      if (assignee == null) {
+        assignee = parsedAssignee;
+      }
+      if (parsedAssignee.isPresent()) {
+        pastAssignees.add(parsedAssignee.get());
+      }
     }
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesState.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesState.java
index 797c9b5..b179dd1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesState.java
@@ -60,6 +60,7 @@
         change.getId(),
         null,
         null,
+        ImmutableSet.<Account.Id>of(),
         ImmutableSet.<String>of(),
         ImmutableSortedMap.<PatchSet.Id, PatchSet>of(),
         ImmutableListMultimap.<PatchSet.Id, PatchSetApproval>of(),
@@ -86,6 +87,7 @@
       @Nullable String submissionId,
       @Nullable Change.Status status,
       @Nullable Account.Id assignee,
+      @Nullable Set<Account.Id> pastAssignees,
       @Nullable Set<String> hashtags,
       Map<PatchSet.Id, PatchSet> patchSets,
       Multimap<PatchSet.Id, PatchSetApproval> approvals,
@@ -114,6 +116,7 @@
             submissionId,
             status),
         assignee,
+        ImmutableSet.copyOf(pastAssignees),
         ImmutableSet.copyOf(hashtags),
         ImmutableSortedMap.copyOf(patchSets, comparing(PatchSet.Id::get)),
         ImmutableListMultimap.copyOf(approvals),
@@ -157,6 +160,7 @@
 
   // Other related to this Change.
   @Nullable abstract Account.Id assignee();
+  abstract ImmutableSet<Account.Id> pastAssignees();
   abstract ImmutableSet<String> hashtags();
   abstract ImmutableSortedMap<PatchSet.Id, PatchSet> patchSets();
   abstract ImmutableListMultimap<PatchSet.Id, PatchSetApproval> approvals();
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java
index 62a682e..7127766 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java
@@ -600,7 +600,31 @@
 
     notes = newNotes(c);
     assertThat(notes.getAssignee().get()).isEqualTo(changeOwner.getAccountId());
+  }
 
+  @Test
+  public void pastAssigneesChangeNotes() throws Exception {
+    Change c = newChange();
+    ChangeUpdate update = newUpdate(c, changeOwner);
+    update.setAssignee(Optional.fromNullable(otherUserId));
+    update.commit();
+
+    ChangeNotes notes = newNotes(c);
+
+    update = newUpdate(c, changeOwner);
+    update.setAssignee(Optional.fromNullable(changeOwner.getAccountId()));
+    update.commit();
+
+    update = newUpdate(c, changeOwner);
+    update.setAssignee(Optional.fromNullable(otherUserId));
+    update.commit();
+
+    update = newUpdate(c, changeOwner);
+    update.setAssignee(Optional.absent());
+    update.commit();
+
+    notes = newNotes(c);
+    assertThat(notes.getPastAssignees()).hasSize(2);
   }
 
   @Test