def main(argv=None): if argv is None: argv = sys.argv optparser = optparse.OptionParser() optparser.add_option( '-p', '--project', default='projects/nova.json', help='JSON file describing the project to generate stats for') optparser.add_option( '-a', '--all', action='store_true', help='Generate stats across all known projects (*.json)') optparser.add_option( '-s', '--stable', default='', metavar='BRANCH', help='Generate stats for the specified stable BRANCH ("havana") ' 'across all integrated projects') optparser.add_option( '-o', '--output', default='-', help='Where to write output. If - stdout is used and only one output' 'format may be given. Otherwise the output format is appended to' 'the output parameter to generate file names.') optparser.add_option( '--outputs', default=['txt'], action='append', help='Select what outputs to generate. (txt,csv).') optparser.add_option( '-d', '--days', type='int', default=14, help='Number of days to consider') optparser.add_option( '-u', '--user', default=getpass.getuser(), help='gerrit user') optparser.add_option( '-k', '--key', default=None, help='ssh key for gerrit') optparser.add_option( '-r', '--csv-rows', default=0, help='Max rows for CSV output', type='int', dest='csv_rows') options, args = optparser.parse_args() if options.stable: projects = utils.get_projects_info('projects/stable.json', False) else: projects = utils.get_projects_info(options.project, options.all) if not projects: print "Please specify a project." sys.exit(1) reviewers = {} now = datetime.datetime.utcnow() cut_off = now - datetime.timedelta(days=options.days) ts = calendar.timegm(cut_off.timetuple()) now_ts = calendar.timegm(now.timetuple()) change_stats = { 'patches': 0, 'created': 0, 'involved': 0, 'merged': 0, 'abandoned': 0, 'wip': 0, } for project in projects: changes = utils.get_changes([project], options.user, options.key, stable=options.stable) for change in changes: patch_for_change = False first_patchset = True for patchset in change.get('patchSets', []): process_patchset(project, patchset, reviewers, ts) age = utils.get_age_of_patch(patchset, now_ts) if (now_ts - age) > ts: change_stats['patches'] += 1 patch_for_change = True if first_patchset: change_stats['created'] += 1 first_patchset = False if patch_for_change: change_stats['involved'] += 1 if change['status'] == 'MERGED': change_stats['merged'] += 1 elif change['status'] == 'ABANDONED': change_stats['abandoned'] += 1 elif change['status'] == 'WORKINPROGRESS': change_stats['wip'] += 1 reviewers = [(v, k) for k, v in reviewers.iteritems() if k.lower() not in ('jenkins', 'smokestack')] reviewers.sort(reverse=True, key=lambda r: r[0]['total']) # Do logical processing of reviewers. reviewer_data = [] totals = { 'all': 0, 'core': 0, } for k, v in reviewers: in_core_team = False for project in projects: if v in project['core-team']: in_core_team = True break name = '%s%s' % (v, ' **' if in_core_team else '') plus = float(k['votes']['2'] + k['votes']['1']) minus = float(k['votes']['-2'] + k['votes']['-1']) all_reviews = plus + minus ratio = ((plus / (all_reviews)) * 100) if all_reviews > 0 else 0 r = (k['total'], k['votes']['-2'], k['votes']['-1'], k['votes']['1'], k['votes']['2'], k['votes']['A'], "%5.1f%%" % ratio) dratio = (((float(k['disagreements']) / all_reviews) * 100) if all_reviews else 0.0) d = (k['disagreements'], "%5.1f%%" % dratio) sratio = ((float(k['total']) / k['received']) * 100 if k['received'] else 0) s = (k['received'], "%5.1f%%" % sratio if k['received'] else 'inf') reviewer_data.append((name, r, d, s)) totals['all'] += k['total'] if in_core_team: totals['core'] += k['total'] # And output. writers = { 'csv': write_csv, 'txt': write_pretty, } if options.output == '-': if len(options.outputs) != 1: raise Exception("Can only output one format to stdout.") for output in options.outputs: if options.output == '-': file_obj = sys.stdout on_done = None else: file_obj = open(options.output + '.' + output, 'wt') on_done = file_obj.close try: writer = writers[output] writer(reviewer_data, file_obj, options, reviewers, projects, totals, change_stats) finally: if on_done: on_done() return 0
def main(argv=None): if argv is None: argv = sys.argv optparser = optparse.OptionParser() optparser.add_option( '-p', '--project', default='projects/nova.json', help='JSON file describing the project to generate stats for') optparser.add_option( '-a', '--all', action='store_true', help='Generate stats across all known projects (*.json)') optparser.add_option( '-u', '--user', default=getpass.getuser(), help='gerrit user') optparser.add_option( '-k', '--key', default=None, help='ssh key for gerrit') optparser.add_option( '-s', '--stable', action='store_true', help='Include stable branch commits') optparser.add_option( '-l', '--longest-waiting', type='int', default=5, help='Show n changesets that have waited the longest)') optparser.add_option( '-m', '--waiting-more', type='int', default=7, help='Show number of changesets that have waited more than n days)') optparser.add_option( '-H', '--html', action='store_true', help='Use HTML output instead of plain text') optparser.add_option( '--server', default='review.openstack.org', help='Gerrit server to connect to') optparser.add_option( '--debug', action='store_true', help='Show extra debug output') optparser.add_option( '--projects-dir', default='./projects', help='Directory where to locate the project files') options, args = optparser.parse_args() logging.basicConfig(level=logging.ERROR) if options.debug: logging.root.setLevel(logging.DEBUG) projects = utils.get_projects_info(options.project, options.all, base_dir=options.projects_dir) if not projects: print "Please specify a project." sys.exit(1) changes = utils.get_changes(projects, options.user, options.key, only_open=True, server=options.server) waiting_on_submitter = [] waiting_on_reviewer = [] now = datetime.datetime.utcnow() now_ts = calendar.timegm(now.timetuple()) for change in changes: if 'rowCount' in change: continue if not options.stable and 'stable' in change['branch']: continue if change['status'] != 'NEW': # Filter out WORKINPROGRESS continue latest_patch = change['patchSets'][-1] if utils.patch_set_approved(latest_patch): # Ignore patches already approved and just waiting to merge continue waiting_for_review = True approvals = latest_patch.get('approvals', []) approvals.sort(key=lambda a: a['grantedOn']) for review in approvals: if review['type'] not in ('CRVW', 'VRIF', 'Code-Review', 'Verified'): continue if review['value'] in ('-1', '-2'): waiting_for_review = False break change['age'] = utils.get_age_of_patch(latest_patch, now_ts) change['age2'] = utils.get_age_of_patch(change['patchSets'][0], now_ts) patch = find_oldest_no_nack(change) change['age3'] = utils.get_age_of_patch(patch, now_ts) if patch else 0 if waiting_for_review: waiting_on_reviewer.append(change) else: waiting_on_submitter.append(change) stats = gen_stats(projects, waiting_on_reviewer, waiting_on_submitter, options) if options.html: print_stats_html(stats) else: print_stats_txt(stats)
def main(argv=None): if argv is None: argv = sys.argv optparser = optparse.OptionParser() optparser.add_option( '-p', '--project', default='projects/nova.json', help='JSON file describing the project to generate stats for') optparser.add_option( '-a', '--all', action='store_true', help='Generate stats across all known projects (*.json)') optparser.add_option( '-s', '--stable', default='', metavar='BRANCH', help='Generate stats for the specified stable BRANCH ("havana") ' 'across all integrated projects') optparser.add_option( '-o', '--output', default='-', help='Where to write output. If - stdout is used and only one output ' 'format may be given. Otherwise the output format is appended to ' 'the output parameter to generate file names.') optparser.add_option('--outputs', default=['txt'], action='append', help='Select what outputs to generate. (txt,csv).') optparser.add_option('-d', '--days', type='int', default=14, help='Number of days to consider') optparser.add_option('-u', '--user', default=getpass.getuser(), help='gerrit user') optparser.add_option('-P', '--password', default=getpass.getuser(), help='gerrit HTTP password') optparser.add_option('-k', '--key', default=None, help='ssh key for gerrit') optparser.add_option('-r', '--csv-rows', default=0, help='Max rows for CSV output', type='int', dest='csv_rows') optparser.add_option('--server', default='review.openstack.org', help='Gerrit server to connect to') options, args = optparser.parse_args() if options.stable: projects = utils.get_projects_info('projects/stable.json', False) else: projects = utils.get_projects_info(options.project, options.all) if not projects: print "Please specify a project." sys.exit(1) reviewers = {} now = datetime.datetime.utcnow() cut_off = now - datetime.timedelta(days=options.days) ts = calendar.timegm(cut_off.timetuple()) now_ts = calendar.timegm(now.timetuple()) change_stats = { 'patches': 0, 'created': 0, 'involved': 0, 'merged': 0, 'abandoned': 0, 'wip': 0, } for project in projects: changes = utils.get_changes([project], options.user, options.key, stable=options.stable, server=options.server) for change in changes: patch_for_change = False first_patchset = True for patchset in change.get('patchSets', []): process_patchset(project, patchset, reviewers, ts, options) age = utils.get_age_of_patch(patchset, now_ts) if (now_ts - age) > ts: change_stats['patches'] += 1 patch_for_change = True if first_patchset: change_stats['created'] += 1 first_patchset = False if patch_for_change: change_stats['involved'] += 1 if change['status'] == 'MERGED': change_stats['merged'] += 1 elif change['status'] == 'ABANDONED': change_stats['abandoned'] += 1 elif change['status'] == 'WORKINPROGRESS': change_stats['wip'] += 1 reviewers = [(v, k) for k, v in reviewers.iteritems() if k.lower() not in ('jenkins', 'smokestack')] reviewers.sort(reverse=True, key=lambda r: r[0]['total']) # Do logical processing of reviewers. reviewer_data = [] totals = { 'all': 0, 'core': 0, } for k, v in reviewers: in_core_team = False for project in projects: if v in utils.get_core_team(project, options.server, options.user, options.password): in_core_team = True break name = '%s%s' % (v, ' **' if in_core_team else '') plus = float(k['votes']['2'] + k['votes']['1']) minus = float(k['votes']['-2'] + k['votes']['-1']) all_reviews = plus + minus ratio = ((plus / (all_reviews)) * 100) if all_reviews > 0 else 0 r = (k['total'], k['votes']['-2'], k['votes']['-1'], k['votes']['1'], k['votes']['2'], k['votes']['A'], "%5.1f%%" % ratio) dratio = (((float(k['disagreements']) / all_reviews) * 100) if all_reviews else 0.0) d = (k['disagreements'], "%5.1f%%" % dratio) sratio = ((float(k['total']) / k['received']) * 100 if k['received'] else 0) s = (k['received'], "%5.1f%%" % sratio if k['received'] else 'inf') reviewer_data.append((name, r, d, s)) totals['all'] += k['total'] if in_core_team: totals['core'] += k['total'] # And output. writers = { 'csv': write_csv, 'txt': write_pretty, } if options.output == '-': if len(options.outputs) != 1: raise Exception("Can only output one format to stdout.") for output in options.outputs: if options.output == '-': file_obj = sys.stdout on_done = None else: file_obj = open(options.output + '.' + output, 'wt') on_done = file_obj.close try: writer = writers[output] writer(reviewer_data, file_obj, options, reviewers, projects, totals, change_stats) finally: if on_done: on_done() return 0
def main(argv=None): if argv is None: argv = sys.argv optparser = optparse.OptionParser() optparser.add_option( '-p', '--project', default='projects/nova.json', help='JSON file describing the project to generate stats for') optparser.add_option( '-a', '--all', action='store_true', help='Generate stats across all known projects (*.json)') optparser.add_option('-u', '--user', default=getpass.getuser(), help='gerrit user') optparser.add_option('-k', '--key', default=None, help='ssh key for gerrit') optparser.add_option('-s', '--stable', action='store_true', help='Include stable branch commits') optparser.add_option( '-l', '--longest-waiting', type='int', default=5, help='Show n changesets that have waited the longest)') optparser.add_option( '-m', '--waiting-more', type='int', default=7, help='Show number of changesets that have waited more than n days)') optparser.add_option('-H', '--html', action='store_true', help='Use HTML output instead of plain text') optparser.add_option('--server', default='review.openstack.org', help='Gerrit server to connect to') optparser.add_option('--debug', action='store_true', help='Show extra debug output') optparser.add_option('--projects-dir', default='./projects', help='Directory where to locate the project files') optparser.add_option( '--output', '-o', default='-', help="Where to write output. - for stdout. The file will be appended" " if it exists.") options, args = optparser.parse_args() logging.basicConfig(level=logging.ERROR) if options.debug: logging.root.setLevel(logging.DEBUG) projects = utils.get_projects_info(options.project, options.all, base_dir=options.projects_dir) if not projects: print "Please specify a project." sys.exit(1) changes = utils.get_changes(projects, options.user, options.key, only_open=True, server=options.server) waiting_on_submitter = [] waiting_on_reviewer = [] now = datetime.datetime.utcnow() now_ts = calendar.timegm(now.timetuple()) for change in changes: if 'rowCount' in change: continue if not options.stable and 'stable' in change['branch']: continue if utils.is_workinprogress(change): # Filter out WORKINPROGRESS continue latest_patch = change['patchSets'][-1] if utils.patch_set_approved(latest_patch): # Ignore patches already approved and just waiting to merge continue waiting_for_review = True approvals = latest_patch.get('approvals', []) approvals.sort(key=lambda a: a['grantedOn']) for review in approvals: if review['type'] not in ('CRVW', 'VRIF', 'Code-Review', 'Verified'): continue if review['value'] in ('-1', '-2'): waiting_for_review = False break change['age'] = utils.get_age_of_patch(latest_patch, now_ts) change['age2'] = utils.get_age_of_patch(change['patchSets'][0], now_ts) patch = find_oldest_no_nack(change) change['age3'] = utils.get_age_of_patch(patch, now_ts) if patch else 0 if waiting_for_review: waiting_on_reviewer.append(change) else: waiting_on_submitter.append(change) stats = gen_stats(projects, waiting_on_reviewer, waiting_on_submitter, options) if options.output == '-': output = sys.stdout else: output = open(options.output, 'at') try: if options.html: print_stats_html(stats, f=output) else: print_stats_txt(stats, f=output) finally: if output is not sys.stdout: output.close()
def main(argv=None): if argv is None: argv = sys.argv optparser = optparse.OptionParser() optparser.add_option( "-p", "--project", default="projects/nova.json", help="JSON file describing the project to generate stats for" ) optparser.add_option("-a", "--all", action="store_true", help="Generate stats across all known projects (*.json)") optparser.add_option( "-s", "--stable", default="", metavar="BRANCH", help='Generate stats for the specified stable BRANCH ("havana") ' "across all integrated projects", ) optparser.add_option( "-o", "--output", default="-", help="Where to write output. If - stdout is used and only one output " "format may be given. Otherwise the output format is appended to " "the output parameter to generate file names.", ) optparser.add_option( "--outputs", default=["txt"], action="append", help="Select what outputs to generate. (txt,csv)." ) optparser.add_option("-d", "--days", type="int", default=14, help="Number of days to consider") optparser.add_option("-u", "--user", default=getpass.getuser(), help="gerrit user") optparser.add_option("-P", "--password", default=getpass.getuser(), help="gerrit HTTP password") optparser.add_option("-k", "--key", default=None, help="ssh key for gerrit") optparser.add_option("-r", "--csv-rows", default=0, help="Max rows for CSV output", type="int", dest="csv_rows") optparser.add_option("--server", default="review.openstack.org", help="Gerrit server to connect to") options, args = optparser.parse_args() if options.stable: projects = utils.get_projects_info("projects/stable.json", False) else: projects = utils.get_projects_info(options.project, options.all) if not projects: print "Please specify a project." sys.exit(1) reviewers = {} now = datetime.datetime.utcnow() cut_off = now - datetime.timedelta(days=options.days) ts = calendar.timegm(cut_off.timetuple()) now_ts = calendar.timegm(now.timetuple()) change_stats = {"patches": 0, "created": 0, "involved": 0, "merged": 0, "abandoned": 0, "wip": 0} for project in projects: changes = utils.get_changes([project], options.user, options.key, stable=options.stable, server=options.server) for change in changes: patch_for_change = False first_patchset = True for patchset in change.get("patchSets", []): process_patchset(project, patchset, reviewers, ts, options) age = utils.get_age_of_patch(patchset, now_ts) if (now_ts - age) > ts: change_stats["patches"] += 1 patch_for_change = True if first_patchset: change_stats["created"] += 1 first_patchset = False if patch_for_change: change_stats["involved"] += 1 if change["status"] == "MERGED": change_stats["merged"] += 1 elif change["status"] == "ABANDONED": change_stats["abandoned"] += 1 elif change["status"] == "WORKINPROGRESS": change_stats["wip"] += 1 reviewers = [(v, k) for k, v in reviewers.iteritems() if k.lower() not in ("jenkins", "smokestack")] reviewers.sort(reverse=True, key=lambda r: r[0]["total"]) # Do logical processing of reviewers. reviewer_data = [] totals = {"all": 0, "core": 0} for k, v in reviewers: in_core_team = False for project in projects: if v in utils.get_core_team(project, options.server, options.user, options.password): in_core_team = True break name = "%s%s" % (v, " **" if in_core_team else "") plus = float(k["votes"]["2"] + k["votes"]["1"]) minus = float(k["votes"]["-2"] + k["votes"]["-1"]) all_reviews = plus + minus ratio = ((plus / (all_reviews)) * 100) if all_reviews > 0 else 0 r = ( k["total"], k["votes"]["-2"], k["votes"]["-1"], k["votes"]["1"], k["votes"]["2"], k["votes"]["A"], "%5.1f%%" % ratio, ) dratio = ((float(k["disagreements"]) / all_reviews) * 100) if all_reviews else 0.0 d = (k["disagreements"], "%5.1f%%" % dratio) sratio = (float(k["total"]) / k["received"]) * 100 if k["received"] else 0 s = (k["received"], "%5.1f%%" % sratio if k["received"] else "inf") reviewer_data.append((name, r, d, s)) totals["all"] += k["total"] if in_core_team: totals["core"] += k["total"] # And output. writers = {"csv": write_csv, "txt": write_pretty} if options.output == "-": if len(options.outputs) != 1: raise Exception("Can only output one format to stdout.") for output in options.outputs: if options.output == "-": file_obj = sys.stdout on_done = None else: file_obj = open(options.output + "." + output, "wt") on_done = file_obj.close try: writer = writers[output] writer(reviewer_data, file_obj, options, reviewers, projects, totals, change_stats) finally: if on_done: on_done() return 0