Commit c73e516e authored by maruel@chromium.org's avatar maruel@chromium.org

Add my_reviews.py script for perf time.

Add search interface for rietveld.

R=dpranke@chromium.org
BUG=
TEST=


Review URL: http://codereview.chromium.org/7977030

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@102191 0039d316-1c4b-4281-b951-d872f2087c98
parent eb2756df
#!/usr/bin/env python
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Get rietveld stats.
Example:
- my_reviews.py -o me@chromium.org -Q for stats for last quarter.
"""
import datetime
import optparse
import os
import sys
import rietveld
def print_reviews(owner, reviewer, created_after, created_before):
"""Prints issues with the filter.
Set with_messages=True to search() call bellow if you want each message too.
If you only want issue numbers, use keys_only=True in the search() call.
You can then use remote.get_issue_properties(issue, True) to get the data per
issue.
"""
instance_url = 'codereview.chromium.org'
remote = rietveld.Rietveld(instance_url, None, None)
# See def search() in rietveld.py to see all the filters you can use.
for issue in remote.search(
owner=owner,
reviewer=reviewer,
created_after=created_after,
created_before=created_before,
keys_only=False,
with_messages=False,
):
# By default, hide commit-bot and the domain.
reviewers = set(r.split('@', 1)[0] for r in issue['reviewers'])
reviewers -= set(('commit-bot',))
# Strip time.
timestamp = issue['created'][:10]
# More information is available, print issue.keys() to see them.
print '%d: %s %s' % (issue['issue'], timestamp, ', '.join(reviewers))
def get_previous_quarter(today):
"""There are four quarters, 01-03, 04-06, 07-09, 10-12.
If today is in the last month of a quarter, assume it's the current quarter
that is requested.
"""
year = today.year
month = today.month - (today.month % 3)
if not month:
month = 12
year -= 1
previous_month = month - 2
return (
'%d-%02d-01' % (year, previous_month),
'%d-%02d-01' % (year, month))
def main():
parser = optparse.OptionParser(description=sys.modules[__name__].__doc__)
parser.add_option('-o', '--owner')
parser.add_option('-r', '--reviewer')
parser.add_option('-c', '--created_after')
parser.add_option('-C', '--created_before')
parser.add_option('-Q', '--last_quarter', action='store_true')
# Remove description formatting
parser.format_description = lambda x: parser.description
options, args = parser.parse_args()
if args:
parser.error('Args unsupported')
if not options.owner and not options.reviewer:
options.owner = os.environ['EMAIL_ADDRESS']
if '@' not in options.owner:
parser.error('Please specify at least -o or -r')
print 'Defaulting to owner=%s' % options.owner
if options.last_quarter:
today = datetime.date.today()
options.created_after, options.created_before = get_previous_quarter(today)
print 'Using range %s to %s' % (
options.created_after, options.created_before)
print_reviews(
options.owner, options.reviewer,
options.created_after, options.created_before)
return 0
if __name__ == '__main__':
sys.exit(main())
......@@ -242,6 +242,64 @@ class Rietveld(object):
('xsrf_token', self.xsrf_token()),
(flag, value)])
def search(
self,
owner=None, reviewer=None,
base=None,
closed=None, private=None, commit=None,
created_before=None, created_after=None,
modified_before=None, modified_after=None,
per_request=None, keys_only=False,
with_messages=False):
"""Yields search results."""
# These are expected to be strings.
string_keys = {
'owner': owner,
'reviewer': reviewer,
'base': base,
'created_before': created_before,
'created_after': created_after,
'modified_before': modified_before,
'modified_after': modified_after,
}
# These are either None, False or True.
three_state_keys = {
'closed': closed,
'private': private,
'commit': commit,
}
url = '/search?format=json'
# Sort the keys mainly to ease testing.
for key in sorted(string_keys):
value = string_keys[key]
if value:
url += '&%s=%s' % (key, urllib2.quote(value))
for key in sorted(three_state_keys):
value = three_state_keys[key]
if value is not None:
url += '&%s=%d' % (key, int(value) + 1)
if keys_only:
url += '&keys_only=True'
if with_messages:
url += '&with_messages=True'
if per_request:
url += '&limit=%d' % per_request
cursor = ''
while True:
output = self.get(url + cursor)
if output.startswith('<'):
# It's an error message. Return as no result.
break
data = json.loads(output) or {}
if not data.get('results'):
break
for i in data['results']:
yield i
cursor = '&cursor=%s' % data['cursor']
def get(self, request_path, **kwargs):
kwargs.setdefault('payload', None)
return self._send(request_path, **kwargs)
......
......@@ -281,6 +281,70 @@ class RietveldTest(unittest.TestCase):
# TODO(maruel): Change with no diff, only svn property change:
# http://codereview.chromium.org/6462019/
def test_search_all_empty(self):
url = (
'/search?format=json'
'&base=base'
'&created_after=2010-01-02'
'&created_before=2010-01-01'
'&modified_after=2010-02-02'
'&modified_before=2010-02-01'
'&owner=owner%40example.com'
'&reviewer=reviewer%40example.com'
'&closed=2'
'&commit=2'
'&private=2'
'&keys_only=True'
'&with_messages=True'
'&limit=23')
self.requests = [
(url, '{}'),
]
results = list(self.rietveld.search(
'owner@example.com',
'reviewer@example.com',
'base',
True,
True,
True,
'2010-01-01',
'2010-01-02',
'2010-02-01',
'2010-02-02',
23,
True,
True,
))
self.assertEquals([], results)
def test_results_cursor(self):
# Verify cursor iteration is transparent.
self.requests = [
('/search?format=json&base=base',
rietveld.json.dumps({
'cursor': 'MY_CURSOR',
'results': [{'foo': 'bar'}, {'foo': 'baz'}],
})),
('/search?format=json&base=base&cursor=MY_CURSOR',
rietveld.json.dumps({
'cursor': 'NEXT',
'results': [{'foo': 'prout'}],
})),
('/search?format=json&base=base&cursor=NEXT',
rietveld.json.dumps({
'cursor': 'VOID',
'results': [],
})),
]
expected = [
{'foo': 'bar'},
{'foo': 'baz'},
{'foo': 'prout'},
]
for i in self.rietveld.search(base='base'):
self.assertEquals(expected.pop(0), i)
self.assertEquals([], expected)
if __name__ == '__main__':
logging.basicConfig(level=logging.ERROR)
......
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