blob: 7c2b6a286b1559f75bd0cc0eb45a7440ff14d981 [file] [log] [blame]
#!/usr/bin/python
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import optparse
from chromite.buildbot import constants
from chromite.lib import gerrit
import logging
def find_user(helper, username):
# Try querying both initially; if it works, we can save a query.
emails = ["%s@%s" % (username, domain)
for domain in ("google.com", "chromium.org")]
owners = ["owner:%s" % x for x in emails]
try:
helper.Query('( %s ) limit:0' % ' OR '.join(owners))
return emails
except gerrit.GerritException:
# find the offender.
pass
recomposed = []
for email in emails:
try:
helper.Query("%s limit:0" % email)
recomposed.append(email)
except gerrit.GerritException:
pass
if not recomposed:
raise Exception("no email addresses found for %r" % username)
return recomposed
def main(argv):
parser = optparse.OptionParser(usage=
"usage: prog [--internal|--external] [--query|--age] "
"[email_addresses|usernames]")
parser.add_option("-i", "--internal", default=False, action="store_true",
help="Query gerrit-int.")
parser.add_option("-e", "--external", dest="internal", action="store_false",
help="Query gerrit. Note this is the default.")
parser.add_option("--age", default="6mon",
help="Limit results to within this gerrit age query. See "
"http://goo.gl/AdJy3 for the age form; to see the last 3 "
"months, it would be '3mon'. Defaults to the last 6 "
"months.")
parser.add_option("--query", default=None,
help="Freeform gerrit query. If specified, it overrides "
"the normal querying behaviour. Use only if you know "
"what you're doing.")
opts, args = parser.parse_args(argv)
if not args and not opts.query:
parser.error("no querying parameters given.")
logging.getLogger().setLevel(logging.WARNING)
query = []
helper = gerrit.GetGerritHelper(
constants.INTERNAL_REMOTE if opts.internal else constants.EXTERNAL_REMOTE)
recomposed_args = []
for arg in args:
if "@" not in arg:
recomposed_args.extend(find_user(helper, arg))
else:
recomposed_args.append(arg)
args = set(recomposed_args)
addresses = [x.replace(":", "\:") for x in args]
owners = ["owner:%s" % x for x in addresses]
reviewers = ["reviewer:%s" % x for x in addresses]
if opts.query:
query.append(opts.query)
elif args:
query.append("( %s )" % " OR ".join(owners))
query.append("-age:%s" % opts.age)
query = " AND ".join(query)
results = helper.Query(query, current_patch=False, sort="lastUpdated")
targets = frozenset(args)
if not args:
print "query resulted in %i owned CLs." % len(results)
print "no email addresses given so unable to do scoring stats"
return 0
print "Owner stats: %i CLs." % len(results)
stats = {}
for x in results:
status = x["status"].lower()
stats[status] = stats.get(status, 0) + 1
if "new" in stats:
stats["open"] = stats.pop("new")
for status, value in sorted(stats.iteritems(), key=lambda x:x[0]):
print " %s: %i" % (status, value)
# Get approval stats.
requested = helper.Query(
"( %s AND NOT ( %s ) ) AND -age:%s" % (" OR ".join(reviewers),
" OR ".join(owners), opts.age),
current_patch=False, options=("--all-approvals",))
total_scored_patchsets = scoring = 0
lgtms = 0
for cl in requested:
touched_it = False
lgtmed = False
for patchset in cl.get("patchSets", ()):
for approval in patchset.get("approvals", ()):
if targets.intersection([approval["by"].get("email")]):
touched_it = True
if (("CRVW", 2) ==
(approval.get("type"), int(approval.get("value", 0)))):
lgtmed = True
total_scored_patchsets += 1
if touched_it:
scoring += 1
if lgtmed:
lgtms += 1
# Find comments; gerrit doesn't give that information in --all-approvals
# unfortunately.
comments = helper.Query(
"( %s AND NOT ( %s ) ) AND -age:%s" % (" OR ".join(reviewers),
" OR ".join(owners), opts.age),
options=("--comments", "--patch-sets"), raw=True, current_patch=False)
requested_review = len(comments)
commented_changes = total_comments = 0
for change in comments:
touched = False
for comment in change.get("comments", ()):
if comment["reviewer"].get("email", None) in targets:
total_comments += 1
touched = True
if touched:
commented_changes += 1
print ("Requested as a reviewer for %i changes, commented on %i, "
"%i comments total; lgtm'd %i changes" % (
requested_review, commented_changes,
total_comments, lgtms))
ratio = float(total_scored_patchsets)/scoring if total_scored_patchsets else 0
print ("Review stats: %i Changes scored; %i individual patchsets scored "
"(for a %2.2fx scoring/change rate)" % (
scoring, total_scored_patchsets, ratio))