git-cl-comments: Support Gerrit file- and line-comments

This brings the gerrit version of "git cl comments" into line
with the Rietveld implementation by including file- and line-level
comments as well as top-level review comments. It requires an
extra API call to do so, so this may result in some slow-down, but
the result is worth it.

It formats the comments to match the formatting used in the
PolyGerrit UI, with the addition of visible URLs linking to
the comment since we can't hyperlink text in the terminal.

This CL also causes it to ignore messages and comments with
the 'autogenerated' tag, which are generally less interesting
and clutter the output.

Bug: 726514
Change-Id: I1fd939d90259b43886ddc209c0e727eab36cc9c9
Reviewed-on: https://chromium-review.googlesource.com/520722
Commit-Queue: Aaron Gable <agable@chromium.org>
Reviewed-by: Andrii Shyshkalov <tandrii@chromium.org>
diff --git a/tests/git_cl_test.py b/tests/git_cl_test.py
index cb7228e..b966c06 100755
--- a/tests/git_cl_test.py
+++ b/tests/git_cl_test.py
@@ -593,6 +593,9 @@
     self.mock(git_cl.gerrit_util, 'GetChangeDetail',
               lambda *args, **kwargs: self._mocked_call(
                   'GetChangeDetail', *args, **kwargs))
+    self.mock(git_cl.gerrit_util, 'GetChangeComments',
+              lambda *args, **kwargs: self._mocked_call(
+                  'GetChangeComments', *args, **kwargs))
     self.mock(git_cl.gerrit_util, 'AddReviewers',
               lambda h, i, reviewers, ccs, notify: self._mocked_call(
                   'AddReviewers', h, i, reviewers, ccs, notify))
@@ -3418,7 +3421,7 @@
        'https://chromium.googlesource.com/infra/infra'),
       (('GetChangeDetail', 'chromium-review.googlesource.com', '1',
         ['MESSAGES', 'DETAILED_ACCOUNTS']), {
-          'owner': {'email': 'owner@example.com'},
+        'owner': {'email': 'owner@example.com'},
         'messages': [
           {
              u'_revision_number': 1,
@@ -3455,19 +3458,48 @@
              u'message': u'Patch Set 2: Code-Review+1',
           },
         ]
-      })
+      }),
+      (('GetChangeComments', 'chromium-review.googlesource.com', 1), {
+        '/COMMIT_MSG': [
+          {
+            'author': {'email': u'reviewer@example.com'},
+            'updated': u'2017-03-17 05:19:37.500000000',
+            'patch_set': 2,
+            'side': 'REVISION',
+            'message': 'Please include a bug link',
+          },
+        ],
+        'codereview.settings': [
+          {
+            'author': {'email': u'owner@example.com'},
+            'updated': u'2017-03-16 20:00:41.000000000',
+            'patch_set': 2,
+            'side': 'PARENT',
+            'line': 42,
+            'message': 'I removed this because it is bad',
+          },
+        ]
+      }),
     ] * 2
     expected_comments_summary = [
       git_cl._CommentSummary(
-        message=u'Patch Set 1:\n\nDry run: CQ is trying da patch...',
-        date=datetime.datetime(2017, 3, 15, 20, 8, 45, 0),
-        disapproval=False, approval=False, sender=u'commit-bot@chromium.org'),
-      git_cl._CommentSummary(
-        message=u'PTAL',
+        message=(
+            u'PTAL\n' +
+            u'\n' +
+            u'codereview.settings\n' +
+            u'  Base, Line 42: https://chromium-review.googlesource.com/' +
+            u'c/1/2/codereview.settings#b42\n' +
+            u'  I removed this because it is bad\n'),
         date=datetime.datetime(2017, 3, 16, 20, 0, 41, 0),
         disapproval=False, approval=False, sender=u'owner@example.com'),
       git_cl._CommentSummary(
-        message=u'Patch Set 2: Code-Review+1',
+        message=(
+            u'Patch Set 2: Code-Review+1\n' +
+            u'\n' +
+            u'/COMMIT_MSG\n' +
+            u'  PS2, File comment: https://chromium-review.googlesource.com/' +
+            u'c/1/2//COMMIT_MSG#\n' +
+            u'  Please include a bug link\n'),
         date=datetime.datetime(2017, 3, 17, 5, 19, 37, 500000),
         disapproval=False, approval=False, sender=u'reviewer@example.com'),
     ]
@@ -3480,15 +3512,31 @@
                                        '-j', out_file]))
       with open(out_file) as f:
         read = json.load(f)
-      self.assertEqual(len(read), 3)
-      self.assertEqual(read[0]['date'], u'2017-03-15 20:08:45.000000')
-      self.assertEqual(read[1]['date'], u'2017-03-16 20:00:41.000000')
-      self.assertEqual(read[2], {
-          u'date': u'2017-03-17 05:19:37.500000',
-          u'message': u'Patch Set 2: Code-Review+1',
-          u'approval': False,
-          u'disapproval': False,
-          u'sender': u'reviewer@example.com'})
+      self.assertEqual(len(read), 2)
+      self.assertEqual(read[0], {
+        u'date': u'2017-03-16 20:00:41.000000',
+        u'message': (
+            u'PTAL\n' +
+            u'\n' +
+            u'codereview.settings\n' +
+            u'  Base, Line 42: https://chromium-review.googlesource.com/' +
+            u'c/1/2/codereview.settings#b42\n' +
+            u'  I removed this because it is bad\n'),
+        u'approval': False,
+        u'disapproval': False,
+        u'sender': u'owner@example.com'})
+      self.assertEqual(read[1], {
+        u'date': u'2017-03-17 05:19:37.500000',
+        u'message': (
+            u'Patch Set 2: Code-Review+1\n' +
+            u'\n' +
+            u'/COMMIT_MSG\n' +
+            u'  PS2, File comment: https://chromium-review.googlesource.com/' +
+            u'c/1/2//COMMIT_MSG#\n' +
+            u'  Please include a bug link\n'),
+        u'approval': False,
+        u'disapproval': False,
+        u'sender': u'reviewer@example.com'})
 
 
 if __name__ == '__main__':