Commit e5deedfc authored by Nicolas Dossou-gbete's avatar Nicolas Dossou-gbete Committed by Commit Bot

Support JSON output in my_activity.py

That JSON output format shows some additional fields such as bug number
for CLs, label and component for issues.

Also does minor changes like replacing the old code.google.com
references and using short urls when possible.

BUG=None

Change-Id: I988d292dc57b72a2f2c6f12096266df8a09a4dd8
Reviewed-on: https://chromium-review.googlesource.com/422203Reviewed-by: 's avatarAaron Gable <agable@chromium.org>
Commit-Queue: Nicolas Dossou-Gbété <dgn@chromium.org>
parent 370ca1bd
......@@ -11,6 +11,7 @@ Example:
- my_activity.py -Y for stats for this year.
- my_activity.py -b 4/5/12 for stats since 4/5/12.
- my_activity.py -b 4/5/12 -e 6/7/12 for stats between 4/5/12 and 6/7/12.
- my_activity.py -jd to output stats for the week to json with deltas data.
"""
# TODO(vadimsh): This script knows too much about ClientLogin and cookies. It
......@@ -34,6 +35,7 @@ import subprocess
from string import Formatter
import sys
import urllib
import re
import auth
import fix_encoding
......@@ -250,6 +252,26 @@ class MyActivity(object):
return issues
def extract_bug_number_from_description(self, issue):
description = None
if 'description' in issue:
# Getting the description for Rietveld
description = issue['description']
elif 'revisions' in issue:
# Getting the description for REST Gerrit
revision = issue['revisions'][issue['current_revision']]
description = revision['commit']['message']
bugs = []
if description:
matches = re.findall('BUG=(((\d+)(,\s?)?)+)', description)
if matches:
for match in matches:
bugs.extend(match[0].replace(' ', '').split(','))
return bugs
def process_rietveld_issue(self, remote, instance, issue):
ret = {}
if self.options.deltas:
......@@ -287,6 +309,9 @@ class MyActivity(object):
ret['created'] = datetime_from_rietveld(issue['created'])
ret['replies'] = self.process_rietveld_replies(issue['messages'])
ret['bug'] = self.extract_bug_number_from_description(issue)
ret['landed_days_ago'] = issue['landed_days_ago']
return ret
@staticmethod
......@@ -323,7 +348,8 @@ class MyActivity(object):
# Instantiate the generator to force all the requests now and catch the
# errors here.
return list(gerrit_util.GenerateAllChanges(instance['url'], req,
o_params=['MESSAGES', 'LABELS', 'DETAILED_ACCOUNTS']))
o_params=['MESSAGES', 'LABELS', 'DETAILED_ACCOUNTS',
'CURRENT_REVISION', 'CURRENT_COMMIT']))
except gerrit_util.GerritError, e:
logging.error('Looking up %r: %s', instance['url'], e)
return []
......@@ -374,6 +400,7 @@ class MyActivity(object):
ret['replies'] = []
ret['reviewers'] = set(r['author'] for r in ret['replies'])
ret['reviewers'].discard(ret['author'])
ret['bug'] = self.extract_bug_number_from_description(issue)
return ret
@staticmethod
......@@ -412,6 +439,7 @@ class MyActivity(object):
ret['replies'] = []
ret['reviewers'] = set(r['author'] for r in ret['replies'])
ret['reviewers'].discard(ret['author'])
ret['bug'] = self.extract_bug_number_from_description(issue)
return ret
@staticmethod
......@@ -455,15 +483,21 @@ class MyActivity(object):
if 'items' in content:
items = content['items']
for item in items:
if instance.get('shorturl'):
item_url = 'https://%s/%d' % (instance['shorturl'], item['id'])
else:
item_url = 'https://bugs.chromium.org/p/%s/issues/detail?id=%d' % (
instance['name'], item['id'])
issue = {
'header': item['title'],
'created': dateutil.parser.parse(item['published']),
'modified': dateutil.parser.parse(item['updated']),
'author': item['author']['name'],
'url': 'https://code.google.com/p/%s/issues/detail?id=%s' % (
instance['name'], item['id']),
'url': item_url,
'comments': [],
'status': item['status'],
'labels': [],
'components': []
}
if 'shorturl' in instance:
issue['url'] = 'http://%s/%d' % (instance['shorturl'], item['id'])
......@@ -474,6 +508,10 @@ class MyActivity(object):
issue['owner'] = 'None'
if issue['owner'] == user_str or issue['author'] == user_str:
issues.append(issue)
if 'labels' in item:
issue['labels'] = item['labels']
if 'components' in item:
issue['components'] = item['components']
return issues
......@@ -634,6 +672,35 @@ class MyActivity(object):
self.print_reviews()
self.print_issues()
def dump_json(self, ignore_keys=None):
if ignore_keys is None:
ignore_keys = ['replies']
def format_for_json_dump(in_array):
output = {}
for item in in_array:
url = item.get('url') or item.get('review_url')
if not url:
raise Exception('Dumped item %s does not specify url' % item)
output[url] = dict(
(k, v) for k,v in item.iteritems() if k not in ignore_keys)
return output
class PythonObjectEncoder(json.JSONEncoder):
def default(self, obj): # pylint: disable=method-hidden
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, set):
return list(obj)
return json.JSONEncoder.default(self, obj)
output = {
'reviews': format_for_json_dump(self.reviews),
'changes': format_for_json_dump(self.changes),
'issues': format_for_json_dump(self.issues)
}
print json.dumps(output, indent=2, cls=PythonObjectEncoder)
def main():
# Silence upload.py.
......@@ -728,6 +795,9 @@ def main():
'-m', '--markdown', action='store_true',
help='Use markdown-friendly output (overrides --output-format '
'and --output-format-heading)')
output_format_group.add_option(
'-j', '--json', action='store_true',
help='Output json data (overrides other format options)')
parser.add_option_group(output_format_group)
auth.add_auth_options(parser)
......@@ -746,6 +816,9 @@ def main():
const=logging.ERROR,
help='Suppress non-error messages.'
)
parser.add_option(
'-o', '--output', metavar='<file>',
help='Where to output the results. By default prints to stdout.')
# Remove description formatting
parser.format_description = (
......@@ -819,9 +892,27 @@ def main():
except auth.AuthenticationError as e:
logging.error('auth.AuthenticationError: %s', e)
my_activity.print_changes()
my_activity.print_reviews()
my_activity.print_issues()
output_file = None
try:
if options.output:
output_file = open(options.output, 'w')
logging.info('Printing output to "%s"', options.output)
sys.stdout = output_file
except (IOError, OSError) as e:
logging.error('Unable to write output: %s', e)
else:
if options.json:
my_activity.dump_json()
else:
my_activity.print_changes()
my_activity.print_reviews()
my_activity.print_issues()
finally:
if output_file:
logging.info('Done printing to file.')
sys.stdout = sys.__stdout__
output_file.close()
return 0
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment