Ejemplo n.º 1
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')
    options, args = optparser.parse_args()

    projects = utils.get_projects_info(options.project, options.all)

    if not projects:
        print "Please specify a project."
        sys.exit(1)

    changes = utils.get_changes(projects, options.user, options.key,
                                only_open=True)

    approved_and_rebased = set()
    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
        for patch_set in change['patchSets'][:-1]:
            if (utils.patch_set_approved(patch_set)
                    and not utils.patch_set_approved(change['patchSets'][-1])):
                if has_negative_feedback(change['patchSets'][-1]):
                    continue
                approved_and_rebased.add("%s %s" % (change['url'],
                                                    change['subject']))

    for x in approved_and_rebased:
        print x
    print "total %d" % len(approved_and_rebased)
Ejemplo n.º 2
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='russellb', 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')

    options, args = optparser.parse_args()

    projects = utils.get_projects_info(options.project, options.all)

    if not projects:
        print "Please specify a project."
        sys.exit(1)

    changes = utils.get_changes(projects, options.user, options.key,
            only_open=True)

    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]
        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'):
                continue
            if review['value'] in ('-1', '-2'):
                waiting_for_review = False
                break

        change['age'] = get_age_of_patch(latest_patch, now_ts)
        change['age2'] = get_age_of_patch(change['patchSets'][0], now_ts)
        patch = find_oldest_no_nack(change)
        change['age3'] = 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)

    age_sorted = sorted(waiting_on_reviewer, key=lambda change: change['age'])

    age2_sorted = sorted(waiting_on_reviewer, key=lambda change: change['age2'])

    age3_sorted = sorted(waiting_on_reviewer, key=lambda change: change['age3'])

    stats = gen_stats(projects, waiting_on_reviewer, waiting_on_submitter,
                age_sorted, age2_sorted, age3_sorted, options)

    if options.html:
        print_stats_html(stats)
    else:
        print_stats_txt(stats)
Ejemplo n.º 3
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('-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')

    options, args = optparser.parse_args()

    projects = utils.get_projects_info(options.project, options.all)

    if not projects:
        print "Please specify a project."
        sys.exit(1)

    reviewers = {}

    cut_off = datetime.datetime.now() - datetime.timedelta(days=options.days)
    ts = calendar.timegm(cut_off.timetuple())

    for project in projects:
        changes = utils.get_changes([project], options.user, options.key)
        for change in changes:
            for patchset in change.get('patchSets', []):
                process_patchset(project, patchset, reviewers, ts)

    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'])

    if options.all:
        print 'Reviews for the last %d days in projects: %s' % (options.days,
                [project['name'] for project in projects])
    else:
        print 'Reviews for the last %d days in %s' % (options.days, projects[0]['name'])
    if options.all:
        print '** -- Member of at least one core reviewer team'
    else:
        print '** -- %s-core team member' % projects[0]['name']
    table = prettytable.PrettyTable(
            ('Reviewer',
             'Reviews   -2  -1  +1  +2    +/- %',
             'Disagreements*'))
    total = 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'])
        ratio = (plus / (plus + minus)) * 100
        r = '%7d  %3d %3d %3d %3d   %5.1f%%' % (k['total'],
                k['votes']['-2'], k['votes']['-1'],
                k['votes']['1'], k['votes']['2'], ratio)
        dratio = ((float(k['disagreements']) / plus) * 100) if plus else 0.0
        d = '%3d (%5.1f%%)' % (k['disagreements'], dratio)
        table.add_row((name, r, d))
        total += k['total']
    print table
    print '\nTotal reviews: %d' % total
    print 'Total reviewers: %d' % len(reviewers)
    print '\n(*) Disagreements are defined as a +1 or +2 vote on a patch ' \
          'where a core team member later gave a -1 or -2 vote, or a ' \
          'negative vote overridden with a postive one afterwards.'

    return 0
Ejemplo n.º 4
0
def main():
    parser = ArgumentParser(
        description="Get reviews for open bugs against a milestone")
    parser.add_argument(
        '-p', '--project', default='projects/nova.json',
        help='JSON file describing the project to generate stats for')
    parser.add_argument(
        '-m', '--milestone', default='',
        help='Only show bugs targeted to a specified milestone')
    parser.add_argument(
        '-u', '--user', default=getpass.getuser(), help='gerrit user')
    parser.add_argument('-k', '--key', default=None, help='ssh key for gerrit')

    args = parser.parse_args()

    projects = utils.get_projects_info(args.project, False)
    project_name = projects[0]['name']

    if not projects:
        print "Please specify a project."
        return 1

    launchpad = Launchpad.login_with('openstack-releasing', 'production')
    proj = launchpad.projects[project_name]
    statuses = ['New', 'Incomplete', 'Confirmed', 'Triaged', 'In Progress']
    if args.milestone:
        milestone = proj.getMilestone(name=args.milestone)
        bugtasks = proj.searchTasks(status=statuses, milestone=milestone)
    else:
        bugtasks = proj.searchTasks(status=statuses)
    bugs_by_id = {}
    for bt in bugtasks:
        bugs_by_id[str(bt.bug.id)] = bt

    milestones = {}

    changes = utils.get_changes(projects, args.user, args.key, only_open=True)
    bug_regex = re.compile('bug/(\d+)')
    for change in changes:
        if 'topic' not in change:
            continue
        match = bug_regex.match(change['topic'])
        if not match:
            continue
        bugid = match.group(1)
        try:
            bugtask = bugs_by_id[bugid]
            milestone = str(bugtask.milestone).split('/')[-1]
            if milestone == 'None':
                milestone = 'Untargeted'
        except KeyError:
            milestone = 'Bug does not exist for this project'

        milestones.setdefault(milestone, [])
        milestones[milestone].append((change['url'], bugid))

    print 'Reviews for bugs grouped by milestone for project: %s\n' % (
        project_name)

    for milestone, reviews in milestones.items():
        if args.milestone and milestone != args.milestone:
            continue
        print 'Milestone: %s' % milestone
        for review, bugid in reviews:
            print '--> %s -- https://bugs.launchpad.net/%s/+bug/%s' \
                % (review, project_name, bugid)
        print
Ejemplo n.º 5
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'] = get_age_of_patch(latest_patch, now_ts)
        change['age2'] = get_age_of_patch(change['patchSets'][0], now_ts)
        patch = find_oldest_no_nack(change)
        change['age3'] = 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)
Ejemplo n.º 6
0
import sys

import utils


optparser = optparse.OptionParser()
optparser.add_option('-p', '--project', default='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='russellb', help='gerrit user')
optparser.add_option('-k', '--key', default=None, help='ssh key for gerrit')

options, args = optparser.parse_args()

projects = utils.get_projects_info(options.project, options.all)

if not projects:
    print "Please specify a project."
    sys.exit(1)

changes = utils.get_changes(projects, options.user, options.key,
        only_open=True)

waiting_on_submitter = []
waiting_on_reviewer = []

now = datetime.datetime.utcnow()
now_ts = calendar.timegm(now.timetuple())

for change in changes:
Ejemplo n.º 7
0
    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('-d',
                     '--days',
                     type='int',
                     default=14,
                     help='Number of days to consider')
optparser.add_option('-u', '--user', default='russellb', help='gerrit user')
optparser.add_option('-k', '--key', default=None, help='ssh key for gerrit')

options, args = optparser.parse_args()

projects = utils.get_projects_info(options.project, options.all)

if not projects:
    print "Please specify a project."
    sys.exit(1)

all_changes = utils.get_changes(projects, options.user, options.key)

reviews = []

for change in all_changes:
    #    print json.dumps(change, sort_keys=True, indent=4)
    for patchset in change.get('patchSets', []):
        for review in patchset.get('approvals', []):
            reviews += [review]
Ejemplo n.º 8
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(
        '-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')

    options, args = optparser.parse_args()

    projects = utils.get_projects_info(options.project, options.all)

    if not projects:
        print "Please specify a project."
        sys.exit(1)

    reviewers = {}

    cut_off = datetime.datetime.now() - datetime.timedelta(days=options.days)
    ts = calendar.timegm(cut_off.timetuple())

    for project in projects:
        changes = utils.get_changes([project], options.user, options.key)
        for change in changes:
            for patchset in change.get('patchSets', []):
                process_patchset(project, patchset, reviewers, ts)

    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 = []
    total = 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'])
        ratio = ((plus / (plus + minus)) * 100) if plus + minus > 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']) / plus) * 100) if plus else 0.0
        d = (k['disagreements'], "%5.1f%%" % dratio)
        reviewer_data.append((name, r, d))
        total += 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]
            if options.all:
                file_obj.write(
                    'Reviews for the last %d days in projects: %s\n' %
                    (options.days, [project['name'] for project in projects]))
            else:
                file_obj.write('Reviews for the last %d days in %s\n'
                    % (options.days, projects[0]['name']))
            if options.all:
                file_obj.write(
                    '** -- Member of at least one core reviewer team\n')
            else:
                file_obj.write(
                    '** -- %s-core team member\n' % projects[0]['name'])
            writer(reviewer_data, file_obj)
            file_obj.write('\nTotal reviews: %d\n' % total)
            file_obj.write('Total reviewers: %d\n' % len(reviewers))
            file_obj.write(
                '\n(*) Disagreements are defined as a +1 or +2 vote on a ' \
                'patch where a core team member later gave a -1 or -2 vote' \
                ', or a negative vote overridden with a positive one ' \
                'afterwards.\n')
        finally:
            if on_done:
                on_done()
    return 0