| 
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -14,6 +14,7 @@ from multiprocessing.pool import ThreadPool
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import base64
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import collections
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import contextlib
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import datetime
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import fnmatch
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import httplib
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import itertools
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -1090,6 +1091,12 @@ class GerritChangeNotExists(Exception):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        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 @@ class Changelist(object):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  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 @@ class _ChangelistCodereviewBase(object):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    """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 @@ class _RietveldChangelistImpl(_ChangelistCodereviewBase):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  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 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    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 @@ def CMDcomments(parser, args):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    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
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
			
			 | 
			 | 
			
				
 
 |