add a tool for determining unaccounted for rechecks
this is specifically not in cmd because this is designed as a local spot checking tool only. However it's more useful in the er repository than on my local disk. builds a summary report of rechecks found in gerrit in the last 2 weeks, including how many had a bug, and how many had a bug we don't know about. Change-Id: I6a99a3bcec527652901c8aa3639926a8e4a518d5
This commit is contained in:
parent
2fa86a63cc
commit
b60efa16d4
11
tools/README.rst
Normal file
11
tools/README.rst
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
====================================
|
||||||
|
Elastic Recheck Useful Point Tools
|
||||||
|
====================================
|
||||||
|
|
||||||
|
These are useful point tools that are examples of using elastic
|
||||||
|
recheck to get additionally useful information out of the
|
||||||
|
system. Items in this directory do not have unit tests,
|
||||||
|
intentionally. This is about useful examples, that are better shared
|
||||||
|
than left on people's hard drives to get lost in the mists of time.
|
||||||
|
|
||||||
|
All tools should have a -h which explain what they do.
|
134
tools/unaccounted_rechecks.py
Executable file
134
tools/unaccounted_rechecks.py
Executable file
@ -0,0 +1,134 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import getpass
|
||||||
|
import os.path
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
|
from gerritlib import gerrit
|
||||||
|
|
||||||
|
|
||||||
|
def get_options():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='Find rechecks not accounted for in ER')
|
||||||
|
parser.add_argument('-u', '--user', help='Gerrit User',
|
||||||
|
default=getpass.getuser())
|
||||||
|
tryfiles = ('id_gerrit', 'id_rsa', 'id_dsa')
|
||||||
|
default_key = ""
|
||||||
|
for f in tryfiles:
|
||||||
|
trykey = os.path.join(os.path.expanduser("~"), '.ssh', f)
|
||||||
|
if os.path.exists(trykey):
|
||||||
|
default_key = trykey
|
||||||
|
break
|
||||||
|
parser.add_argument('-k', '--key', help='Gerrit SSH Key',
|
||||||
|
default=default_key)
|
||||||
|
parser.add_argument('-d', '--dir', help="Queries Directory",
|
||||||
|
default="queries")
|
||||||
|
parser.add_argument('-D', '--days', help="Number of Days to Query",
|
||||||
|
default=14)
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def connect_to_gerrit(user, key):
|
||||||
|
return gerrit.Gerrit('review.openstack.org', user, 29418, key)
|
||||||
|
|
||||||
|
|
||||||
|
def collect_rechecks(gerrit, days="14"):
|
||||||
|
# query only during the last 2 weeks, as that's what ER knows about
|
||||||
|
since = int(time.time()) - 24 * 60 * 60 * int(days)
|
||||||
|
changes = []
|
||||||
|
sortkey = None
|
||||||
|
while True:
|
||||||
|
query = ("--patch-sets --comments project:^openstack.* "
|
||||||
|
" NOT age:%sd" % days)
|
||||||
|
if sortkey:
|
||||||
|
query += " resume_sortkey:%s" % sortkey
|
||||||
|
|
||||||
|
data = gerrit.bulk_query(query)
|
||||||
|
if len(data) <= 1:
|
||||||
|
# means we only have the counter row
|
||||||
|
break
|
||||||
|
|
||||||
|
for d in data:
|
||||||
|
if 'comments' in d:
|
||||||
|
sortkey = d['sortKey']
|
||||||
|
comments = d['comments']
|
||||||
|
project = d['project']
|
||||||
|
for comment in comments:
|
||||||
|
if comment['timestamp'] < since:
|
||||||
|
# bail early if the comment is outside the ER window
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = re.search('recheck (no bug|bug (\#)?(?P<bugno>\d+))$',
|
||||||
|
comment['message'])
|
||||||
|
if m:
|
||||||
|
dev = None
|
||||||
|
if 'username' in comment['reviewer']:
|
||||||
|
dev = comment['reviewer']['username']
|
||||||
|
bug = m.group('bugno') or 'no bug'
|
||||||
|
changes.append(
|
||||||
|
{'dev': dev,
|
||||||
|
'project': project,
|
||||||
|
'bug': bug,
|
||||||
|
'review': d['url']})
|
||||||
|
return changes
|
||||||
|
|
||||||
|
|
||||||
|
def has_er_bug(dirname, bug):
|
||||||
|
return os.path.exists(os.path.join(dirname, "%s.yaml" % bug))
|
||||||
|
|
||||||
|
|
||||||
|
def cross_ref_with_er(changes, dirname):
|
||||||
|
for i in range(len(changes)):
|
||||||
|
changes[i]['er'] = has_er_bug(dirname, changes[i]['bug'])
|
||||||
|
return changes
|
||||||
|
|
||||||
|
|
||||||
|
def summarize_changes(changes):
|
||||||
|
no_er = {}
|
||||||
|
print "Summary"
|
||||||
|
print "%4.4s - Total Rechecks" % (len(changes))
|
||||||
|
print "%4.4s - Total w/Bug" % (
|
||||||
|
len([c for c in changes if c['bug'] != 'no bug']))
|
||||||
|
print "%4.4s - Total w/Bug and new recheck" % (
|
||||||
|
len([c for c in changes if (c['bug'] != 'no bug' and not c['er'])]))
|
||||||
|
|
||||||
|
for c in changes:
|
||||||
|
bug = c['bug']
|
||||||
|
if bug != 'no bug' and not c['er']:
|
||||||
|
if bug not in no_er:
|
||||||
|
no_er[bug] = {'count': 0, 'reviews': []}
|
||||||
|
no_er[bug]['count'] += 1
|
||||||
|
no_er[bug]['reviews'].append(c['review'])
|
||||||
|
print
|
||||||
|
print "New bugs"
|
||||||
|
for k, v in no_er.iteritems():
|
||||||
|
print "Bug %s found %d times" % (k, v['count'])
|
||||||
|
for rev in v['reviews']:
|
||||||
|
print " - %s" % rev
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
opts = get_options()
|
||||||
|
g = connect_to_gerrit(opts.user, opts.key)
|
||||||
|
changes = collect_rechecks(g, opts.days)
|
||||||
|
changes = cross_ref_with_er(changes, opts.dir)
|
||||||
|
summarize_changes(changes)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
x
Reference in New Issue
Block a user