git cl comment: refactor fetching comments for Rietveld and add tests.

R=agable@chromium.org,machenbach@chromium.org
BUG=698236

Change-Id: I04e264130952e3e270540fae8381db544cf40e7c
Reviewed-on: https://chromium-review.googlesource.com/456697
Commit-Queue: Andrii Shyshkalov <tandrii@chromium.org>
Reviewed-by: Michael Achenbach <machenbach@chromium.org>
diff --git a/git_cl.py b/git_cl.py
index dd11ccd..1a67a45 100755
--- a/git_cl.py
+++ b/git_cl.py
@@ -14,6 +14,7 @@
 import base64
 import collections
 import contextlib
+import datetime
 import fnmatch
 import httplib
 import itertools
@@ -1090,6 +1091,12 @@
         self.issue, self.url)
 
 
+_CommentSummary = collections.namedtuple(
+    '_CommentSummary', ['date', 'message', 'sender',
+                        # TODO(tandrii): these two aren't known in Gerrit.
+                        'approval', 'disapproval'])
+
+
 class Changelist(object):
   """Changelist works with one changelist in local branch.
 
@@ -1657,6 +1664,14 @@
   def AddComment(self, message):
     return self._codereview_impl.AddComment(message)
 
+  def GetCommentsSummary(self):
+    """Returns list of _CommentSummary for each comment.
+
+    Note: comments per file or per line are not included,
+    only top-level comments are returned.
+    """
+    return self._codereview_impl.GetCommentsSummary()
+
   def CloseIssue(self):
     return self._codereview_impl.CloseIssue()
 
@@ -1759,6 +1774,9 @@
     """Posts a comment to the codereview site."""
     raise NotImplementedError()
 
+  def GetCommentsSummary(self):
+    raise NotImplementedError()
+
   def CloseIssue(self):
     """Closes the issue."""
     raise NotImplementedError()
@@ -1934,6 +1952,19 @@
   def AddComment(self, message):
     return self.RpcServer().add_comment(self.GetIssue(), message)
 
+  def GetCommentsSummary(self):
+    summary = []
+    for message in self.GetIssueProperties().get('messages', []):
+      date = datetime.datetime.strptime(message['date'], '%Y-%m-%d %H:%M:%S.%f')
+      summary.append(_CommentSummary(
+        date=date,
+        disapproval=bool(message['disapproval']),
+        approval=bool(message['approval']),
+        sender=message['sender'],
+        message=message['text'],
+      ))
+    return summary
+
   def GetStatus(self):
     """Apply a rough heuristic to give a simple summary of an issue's review
     or CQ status, assuming adherence to a common workflow.
@@ -2499,6 +2530,10 @@
     gerrit_util.SetReview(self._GetGerritHost(), self.GetIssue(),
                           msg=message)
 
+  def GetCommentsSummary(self):
+    # TODO(tandrii): implement in follow up CL (http://crbug.com/698236).
+    raise NotImplementedError()
+
   def CloseIssue(self):
     gerrit_util.AbandonChange(self._GetGerritHost(), self.GetIssue(), msg='')
 
@@ -4234,34 +4269,30 @@
     cl.AddComment(options.comment)
     return 0
 
-  data = cl.GetIssueProperties()
-  summary = []
-  for message in sorted(data.get('messages', []), key=lambda x: x['date']):
-    summary.append({
-        'date': message['date'],
-        'lgtm': False,
-        'message': message['text'],
-        'not_lgtm': False,
-        'sender': message['sender'],
-    })
-    if message['disapproval']:
+  summary = sorted(cl.GetCommentsSummary(), key=lambda c: c.date)
+  for comment in summary:
+    if comment.disapproval:
       color = Fore.RED
-      summary[-1]['not lgtm'] = True
-    elif message['approval']:
+    elif comment.approval:
       color = Fore.GREEN
-      summary[-1]['lgtm'] = True
-    elif message['sender'] == data['owner_email']:
+    elif comment.sender == cl.GetIssueOwner():
       color = Fore.MAGENTA
     else:
       color = Fore.BLUE
-    print('\n%s%s  %s%s' % (
-        color, message['date'].split('.', 1)[0], message['sender'],
-        Fore.RESET))
-    if message['text'].strip():
-      print('\n'.join('  ' + l for l in message['text'].splitlines()))
+    print('\n%s%s   %s%s\n%s' % (
+      color,
+      comment.date.strftime('%Y-%m-%d %H:%M:%S UTC'),
+      comment.sender,
+      Fore.RESET,
+      '\n'.join('  ' + l for l in comment.message.strip().splitlines())))
+
   if options.json_file:
+    def pre_serialize(c):
+      dct = c.__dict__.copy()
+      dct['date'] = dct['date'].strftime('%Y-%m-%d %H:%M:%S.%f')
+      return dct
     with open(options.json_file, 'wb') as f:
-      json.dump(summary, f)
+      json.dump(map(pre_serialize, summary), f)
   return 0