Exemplo n.º 1
0
 def GET(self, path):
     page = web.ctx.site.get(path)
     if not page:
         raise web.seeother(path)
     i = web.input(page=0)
     offset = 20 * safeint(i.page)
     limit = 20
     history = get_changes(dict(key=path, limit=limit, offset=offset))
     return render.history(page, history)
Exemplo n.º 2
0
 def GET(self, path):
     page = web.ctx.site.get(path)
     if not page:
         raise web.seeother(path)
     i = web.input(page=0)
     offset = 20 * safeint(i.page)
     limit = 20
     history = get_changes(dict(key=path, limit=limit, offset=offset))
     return render.history(page, history)
Exemplo 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(
        '-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)
Exemplo n.º 4
0
def proposals():
    proposals_ = get_proposals()
    for p in proposals_:
        c = get_changes(p['id'])
        adds = 0
        rems = 0;
        subs = []
        for x in c:
            if x['type'] == 'addition':
                adds += 1
            else:
                rems += 1
            s = {'subject': x['subject'], 'ontology': get_prefix_from_uri(x['context'])}
            if s not in subs:
                subs.append(s)
        p['additions'] = adds
        p['removals'] = rems
        p['subjects'] = subs
    return render_template('proposals.html', proposals=proposals_)
Exemplo 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='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)
Exemplo n.º 6
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
Exemplo n.º 7
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
Exemplo 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(
        '-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)
Exemplo n.º 9
0
for mod in __all__:
    models[mod] = importlib.import_module('models.' + mod).model


print('Imported Models: {}'.format(__all__))




#################################
# MONITOR FOR NEW CHANGES TO PACS
# monitors every 1 second
#################################

# get last change Seq # to set start point of loop
n_last = get_changes('last')['Last']

while True:
    changes = get_changes('since={}'.format(n_last))

    for item in changes['Changes']:
        if item['ChangeType'] == 'NewStudy':
            study = get_study(item['ID'])
            print('-'*50)
            print('PROCESSING STUDY: ' + item['ID'])
            print('Accession: ' + study.get('MainDicomTags').get('AccessionNumber'))
            print('-'*50)

            # wait until study "is stable" (i.e. has not recieved new instances in a while)
            ##Waits 1 min (can be configured) to see if a new instance will upload
            while study['IsStable'] == False:
Exemplo n.º 10
0
                     '--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]

cut_off = datetime.datetime.now() - datetime.timedelta(days=options.days)
ts = calendar.timegm(cut_off.timetuple())
reviews = filter(lambda x: x['grantedOn'] > ts, reviews)


def round_to_day(ts):
Exemplo n.º 11
0
def post_receive(sBZUrl,
                 sBZUser=None,
                 sBZPasswd=None,
                 sFormatSpec=None,
                 oBugRegex=None,
                 sSeparator=None,
                 logger=None,
                 bz_init=None,
                 sRefPrefix=None,
                 bIncludeDiffStat=True,
                 aasPushes=None):
    """
  a post-recieve hook handler which extracts bug ids and adds the commit
  info to the comment. If multiple bug ids are found, the comment is added
  to each of those bugs.

  sBZUrl is the base URL for the Bugzilla installation. If sBZUser and
  sBZPasswd are None, then it uses the ~/.bugz_cookie cookiejar.

  oBugRegex specifies the regex used to search for the bug id in the commit
  messages. It MUST provide a named group called 'bug' which contains the bug
  id (all digits only). If oBugRegex is None, a default bug regex is used,
  which is:

      r"bug\s*(?:#|)\s*(?P<bug>\d+)"

  This matches forms such as:
    - bug 123
    - bug #123
    - BUG # 123
    - Bug#123
    - bug123

  The format spec is appended to "--pretty=format:" and passed to
  "git whatchanged". See the git whatchanged manpage for more info on the
  format spec. Newlines are automatically converted to the "--pretty"
  equivalent, which is '%n'.

  If sFormatSpec is None, a default format spec is used.

  The separator is a string that would never occur in a commit message.
  If sSeparator is None, a default separator is used, which should be
  good enough for everyone.

  If a logger is provided, it would be used for all the logging. If logger
  is None, logging will be disabled. The logger must be a Python
  logging.Logger instance.

  The function bz_init(url, username, password) is invoked to instantiate the
  bugz.bugzilla.Bugz instance. If this is None, the default method is used.

  sRefPrefix is the string prefix of the git reference. If a git reference
  does not start with this, its commits will be ignored. 'refs/heads/' by default.

  aasPushes is a list of (sOldRev, sNewRev, sRefName) tuples, for when these
  aren't read from stdin (gerrit integration).
  """
    if sFormatSpec is None:
        sFormatSpec = sDefaultFormatSpec

    if sSeparator is None:
        sSeparator = sDefaultSeparator

    if oBugRegex is None:
        oBugRegex = oDefaultBugRegex

    if logger is None:
        logger = NullLogger

    if bz_init is None:
        bz_init = init_bugzilla

    if sRefPrefix is None:
        sRefPrefix = sDefaultRefPrefix

    oBZ = bz_init(sBZUrl, sBZUser, sBZPasswd)

    def gPushes():
        for sLine in iter(sys.stdin.readline, ""):
            yield sLine.strip().split(" ")

    if not aasPushes:
        aasPushes = gPushes()

    sPrevRev = None
    for asPush in aasPushes:
        (sOldRev, sNewRev, sRefName) = asPush
        if not sRefName.startswith(sRefPrefix):
            logger.debug("ignoring ref: '%s'" % (sRefName, ))
            continue

        if sPrevRev is None:
            sPrevRev = sOldRev
        logger.debug("oldrev: '%s', newrev: '%s'" % (sOldRev, sNewRev))
        asChangeLogs = get_changes(sOldRev, sNewRev, sFormatSpec, sSeparator,
                                   bIncludeDiffStat, sRefName, sRefPrefix)

        for sMessage in asChangeLogs:
            logger.debug("Considering commit:\n%s" % (sMessage, ))
            oMatch = re.search(oBugRegex, sMessage)
            if oMatch is None:
                logger.info("Bug id not found in commit:\n%s" % (sMessage, ))
                continue
            for oMatch in re.finditer(oBugRegex, sMessage):
                iBugId = int(oMatch.group("bug"))
                logger.debug("Found bugid %d" % (iBugId, ))
                try:
                    oBZ.modify(iBugId, comment=sMessage)
                except Exception, e:
                    logger.exception("Could not add comment to bug %d" %
                                     (iBugId, ))
Exemplo n.º 12
0
def update(oBugRegex=None,
           asAllowedStatuses=None,
           sSeparator=None,
           sBZUrl=None,
           sBZUser=None,
           sBZPasswd=None,
           logger=None,
           bz_init=None,
           sRefPrefix=None,
           bRequireBugNumber=True):
    """
  an update hook handler which rejects commits without a bug reference.
  This looks at the sys.argv array, so make sure you don't modify it before
  calling this function.

  oBugRegex specifies the regex used to search for the bug id in the commit
  messages. It MUST provide a named group called 'bug' which contains the bug
  id (all digits only). If oBugRegex is None, a default bug regex is used,
  which is:

      r"bug\s*(?:#|)\s*(?P<bug>\d+)"

  This matches forms such as:
    - bug 123
    - bug #123
    - BUG # 123
    - Bug#123
    - bug123

  asAllowedStatuses is an array containing allowed statuses for the found
  bugs. If a bug is not in one of these states, the commit will be rejected.
  If asAllowedStatuses is None, status checking is diabled.

  The separator is a string that would never occur in a commit message.
  If sSeparator is None, a default separator is used, which should be
  good enough for everyone.

  sBZUrl specifies the base URL for the Bugzilla installation.  sBZUser and
  sBZPasswd are the bugzilla credentials.

  If a logger is provided, it would be used for all the logging. If logger
  is None, logging will be disabled. The logger must be a Python
  logging.Logger instance.

  The function bz_init(url, username, password) is invoked to instantiate the
  bugz.bugzilla.Bugz instance. If this is None, the default method is used.

  sRefPrefix is the string prefix of the git reference. If a git reference
  does not start with this, its commits will be ignored. 'refs/heads/' by default.

  bRequireBugNumber, if True, requires that a bug number appears in the
  commit message (otherwise it will be rejected).
  """
    if oBugRegex is None:
        oBugRegex = oDefaultBugRegex

    if sSeparator is None:
        sSeparator = sDefaultSeparator

    if logger is None:
        logger = NullLogger

    if bz_init is None:
        bz_init = init_bugzilla

    if sRefPrefix is None:
        sRefPrefix = sDefaultRefPrefix

    sFormatSpec = sDefaultFormatSpec

    if asAllowedStatuses is not None:
        # sanity checking
        if sBZUrl is None:
            raise ValueError("Bugzilla info required for status checks")

    # create and cache bugzilla instance
    oBZ = bz_init(sBZUrl, sBZUser, sBZPasswd)
    # check auth
    try:
        oBZ.auth()
    except:
        logger.error("Could not login to Bugzilla", exc_info=1)
        notify_and_exit(
            "Could not login to Bugzilla. Check your auth details and settings"
        )

    (sRefName, sOldRev, sNewRev) = sys.argv[1:4]
    if not sRefName.startswith(sRefPrefix):
        logger.debug("ignoring ref: '%s'" % (sRefName, ))
        return

    logger.debug("oldrev: '%s', newrev: '%s'" % (sOldRev, sNewRev))

    asChangeLogs = get_changes(sOldRev, sNewRev, sFormatSpec, sSeparator,
                               False, sRefName, sRefPrefix)

    for sMessage in asChangeLogs:
        logger.debug("Checking for bug refs in commit:\n%s" % (sMessage, ))
        oMatch = re.search(oBugRegex, sMessage)
        if oMatch is None:
            if bRequireBugNumber:
                logger.error("No bug ref found in commit:\n%s" % (sMessage, ))
                notify_and_exit("No bug ref found in commit:\n%s" %
                                (sMessage, ))
            else:
                logger.debug("No bug ref found, but none required.")
        else:
            if asAllowedStatuses is not None:
                # check all bug statuses
                for oMatch in re.finditer(oBugRegex, sMessage):
                    iBugId = int(oMatch.group("bug"))
                    logger.debug("Found bug id %d" % (iBugId, ))
                    try:
                        sStatus = get_bug_status(oBZ, iBugId)
                        if sStatus is None:
                            notify_and_exit("Bug %d does not exist" %
                                            (iBugId, ))
                    except Exception, e:
                        logger.exception("Could not get status for bug %d" %
                                         (iBugId, ))
                        notify_and_exit("Could not get staus for bug %d" %
                                        (iBugId, ))

                    logger.debug("status for bug %d is %s" % (iBugId, sStatus))
                    if sStatus not in asAllowedStatuses:
                        logger.info(
                            "Cannot accept commit for bug %d in state %s" %
                            (iBugId, sStatus))
                        notify_and_exit("Bug %d['%s'] is not in %s" %
                                        (iBugId, sStatus, asAllowedStatuses))
Exemplo n.º 13
0
optparser.add_option('-n', '--no-stable', action='store_true',
        help='Exclude changesets for stable branch)')
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)')

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())

def sec_to_period_string(seconds):
    days = seconds / (3600 * 24)
    hours = (seconds / 3600) - (days * 24)
    minutes = (seconds / 60) - (days * 24 * 60) - (hours * 60)
    return '%d days, %d hours, %d minutes' % (days, hours, minutes)


Exemplo n.º 14
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
Exemplo n.º 15
0
def update(
    oBugRegex=None,
    bRequireBugNumber=True,
    asAllowedStatuses=None,
    sSeparator=None,
    sBZUrl=None,
    sBZUser=None,
    sBZPasswd=None,
    logger=None,
    bz_init=None,
    sRefPrefix=None,
):
    """
  an update hook handler which rejects commits without a bug reference.
  This looks at the sys.argv array, so make sure you don't modify it before
  calling this function.

  oBugRegex specifies the regex used to search for the bug id in the commit
  messages. It MUST provide a named group called 'bug' which contains the bug
  id (all digits only). If oBugRegex is None, a default bug regex is used,
  which is:

      r"bug\s*(?:#|)\s*(?P<bug>\d+)"

  This matches forms such as:
    - bug 123
    - bug #123
    - BUG # 123
    - Bug#123
    - bug123

  bRequireBugNumber, if True, requires that a bug number appears in the
  commit message (otherwise it will be rejected).

  asAllowedStatuses is an array containing allowed statuses for the found
  bugs. If a bug is not in one of these states, the commit will be rejected.
  If asAllowedStatuses is None, status checking is diabled.

  The separator is a string that would never occur in a commit message.
  If sSeparator is None, a default separator is used, which should be
  good enough for everyone.

  sBZUrl specifies the base URL for the Bugzilla installation.  sBZUser and
  sBZPasswd are the bugzilla credentials.

  If a logger is provided, it would be used for all the logging. If logger
  is None, logging will be disabled. The logger must be a Python
  logging.Logger instance.

  The function bz_init(url, username, password) is invoked to instantiate the
  bugz.bugzilla.Bugz instance. If this is None, the default method is used.
  
  sRefPrefix is the string prefix of the git reference. If a git reference
  does not start with this, its commits will be ignored. 'refs/heads/' by default.
  """
    if oBugRegex is None:
        oBugRegex = oDefaultBugRegex

    if sSeparator is None:
        sSeparator = sDefaultSeparator

    if logger is None:
        logger = NullLogger

    if bz_init is None:
        bz_init = init_bugzilla

    if sRefPrefix is None:
        sRefPrefix = sDefaultRefPrefix

    sFormatSpec = sDefaultFormatSpec

    if asAllowedStatuses is not None:
        # sanity checking
        if sBZUrl is None:
            raise ValueError("Bugzilla info required for status checks")

    # create and cache bugzilla instance
    oBZ = bz_init(sBZUrl, sBZUser, sBZPasswd)
    # check auth
    try:
        oBZ.auth()
    except:
        logger.error("Could not login to Bugzilla", exc_info=1)
        notify_and_exit("Could not login to Bugzilla. Check your auth details and settings")

    (sRefName, sOldRev, sNewRev) = sys.argv[1:4]
    if not sRefName.startswith(sRefPrefix):
        logger.debug("ignoring ref: '%s'" % (sRefName,))
        return

    logger.debug("oldrev: '%s', newrev: '%s'" % (sOldRev, sNewRev))

    asChangeLogs = get_changes(sOldRev, sNewRev, sFormatSpec, sSeparator)

    for sMessage in asChangeLogs:
        logger.debug("Checking for bug refs in commit:\n%s" % (sMessage,))
        oMatch = re.search(oBugRegex, sMessage)
        if oMatch is None:
            if bRequireBugNumber:
                logger.error("No bug ref found in commit:\n%s" % (sMessage,))
                notify_and_exit("No bug ref found in commit:\n%s" % (sMessage,))
            else:
                logger.debug("No bug ref found, but none required.")
        else:
            if asAllowedStatuses is not None:
                # check all bug statuses
                for oMatch in re.finditer(oBugRegex, sMessage):
                    iBugId = int(oMatch.group("bug"))
                    logger.debug("Found bug id %d" % (iBugId,))
                    try:
                        sStatus = get_bug_status(oBZ, iBugId)
                        if sStatus is None:
                            notify_and_exit("Bug %d does not exist" % (iBugId,))
                    except Exception, e:
                        logger.exception("Could not get status for bug %d" % (iBugId,))
                        notify_and_exit("Could not get staus for bug %d" % (iBugId,))

                    logger.debug("status for bug %d is %s" % (iBugId, sStatus))
                    if sStatus not in asAllowedStatuses:
                        logger.info("Cannot accept commit for bug %d in state %s" % (iBugId, sStatus))
                        notify_and_exit("Bug %d['%s'] is not in %s" % (iBugId, sStatus, asAllowedStatuses))
Exemplo n.º 16
0
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:
    if 'rowCount' in change:
        continue
    latest_patch = change['patchSets'][-1]
    waiting_for_review = True
    for review in latest_patch.get('approvals', []):
        if review['type'] == 'CRVW' and (review['value'] != '-1' or
                                         review['value'] == '-2'):
Exemplo n.º 17
0
def post_receive(
    sBZUrl,
    sBZUser=None,
    sBZPasswd=None,
    sFormatSpec=None,
    oBugRegex=None,
    sSeparator=None,
    logger=None,
    bz_init=None,
    sRefPrefix=None,
):
    """
  a post-recieve hook handler which extracts bug ids and adds the commit
  info to the comment. If multiple bug ids are found, the comment is added
  to each of those bugs.

  sBZUrl is the base URL for the Bugzilla installation. If sBZUser and
  sBZPasswd are None, then it uses the ~/.bugz_cookie cookiejar.

  oBugRegex specifies the regex used to search for the bug id in the commit
  messages. It MUST provide a named group called 'bug' which contains the bug
  id (all digits only). If oBugRegex is None, a default bug regex is used,
  which is:

      r"bug\s*(?:#|)\s*(?P<bug>\d+)"

  This matches forms such as:
    - bug 123
    - bug #123
    - BUG # 123
    - Bug#123
    - bug123

  The format spec is appended to "--pretty=format:" and passed to
  "git whatchanged". See the git whatchanged manpage for more info on the
  format spec.

  If sFormatSpec is None, a default format spec is used.

  The separator is a string that would never occur in a commit message.
  If sSeparator is None, a default separator is used, which should be
  good enough for everyone.

  If a logger is provided, it would be used for all the logging. If logger
  is None, logging will be disabled. The logger must be a Python
  logging.Logger instance.

  The function bz_init(url, username, password) is invoked to instantiate the
  bugz.bugzilla.Bugz instance. If this is None, the default method is used.
  
  sRefPrefix is the string prefix of the git reference. If a git reference
  does not start with this, its commits will be ignored. 'refs/heads/' by default.
  """
    if sFormatSpec is None:
        sFormatSpec = sDefaultFormatSpec

    if sSeparator is None:
        sSeparator = sDefaultSeparator

    if oBugRegex is None:
        oBugRegex = oDefaultBugRegex

    if logger is None:
        logger = NullLogger

    if bz_init is None:
        bz_init = init_bugzilla

    if sRefPrefix is None:
        sRefPrefix = sDefaultRefPrefix

    oBZ = bz_init(sBZUrl, sBZUser, sBZPasswd)

    sPrevRev = None
    for sLine in iter(sys.stdin.readline, ""):
        (sOldRev, sNewRev, sRefName) = sLine.strip().split(" ")
        if not sRefName.startswith(sRefPrefix):
            logger.debug("ignoring ref: '%s'" % (sRefName,))
            continue

        if sPrevRev is None:
            sPrevRev = sOldRev
        logger.debug("oldrev: '%s', newrev: '%s'" % (sOldRev, sNewRev))
        asChangeLogs = get_changes(sOldRev, sNewRev, sFormatSpec, sSeparator)

        for sMessage in asChangeLogs:
            logger.debug("Considering commit:\n%s" % (sMessage,))
            oMatch = re.search(oBugRegex, sMessage)
            if oMatch is None:
                logger.info("Bug id not found in commit:\n%s" % (sMessage,))
                continue
            for oMatch in re.finditer(oBugRegex, sMessage):
                iBugId = int(oMatch.group("bug"))
                logger.debug("Found bugid %d" % (iBugId,))
                try:
                    oBZ.modify(iBugId, comment=sMessage)
                except Exception, e:
                    logger.exception("Could not add comment to bug %d" % (iBugId,))
Exemplo n.º 18
0
        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]

cut_off = datetime.datetime.now() - datetime.timedelta(days=options.days)
ts = calendar.timegm(cut_off.timetuple())
reviews = filter(lambda x:x['grantedOn'] > ts, reviews)

def round_to_day(ts):
    SECONDS_PER_DAY = 60*60*24