Add [automerger] prefix to all automerger-created CLs.

This makes it much easier to query for automerger-created CLs.

Change-Id: I7200c261f6c061b9549dead8288d9f477d80e12a
diff --git a/src/main/java/com/googlesource/gerrit/plugins/automerger/DownstreamCreator.java b/src/main/java/com/googlesource/gerrit/plugins/automerger/DownstreamCreator.java
index 2045762..db3729a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/automerger/DownstreamCreator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/automerger/DownstreamCreator.java
@@ -69,6 +69,7 @@
   private static final Logger log = LoggerFactory.getLogger(DownstreamCreator.class);
   private static final String AUTOMERGER_TAG = "autogenerated:Automerger";
   private static final String MERGE_CONFLICT_TAG = "autogenerated:MergeConflict";
+  private static final String SUBJECT_PREFIX = "[automerger]";
 
   protected GerritApi gApi;
   protected ConfigLoader config;
@@ -410,7 +411,7 @@
     downstreamChangeInput.project = sdsMergeInput.project;
     downstreamChangeInput.branch = sdsMergeInput.downstreamBranch;
     downstreamChangeInput.subject =
-        sdsMergeInput.subject + " am: " + sdsMergeInput.currentRevision.substring(0, 10);
+        getSubjectForDownstreamMerge(sdsMergeInput.subject, sdsMergeInput.currentRevision, false);
     downstreamChangeInput.topic = currentTopic;
     downstreamChangeInput.merge = mergeInput;
     downstreamChangeInput.notify = NotifyHandling.NONE;
@@ -423,7 +424,7 @@
     if (!sdsMergeInput.doMerge) {
       mergeInput.strategy = "ours";
       downstreamChangeInput.subject =
-          sdsMergeInput.subject + " skipped: " + sdsMergeInput.currentRevision.substring(0, 10);
+          getSubjectForDownstreamMerge(sdsMergeInput.subject, sdsMergeInput.currentRevision, true);
       log.debug(
           "Skipping merge for {} to {}",
           sdsMergeInput.currentRevision,
@@ -565,11 +566,13 @@
     mergeInput.source = newParentRevision;
 
     MergePatchSetInput mergePatchSetInput = new MergePatchSetInput();
-    mergePatchSetInput.subject = upstreamSubject + " am: " + newParentRevision.substring(0, 10);
+
+    mergePatchSetInput.subject =
+        getSubjectForDownstreamMerge(upstreamSubject, newParentRevision, false);
     if (!doMerge) {
       mergeInput.strategy = "ours";
       mergePatchSetInput.subject =
-          upstreamSubject + " skipped: " + newParentRevision.substring(0, 10);
+          getSubjectForDownstreamMerge(upstreamSubject, newParentRevision, true);
       log.debug("Skipping merge for {} on {}", newParentRevision, sourceNum);
     }
     mergePatchSetInput.merge = mergeInput;
@@ -677,4 +680,26 @@
     }
     return false;
   }
+
+  /**
+   * Create subject line for downstream merge with metadata from upstream change.
+   *
+   * <p>The downstream subject will be in the format: "[automerger] upstreamSubject am:
+   * upstreamRevision". If it is a skip, "am" will be replaced with "skipped". [automerger] will not
+   * be repeated for changes with multiple downstreams.
+   *
+   * @param upstreamSubject Subject line of the upstream change
+   * @param upstreamRevision Commit SHA1 of the upstream change
+   * @param skipped Whether or not the merge is done with "-s ours"
+   * @return Subject line for downstream merge
+   */
+  private String getSubjectForDownstreamMerge(
+      String upstreamSubject, String upstreamRevision, boolean skipped) {
+    if (!upstreamSubject.startsWith(SUBJECT_PREFIX)) {
+      upstreamSubject = Joiner.on(" ").join(SUBJECT_PREFIX, upstreamSubject);
+    }
+    String denotationString = skipped ? "skipped:" : "am:";
+    return Joiner.on(" ")
+        .join(upstreamSubject, denotationString, upstreamRevision.substring(0, 10));
+  }
 }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/automerger/DownstreamCreatorIT.java b/src/test/java/com/googlesource/gerrit/plugins/automerger/DownstreamCreatorIT.java
index 38f8d08..b680585 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/automerger/DownstreamCreatorIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/automerger/DownstreamCreatorIT.java
@@ -68,7 +68,10 @@
     result.assertOkStatus();
     // Check that there are the correct number of changes in the topic
     List<ChangeInfo> changesInTopic =
-        gApi.changes().query("topic: " + gApi.changes().id(result.getChangeId()).topic()).get();
+        gApi.changes()
+            .query("topic: " + gApi.changes().id(result.getChangeId()).topic())
+            .withOption(ListChangesOption.CURRENT_REVISION)
+            .get();
     assertThat(changesInTopic).hasSize(3);
     // +2 and submit
     merge(result);
@@ -91,6 +94,15 @@
     assertThat(getVote(masterChange, "Code-Review").value).isEqualTo(2);
     assertThat(getVote(masterChange, "Code-Review").tag).isEqualTo(null);
     assertThat(masterChangeInfo.branch).isEqualTo("master");
+
+    // Ensure that commit subjects are correct
+    String masterSubject = masterChangeInfo.subject;
+    String shortMasterSha = masterChangeInfo.currentRevision.substring(0, 10);
+    assertThat(masterChangeInfo.subject).doesNotContainMatch("automerger");
+    assertThat(dsOneChangeInfo.subject)
+        .isEqualTo("[automerger] " + masterSubject + " am: " + shortMasterSha);
+    assertThat(dsTwoChangeInfo.subject)
+        .isEqualTo("[automerger] " + masterSubject + " am: " + shortMasterSha);
   }
 
   @Test
@@ -125,7 +137,10 @@
     result.assertOkStatus();
     // Check that there are the correct number of changes in the topic
     List<ChangeInfo> changesInTopic =
-        gApi.changes().query("topic: " + gApi.changes().id(result.getChangeId()).topic()).get();
+        gApi.changes()
+            .query("topic: " + gApi.changes().id(result.getChangeId()).topic())
+            .withOption(ListChangesOption.CURRENT_REVISION)
+            .get();
     assertThat(changesInTopic).hasSize(5);
     // +2 and submit
     merge(result);
@@ -161,6 +176,23 @@
     ChangeApi rightChange = gApi.changes().id(rightChangeInfo._number);
     assertThat(getVote(rightChange, "Code-Review").value).isEqualTo(2);
     assertThat(getVote(rightChange, "Code-Review").tag).isEqualTo("autogenerated:Automerger");
+
+    // Ensure that commit subjects are correct
+    String masterSubject = masterChangeInfo.subject;
+    String shortMasterSha = masterChangeInfo.currentRevision.substring(0, 10);
+    String shortLeftSha = leftChangeInfo.currentRevision.substring(0, 10);
+    String shortRightSha = rightChangeInfo.currentRevision.substring(0, 10);
+    assertThat(masterChangeInfo.subject).doesNotContainMatch("automerger");
+    assertThat(leftChangeInfo.subject)
+        .isEqualTo("[automerger] " + masterSubject + " am: " + shortMasterSha);
+    assertThat(rightChangeInfo.subject)
+        .isEqualTo("[automerger] " + masterSubject + " am: " + shortMasterSha);
+    assertThat(bottomChangeInfoA.subject)
+        .isEqualTo(
+            "[automerger] " + masterSubject + " am: " + shortMasterSha + " am: " + shortLeftSha);
+    assertThat(bottomChangeInfoB.subject)
+        .isEqualTo(
+            "[automerger] " + masterSubject + " am: " + shortMasterSha + " am: " + shortRightSha);
   }
 
   @Test
@@ -191,7 +223,10 @@
     result.assertOkStatus();
 
     List<ChangeInfo> changesInTopic =
-        gApi.changes().query("topic: " + gApi.changes().id(result.getChangeId()).topic()).get();
+        gApi.changes()
+            .query("topic: " + gApi.changes().id(result.getChangeId()).topic())
+            .withOption(ListChangesOption.CURRENT_REVISION)
+            .get();
     assertThat(changesInTopic).hasSize(4);
     // +2 and submit
     merge(result);
@@ -221,6 +256,19 @@
     ChangeApi rightChange = gApi.changes().id(rightChangeInfo._number);
     assertThat(getVote(rightChange, "Code-Review").value).isEqualTo(2);
     assertThat(getVote(rightChange, "Code-Review").tag).isEqualTo("autogenerated:Automerger");
+
+    // Ensure that commit subjects are correct
+    String masterSubject = masterChangeInfo.subject;
+    String shortMasterSha = masterChangeInfo.currentRevision.substring(0, 10);
+    String shortLeftSha = leftChangeInfo.currentRevision.substring(0, 10);
+    assertThat(masterChangeInfo.subject).doesNotContainMatch("automerger");
+    assertThat(leftChangeInfo.subject)
+        .isEqualTo("[automerger] " + masterSubject + " am: " + shortMasterSha);
+    assertThat(rightChangeInfo.subject)
+        .isEqualTo("[automerger] " + masterSubject + " am: " + shortMasterSha);
+    assertThat(bottomChangeInfo.subject)
+        .isEqualTo(
+            "[automerger] " + masterSubject + " am: " + shortMasterSha + " am: " + shortLeftSha);
   }
 
   @Test
@@ -296,6 +344,12 @@
             .commit;
     // Check that first parent of B'' is A''
     assertThat(masterChangeInfo.currentRevision).isEqualTo(masterChangeInfo2FirstParentSha);
+
+    // Ensure that commit subjects are correct
+    String shortMasterSha = masterChangeInfo.currentRevision.substring(0, 10);
+    assertThat(masterChangeInfo.subject).doesNotContainMatch("automerger");
+    assertThat(dsOneChangeInfo.subject).isEqualTo("[automerger] test commit am: " + shortMasterSha);
+    assertThat(dsTwoChangeInfo.subject).isEqualTo("[automerger] test commit am: " + shortMasterSha);
   }
 
   @Test
@@ -316,7 +370,8 @@
     ChangeApi change = gApi.changes().id(result.getChangeId());
     BinaryResult content = change.current().file("filename").content();
 
-    List<ChangeInfo> changesInTopic = gApi.changes().query("topic: " + change.topic()).get();
+    List<ChangeInfo> changesInTopic = gApi.changes().query("topic: " + change.topic())
+        .withOption(ListChangesOption.CURRENT_REVISION).get();
     assertThat(changesInTopic).hasSize(3);
 
     List<ChangeInfo> sortedChanges = sortedChanges(changesInTopic);
@@ -346,6 +401,15 @@
     assertThat(getVote(masterChange, "Code-Review").value).isEqualTo(0);
     assertThat(getVote(masterChange, "Code-Review").tag).isEqualTo(null);
     assertThat(masterChangeInfo.branch).isEqualTo("master");
+
+    // Ensure that commit subjects are correct
+    String masterSubject = masterChangeInfo.subject;
+    String shortMasterSha = masterChangeInfo.currentRevision.substring(0, 10);
+    assertThat(masterChangeInfo.subject).doesNotContainMatch("automerger");
+    assertThat(dsOneChangeInfo.subject)
+        .isEqualTo("[automerger] " + masterSubject + " skipped: " + shortMasterSha);
+    assertThat(dsTwoChangeInfo.subject)
+        .isEqualTo("[automerger] " + masterSubject + " am: " + shortMasterSha);
   }
 
   @Test
@@ -364,7 +428,8 @@
     result.assertOkStatus();
 
     ChangeApi change = gApi.changes().id(result.getChangeId());
-    List<ChangeInfo> changesInTopic = gApi.changes().query("topic: " + change.topic()).get();
+    List<ChangeInfo> changesInTopic = gApi.changes().query("topic: " + change.topic())
+        .withOption(ListChangesOption.CURRENT_REVISION).get();
     assertThat(changesInTopic).hasSize(3);
 
     List<ChangeInfo> sortedChanges = sortedChanges(changesInTopic);
@@ -394,6 +459,15 @@
     assertThat(getVote(masterChange, "Code-Review").value).isEqualTo(0);
     assertThat(getVote(masterChange, "Code-Review").tag).isEqualTo(null);
     assertThat(masterChangeInfo.branch).isEqualTo("master");
+
+    // Ensure that commit subjects are correct
+    String masterSubject = masterChangeInfo.subject;
+    String shortMasterSha = masterChangeInfo.currentRevision.substring(0, 10);
+    assertThat(masterChangeInfo.subject).doesNotContainMatch("automerger");
+    assertThat(dsOneChangeInfo.subject)
+        .isEqualTo("[automerger] " + masterSubject + " skipped: " + shortMasterSha);
+    assertThat(dsTwoChangeInfo.subject)
+        .isEqualTo("[automerger] " + masterSubject + " skipped: " + shortMasterSha);
   }
 
   @Test
@@ -430,6 +504,7 @@
     List<ChangeInfo> changesInTopic =
         gApi.changes()
             .query("topic: " + gApi.changes().id(masterResult.getChangeId()).topic())
+            .withOption(ListChangesOption.CURRENT_REVISION)
             .get();
     assertThat(changesInTopic).hasSize(2);
     List<ChangeInfo> sortedChanges = sortedChanges(changesInTopic);
@@ -446,6 +521,13 @@
     assertThat(getVote(masterChange, "Code-Review").value).isEqualTo(-2);
     assertThat(getVote(masterChange, "Code-Review").tag).isEqualTo("autogenerated:MergeConflict");
     assertThat(masterChangeInfo.branch).isEqualTo("master");
+
+    // Ensure that commit subjects are correct
+    String masterSubject = masterChangeInfo.subject;
+    String shortMasterSha = masterChangeInfo.currentRevision.substring(0, 10);
+    assertThat(masterChangeInfo.subject).doesNotContainMatch("automerger");
+    assertThat(dsTwoChangeInfo.subject)
+        .isEqualTo("[automerger] " + masterSubject + " am: " + shortMasterSha);
   }
 
   @Test