Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Get stats about your activity. | 6 """Get stats about your activity. |
| 7 | 7 |
| 8 Example: | 8 Example: |
| 9 - my_activity.py for stats for the current week (last week on mondays). | 9 - my_activity.py for stats for the current week (last week on mondays). |
| 10 - my_activity.py -Q for stats for last quarter. | 10 - my_activity.py -Q for stats for last quarter. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 28 from functools import partial | 28 from functools import partial |
| 29 import json | 29 import json |
| 30 import optparse | 30 import optparse |
| 31 import os | 31 import os |
| 32 import re | 32 import re |
| 33 import subprocess | 33 import subprocess |
| 34 import sys | 34 import sys |
| 35 import urllib | 35 import urllib |
| 36 import urllib2 | 36 import urllib2 |
| 37 | 37 |
| 38 import gerrit_util | |
| 38 import rietveld | 39 import rietveld |
| 39 from third_party import upload | 40 from third_party import upload |
| 40 | 41 |
| 41 # Imported later, once options are set. | 42 # Imported later, once options are set. |
| 42 webkitpy = None | 43 webkitpy = None |
| 43 | 44 |
| 44 try: | 45 try: |
| 45 from dateutil.relativedelta import relativedelta # pylint: disable=F0401 | 46 from dateutil.relativedelta import relativedelta # pylint: disable=F0401 |
| 46 except ImportError: | 47 except ImportError: |
| 47 print 'python-dateutil package required' | 48 print 'python-dateutil package required' |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 112 'requires_auth': False, | 113 'requires_auth': False, |
| 113 'email_domain': 'chromium.org', | 114 'email_domain': 'chromium.org', |
| 114 }, | 115 }, |
| 115 ] | 116 ] |
| 116 | 117 |
| 117 gerrit_instances = [ | 118 gerrit_instances = [ |
| 118 { | 119 { |
| 119 'url': 'chromium-review.googlesource.com', | 120 'url': 'chromium-review.googlesource.com', |
| 120 'shorturl': 'crosreview.com', | 121 'shorturl': 'crosreview.com', |
| 121 }, | 122 }, |
| 122 # TODO(deymo): chrome-internal-review requires login credentials. Enable once | 123 { |
| 123 # login support is added to this client. See crbug.com/281695. | 124 'url': 'chrome-internal-review.googlesource.com', |
| 124 #{ | 125 'shorturl': 'crosreview.com/i', |
| 125 # 'url': 'chrome-internal-review.googlesource.com', | 126 }, |
| 126 # 'shorturl': 'crosreview.com/i', | |
| 127 #}, | |
| 128 { | 127 { |
| 129 'host': 'gerrit.chromium.org', | 128 'host': 'gerrit.chromium.org', |
| 130 'port': 29418, | 129 'port': 29418, |
| 131 }, | 130 }, |
| 132 { | 131 { |
| 133 'host': 'gerrit-int.chromium.org', | 132 'host': 'gerrit-int.chromium.org', |
| 134 'port': 29419, | 133 'port': 29419, |
| 135 }, | 134 }, |
| 136 ] | 135 ] |
| 137 | 136 |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 398 '--comments', | 397 '--comments', |
| 399 '--'] + filters | 398 '--'] + filters |
| 400 (stdout, _) = subprocess.Popen(gquery_cmd, stdout=subprocess.PIPE, | 399 (stdout, _) = subprocess.Popen(gquery_cmd, stdout=subprocess.PIPE, |
| 401 stderr=subprocess.PIPE).communicate() | 400 stderr=subprocess.PIPE).communicate() |
| 402 # Drop the last line of the output with the stats. | 401 # Drop the last line of the output with the stats. |
| 403 issues = stdout.splitlines()[:-1] | 402 issues = stdout.splitlines()[:-1] |
| 404 return map(json.loads, issues) | 403 return map(json.loads, issues) |
| 405 | 404 |
| 406 @staticmethod | 405 @staticmethod |
| 407 def gerrit_changes_over_rest(instance, filters): | 406 def gerrit_changes_over_rest(instance, filters): |
| 408 # See https://gerrit-review.googlesource.com/Documentation/rest-api.html | 407 # Convert the "key:value" filter to a dictionary. |
| 409 # Gerrit doesn't allow filtering by created time, only modified time. | 408 req = dict(f.split(':', 1) for f in filters) |
| 410 args = urllib.urlencode([ | |
| 411 ('q', ' '.join(filters)), | |
| 412 ('o', 'MESSAGES'), | |
| 413 ('o', 'LABELS')]) | |
| 414 rest_url = 'https://%s/changes/?%s' % (instance['url'], args) | |
| 415 | |
| 416 req = urllib2.Request(rest_url, headers={'Accept': 'text/plain'}) | |
| 417 try: | 409 try: |
| 418 response = urllib2.urlopen(req) | 410 # Instanciate the generator to force all the requests now and catch the |
|
szager1
2013/10/31 18:15:45
s/Instanciate/Instantiate/
| |
| 419 stdout = response.read() | 411 # errors here. |
| 420 except urllib2.HTTPError, e: | 412 return list(gerrit_util.QueryAllChanges(instance['url'], req, |
| 421 print 'ERROR: Looking up %r: %s' % (rest_url, e) | 413 o_params=['MESSAGES', 'LABELS', 'DETAILED_ACCOUNTS'])) |
| 414 except gerrit_util.GerritError, e: | |
| 415 print 'ERROR: Looking up %r: %s' % (instance['url'], e) | |
| 422 return [] | 416 return [] |
| 423 | 417 |
| 424 # Check that the returned JSON starts with the right marker. | |
| 425 if stdout[:5] != ")]}'\n": | |
| 426 print 'ERROR: Marker not found on REST API response: %r' % stdout[:5] | |
| 427 return [] | |
| 428 return json.loads(stdout[5:]) | |
| 429 | |
| 430 def gerrit_search(self, instance, owner=None, reviewer=None): | 418 def gerrit_search(self, instance, owner=None, reviewer=None): |
| 431 max_age = datetime.today() - self.modified_after | 419 max_age = datetime.today() - self.modified_after |
| 432 max_age = max_age.days * 24 * 3600 + max_age.seconds | 420 max_age = max_age.days * 24 * 3600 + max_age.seconds |
| 433 user_filter = 'owner:%s' % owner if owner else 'reviewer:%s' % reviewer | 421 user_filter = 'owner:%s' % owner if owner else 'reviewer:%s' % reviewer |
| 434 filters = ['-age:%ss' % max_age, user_filter] | 422 filters = ['-age:%ss' % max_age, user_filter] |
| 435 | 423 |
| 436 # Determine the gerrit interface to use: SSH or REST API: | 424 # Determine the gerrit interface to use: SSH or REST API: |
| 437 if 'host' in instance: | 425 if 'host' in instance: |
| 438 issues = self.gerrit_changes_over_ssh(instance, filters) | 426 issues = self.gerrit_changes_over_ssh(instance, filters) |
| 439 issues = [self.process_gerrit_ssh_issue(instance, issue) | 427 issues = [self.process_gerrit_ssh_issue(instance, issue) |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 499 ret['replies'] = self.process_gerrit_rest_issue_replies(issue['messages']) | 487 ret['replies'] = self.process_gerrit_rest_issue_replies(issue['messages']) |
| 500 else: | 488 else: |
| 501 ret['replies'] = [] | 489 ret['replies'] = [] |
| 502 ret['reviewers'] = set(r['author'] for r in ret['replies']) | 490 ret['reviewers'] = set(r['author'] for r in ret['replies']) |
| 503 ret['reviewers'].discard(ret['author']) | 491 ret['reviewers'].discard(ret['author']) |
| 504 return ret | 492 return ret |
| 505 | 493 |
| 506 @staticmethod | 494 @staticmethod |
| 507 def process_gerrit_rest_issue_replies(replies): | 495 def process_gerrit_rest_issue_replies(replies): |
| 508 ret = [] | 496 ret = [] |
| 509 replies = filter(lambda r: 'email' in r['author'], replies) | 497 replies = filter(lambda r: 'author' in r and 'email' in r['author'], |
| 498 replies) | |
| 510 for reply in replies: | 499 for reply in replies: |
| 511 ret.append({ | 500 ret.append({ |
| 512 'author': reply['author']['email'], | 501 'author': reply['author']['email'], |
| 513 'created': datetime_from_gerrit(reply['date']), | 502 'created': datetime_from_gerrit(reply['date']), |
| 514 'content': reply['message'], | 503 'content': reply['message'], |
| 515 }) | 504 }) |
| 516 return ret | 505 return ret |
| 517 | 506 |
| 518 def google_code_issue_search(self, instance): | 507 def google_code_issue_search(self, instance): |
| 519 time_format = '%Y-%m-%dT%T' | 508 time_format = '%Y-%m-%dT%T' |
| (...skipping 585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1105 print '\n\n\n' | 1094 print '\n\n\n' |
| 1106 | 1095 |
| 1107 my_activity.print_changes() | 1096 my_activity.print_changes() |
| 1108 my_activity.print_reviews() | 1097 my_activity.print_reviews() |
| 1109 my_activity.print_issues() | 1098 my_activity.print_issues() |
| 1110 return 0 | 1099 return 0 |
| 1111 | 1100 |
| 1112 | 1101 |
| 1113 if __name__ == '__main__': | 1102 if __name__ == '__main__': |
| 1114 sys.exit(main()) | 1103 sys.exit(main()) |
| OLD | NEW |