Example #1
0
def main():
    load_config()
    print "Calculating F11 0day update metrics..."
    updates = {
        'bugfix': [],
        'security': [],
        'enhancement': [],
        'newpackage': []
    }
    date = datetime(*time.strptime('06-09-2009', '%m-%d-%Y')[:-2])
    f11 = Release.byName('F11')
    for update in PackageUpdate.select(PackageUpdate.q.releaseID == f11.id):
        for comment in update.comments:
            if comment.author == 'bodhi' and comment.timestamp < date and \
               comment.text.startswith('This update has been pushed to stable'):
                updates[update.type].append(update.title)
                break

    pprint(updates)
    print '=' * 80
    print 'F11 0day stats'
    print ' * %d security' % len(updates['security'])
    print ' * %d bugfixes' % len(updates['bugfix'])
    print ' * %d enhancements' % len(updates['enhancement'])
    print ' * %d newpackage' % len(updates['newpackage'])
Example #2
0
def main():
    load_config()
    __connection__ = hub = PackageHub("bodhi")
    if len(sys.argv) != 2:
        print "Usage: %s <release>" % sys.argv[0]
        sys.exit(1)
    try:
        release = Release.byName(sys.argv[1].upper())
    except SQLObjectNotFound:
        print "Cannot find Release '%s'" % sys.argv[1]
        sys.exit(1)

    updates = PackageUpdate.select(PackageUpdate.q.releaseID == release.id)
    progress = ProgressBar(maxValue=updates.count())
    print "Destroying all updates, comments, and bugs associated with %s" % release.name

    for update in updates:
        for comment in update.comments:
            comment.destroySelf()
        for build in update.builds:
            build.destroySelf()
        for bug in update.bugs:
            if len(bug.updates) == 1:
                bug.destroySelf()
        update.destroySelf()
        progress()

    release.destroySelf()
    hub.commit()
    print
Example #3
0
def main():
    """ Initialize the package/release/multilib tables """
    print "Initializing Bodhi\n"
    load_config()
    hub.begin()
    clean_tables()
    if releases:
        import_releases()
    import_rebootpkgs()
    hub.commit()
Example #4
0
def main():
    load_config()
    hub.begin()

    try:
        print "\nCreating guest user and giving it administrator priviliges"
        guest = User(user_name="guest", display_name="Bodhi Hacker", password="******")
        admin = Group(group_name="releng", display_name="Bodhi administrators")
        guest.addGroup(admin)
        hub.commit()
    except DuplicateEntryError:
        print "guest account already created"
Example #5
0
def main():
    load_config()
    hub.begin()

    try:
        print "\nCreating guest user and giving it administrator priviliges"
        guest = User(user_name='guest',
                     display_name='Bodhi Hacker',
                     password='******')
        admin = Group(group_name='releng', display_name='Bodhi administrators')
        guest.addGroup(admin)
        hub.commit()
    except DuplicateEntryError:
        print "guest account already created"
Example #6
0
def main():
    load_config()
    if len(sys.argv) < 2:
        usage()
    elif sys.argv[1] == "save":
        print "Pickling database..."
        save_db()
    elif sys.argv[1] == "load" and len(sys.argv) == 3:
        try:
            hub.begin()
            load_db()
        finally:
            hub.commit()
    else:
        usage()
Example #7
0
def main():
    load_config()
    if len(sys.argv) < 2:
        usage()
    elif sys.argv[1] == 'save':
        print "Pickling database..."
        save_db()
    elif sys.argv[1] == 'load' and len(sys.argv) == 3:
        try:
            hub.begin()
            load_db()
        finally:
            hub.commit()
    else:
        usage()
Example #8
0
def start():
    '''Start the CherryPy application server.'''
    if len(sys.argv) > 1:
        load_config(sys.argv[1])
    else:
        load_config()

    from fedora.tg.util import enable_csrf
    if turbogears.config.get('identity.provider') in ('sqlobjectcsrf', 'jsonfas2'):
        turbogears.startup.call_on_startup.append(enable_csrf)

    ## Schedule our periodic tasks
    from bodhi import jobs
    turbogears.startup.call_on_startup.append(jobs.schedule)

    from bodhi.controllers import Root
    turbogears.start_server(Root())
Example #9
0
def main():
    load_config()
    print "Calculating F11 0day update metrics..."
    updates = {'bugfix': [], 'security': [], 'enhancement': [], 'newpackage': []}
    date = datetime(*time.strptime('06-09-2009', '%m-%d-%Y')[:-2])
    f11 = Release.byName('F11')
    for update in PackageUpdate.select(PackageUpdate.q.releaseID==f11.id):
        for comment in update.comments:
            if comment.author == 'bodhi' and comment.timestamp < date and \
               comment.text.startswith('This update has been pushed to stable'):
                updates[update.type].append(update.title)
                break

    pprint(updates)
    print '=' * 80
    print 'F11 0day stats'
    print ' * %d security' % len(updates['security'])
    print ' * %d bugfixes' % len(updates['bugfix'])
    print ' * %d enhancements' % len(updates['enhancement'])
    print ' * %d newpackage' % len(updates['newpackage'])
Example #10
0
def main():
    load_config()
    __connection__ = hub = PackageHub("bodhi")
    koji = get_session()
    tasks = []
    broke = set()

    # Clean up any stray pending tags
    for release in Release.select():
        print "Finding all pending-testing builds..."
        if release.name.startswith('EL'):
            continue

        tag = release.pending_testing_tag
        tagged = [build['nvr'] for build in koji.listTagged(tag)]
        for nvr in tagged:
            try:
                build = PackageBuild.byNvr(nvr)
                for update in build.updates:
                    if update.status in ('testing', 'stable', 'obsolete'):
                        print "%s %s" % (nvr, update.status)
                        if '--fix' in sys.argv:
                            print "Untagging %s" % nvr
                            koji.untagBuild(tag, nvr, force=True)
            except SQLObjectNotFound:
                print "Can't find build for %s" % nvr
                if '--fix' in sys.argv:
                    print "Untagging %s" % nvr
                    koji.untagBuild(tag, nvr, force=True)

        tag = release.pending_stable_tag
        tagged = [build['nvr'] for build in koji.listTagged(tag)]
        for nvr in tagged:
            try:
                build = PackageBuild.byNvr(nvr)
                for update in build.updates:
                    if update.status in ('pending', 'obsolete', 'stable'):
                        print "%s %s" % (nvr, update.status)
                        if '--fix' in sys.argv:
                            print "Untagging %s" % nvr
                            koji.untagBuild(tag, nvr, force=True)
            except SQLObjectNotFound:
                print "Can't find build for %s" % nvr
                if '--fix' in sys.argv:
                    print "Untagging %s" % nvr
                    koji.untagBuild(tag, nvr, force=True)

    # Check for testing updates that aren't tagged properly
    for update in PackageUpdate.select(PackageUpdate.q.status == 'testing'):
        dest_tag = update.release.testing_tag
        for build in update.builds:
            tags = [tag['name'] for tag in koji.listTags(build=build.nvr)]
            if dest_tag not in tags:
                print "%s marked as testing, but tagged with %s" % (build.nvr,
                                                                    tags)
                if '--fix' in sys.argv:
                    broke.add((tags[0], dest_tag, build.nvr))

    # Check all candidate updates to see if they are in a different bodhi state
    for release in Release.select():
        tag = release.candidate_tag
        tagged = [build['nvr'] for build in koji.listTagged(tag, latest=True)]
        for nvr in tagged:
            try:
                build = PackageBuild.byNvr(nvr)
                for update in build.updates:
                    if update.status in ('testing', 'stable'):
                        print "%s %s but tagged as %s" % (nvr, update.status,
                                                          tag)
                        if '--fix' in sys.argv:
                            dest = release.testing_tag
                            if update.status == 'stable':
                                dest = release.stable_tag
                            elif update.status == 'obsolete':
                                dest = release.candidate_tag
                            broke.add((tag, dest, nvr))
            except SQLObjectNotFound:
                pass

    # Make sure that all builds in koji tagged as an update exist
    # in bodhi, and are in the expect state.
    for release in Release.select():
        for tag in (release.testing_tag, release.stable_tag):
            tagged = [
                build['nvr'] for build in koji.listTagged(tag, latest=True)
            ]
            for nvr in tagged:
                try:
                    build = PackageBuild.byNvr(nvr)
                except SQLObjectNotFound:
                    print "PackageUpdate(%s) not found!" % nvr
                    continue
                if not len(build.updates):
                    print "PackageBuild(%s) has no updates" % (build.nvr)
                status = 'testing' in tag and 'testing' or 'stable'
                for update in build.updates:
                    if update.status != status:
                        print "%s is %s in bodhi but tagged as %s in koji" % (
                            update.title, update.status, tag)
                        if '--fix' in sys.argv:
                            dest = release.testing_tag
                            if update.status == 'stable':
                                dest = release.stable_tag
                            elif update.status == 'obsolete':
                                dest = release.candidate_tag
                            for b in update.builds:
                                broke.add((tag, dest, b.nvr))

    if broke:
        print " ** Fixing broken tags! **"
        koji.multicall = True
        for tag, dest, build in broke:
            print "Moving %s from %s to %s" % (build, tag, dest)
            koji.moveBuild(tag, dest, build, force=True)
        print "Running koji.multiCall()"
        results = koji.multiCall()
        success = False
        print "Waiting for tasks"
        bad_tasks = wait_for_tasks([task[0] for task in results])
        if bad_tasks == 0:
            success = True
        if success:
            print "Tags successfully moved!"
        else:
            print "Error moving tags!"
            print "bad_tasks = %r" % bad_tasks
Example #11
0
def main():
    load_config()
    stats = {}  # {release: {'stat': ...}}
    feedback = 0  # total number of updates that received feedback
    karma = defaultdict(int)  # {username: # of karma submissions}
    num_updates = PackageUpdate.select().count()
    proventesters = set()

    for release in Release.select():
        print header(release.long_name)
        updates = PackageUpdate.select(PackageUpdate.q.releaseID==release.id)
        stats[release.name] = {
                'num_updates': updates.count(),
                'num_tested': 0,
                'num_tested_without_karma': 0,
                'num_feedback': 0,
                'num_anon_feedback': 0,
                'num_critpath': 0,
                'num_critpath_approved': 0,
                'num_critpath_unapproved': 0,
                'num_stablekarma': 0,
                'num_testingtime': 0,
                'critpath_without_karma': set(),
                'conflicted_proventesters': [],
                'critpath_positive_karma_including_proventesters': [],
                'critpath_positive_karma_negative_proventesters': [],
                'stable_with_negative_karma': PackageUpdate.select(
                    AND(PackageUpdate.q.releaseID==release.id,
                        PackageUpdate.q.status=='stable',
                        PackageUpdate.q.karma < 0)).count(),
                'bugs': set(),
                'karma': defaultdict(int),
                'deltas': [],
                'occurrences': {},
                'accumulative': timedelta(),
                'packages': defaultdict(int),
                'proventesters': set(),
                'proventesters_1': 0,
                'proventesters_0': 0,
                'proventesters_-1': 0,
                # for tracking number of types of karma
                '1': 0,
                '0': 0,
                '-1': 0,
                }
        data = stats[release.name]

        for status in statuses:
            data['num_%s' % status] = PackageUpdate.select(AND(
                PackageUpdate.q.releaseID==release.id,
                PackageUpdate.q.status==status)).count()

        for type in types:
            data['num_%s' % type] = PackageUpdate.select(AND(
                PackageUpdate.q.releaseID==release.id,
                PackageUpdate.q.type==type)).count()

        for update in release.updates:
            for build in update.builds:
                data['packages'][build.package] += 1
            for bug in update.bugs:
                data['bugs'].add(bug.bz_id)

            feedback_done = False
            testingtime_done = False

            for comment in update.comments:
                if comment.author_name in ('autoqa', 'taskotron'):
                    continue

                # Track the # of +1's, -1's, and +0's.
                if comment.author_name != 'bodhi':
                    data[str(comment.karma)] += 1

                if comment.author_group == 'proventesters':
                    data['proventesters'].add(comment.author_name)
                    data['proventesters_%d' % comment.karma] += 1

                if comment.text == 'This update has reached the stable karma threshold and will be pushed to the stable updates repository':
                    data['num_stablekarma'] += 1
                elif comment.text and comment.text.endswith('days in testing and can be pushed to stable now if the maintainer wishes'):
                    data['num_testingtime'] += 1

                # For figuring out if an update has received feedback or not
                if not feedback_done:
                    if (not comment.author.startswith('bodhi') and
                            comment.karma != 0 and not comment.anonymous):
                        data['num_feedback'] += 1  # per-release tracking of feedback
                        feedback += 1  # total number of updates that have received feedback
                        feedback_done = True  # so we don't run this for each comment

                # Tracking per-author karma & anonymous feedback
                if not comment.author.startswith('bodhi'):
                    if comment.anonymous:
                        # @@: should we track anon +0 comments as "feedback"?
                        if comment.karma != 0:
                            data['num_anon_feedback'] += 1
                    else:
                        author = comment.author_name
                        data['karma'][author] += 1
                        karma[author] += 1

                if (not testingtime_done and
                        comment.text == 'This update has been pushed to testing'):
                    for othercomment in update.comments:
                        if othercomment.text == 'This update has been pushed to stable':
                            delta = othercomment.timestamp - comment.timestamp
                            data['deltas'].append(delta)
                            data['occurrences'][delta.days] = \
                                data['occurrences'].setdefault(
                                        delta.days, 0) + 1
                            data['accumulative'] += delta
                            testingtime_done = True
                            break

            if update.critpath:
                if update.critpath_approved or update.status == 'stable':
                    data['num_critpath_approved'] += 1
                else:
                    if status in ('testing', 'pending'):
                        data['num_critpath_unapproved'] += 1
                data['num_critpath'] += 1
                #if not feedback_done:
                if update.status == 'stable' and update.karma == 0:
                    data['critpath_without_karma'].add(update)

                # Proventester metrics
                proventester_karma = defaultdict(int)  # {username: karma}
                positive_proventesters = 0
                negative_proventesters = 0
                for comment in update.comments:
                    if comment.author_group == 'proventesters':
                        proventester_karma[comment.author_name] += comment.karma
                for _karma in proventester_karma.values():
                    if _karma > 0:
                        positive_proventesters += 1
                    elif _karma < 0:
                        negative_proventesters += 1

                # Conflicting proventesters
                if positive_proventesters and negative_proventesters:
                    data['conflicted_proventesters'] += [short_url(update)]

                # Track updates with overall positive karma, including positive
                # karma from a proventester
                if update.karma > 0 and positive_proventesters:
                    data['critpath_positive_karma_including_proventesters'] += [short_url(update)]

                # Track updates with overall positive karma, including negative
                # karma from a proventester
                if update.karma > 0 and negative_proventesters:
                    data['critpath_positive_karma_negative_proventesters'] += [short_url(update)]

            if testingtime_done:
                data['num_tested'] += 1
                if not feedback_done:
                    data['num_tested_without_karma'] += 1

        data['deltas'].sort()

        print " * %d updates" % data['num_updates']
        print " * %d packages updated" % (len(data['packages']))
        for status in statuses:
            print " * %d %s updates" % (data['num_%s' % status], status)
        for type in types:
            print " * %d %s updates (%0.2f%%)" % (data['num_%s' % type], type,
                    float(data['num_%s' % type]) / data['num_updates'] * 100)
        print " * %d bugs resolved" % len(data['bugs'])
        print " * %d critical path updates (%0.2f%%)" % (data['num_critpath'],
                float(data['num_critpath']) / data['num_updates'] * 100)
        print " * %d approved critical path updates" % (
                data['num_critpath_approved'])
        print " * %d unapproved critical path updates" % (
                data['num_critpath_unapproved'])
        print " * %d updates received feedback (%0.2f%%)" % (
                data['num_feedback'], (float(data['num_feedback']) /
                 data['num_updates'] * 100))
        print " * %d +0 comments" % data['0']
        print " * %d +1 comments" % data['1']
        print " * %d -1 comments" % data['-1']
        print " * %d unique authenticated karma submitters" % (
                len(data['karma']))
        print " * %d proventesters" % len(data['proventesters'])
        print "   * %d +1's from proventesters" % data['proventesters_1']
        print "   * %d -1's from proventesters" % data['proventesters_-1']
        if data['num_critpath']:
            print " * %d critpath updates with conflicting proventesters (%0.2f%% of critpath)" % (len(data['conflicted_proventesters']), float(len(data['conflicted_proventesters'])) / data['num_critpath'] * 100)
            for u in data['conflicted_proventesters']:
                print "   * " + u
            print " * %d critpath updates with positive karma and negative proventester feedback (%0.2f%% of critpath)" % (len(data['critpath_positive_karma_negative_proventesters']), float(len(data['critpath_positive_karma_negative_proventesters'])) / data['num_critpath'] * 100)
            for u in data['critpath_positive_karma_negative_proventesters']:
                print "   * " + u
            print " * %d critpath updates with positive karma and positive proventester feedback (%0.2f%% of critpath)" % (len(data['critpath_positive_karma_including_proventesters']), float(len(data['critpath_positive_karma_including_proventesters'])) / data['num_critpath'] * 100)
        print " * %d anonymous users gave feedback (%0.2f%%)" % (
                data['num_anon_feedback'], float(data['num_anon_feedback']) /
                (data['num_anon_feedback'] + sum(data['karma'].values())) * 100)
# This does not take into account updates that reach stablekarma before being pushed to testing!
#        print " * %d out of %d stable updates went through testing (%0.2f%%)" %(
#                data['num_tested'], data['num_stable'],
#                float(data['num_tested']) / data['num_stable'] * 100)
        print " * %d updates reached the stable karma threshold (%0.2f%%)" % (
                data['num_stablekarma'],
                float(data['num_stablekarma']) / data['num_stable'] * 100)
        print " * %d updates reached the minimum time in testing threshold (%0.2f%%)" % (
                data['num_testingtime'],
                float(data['num_testingtime']) / data['num_stable'] * 100)
        print " * %d went from testing to stable *without* karma (%0.2f%%)" % (
                data['num_tested_without_karma'],
                float(data['num_tested_without_karma']) /
                data['num_tested'] * 100)
        print " * %d updates were pushed to stable with negative karma (%0.2f%%)" % (
                data['stable_with_negative_karma'], float(data['stable_with_negative_karma']) / data['num_stable'] * 100)
        print " * %d critical path updates pushed to stable *without* karma" % (
                len(data['critpath_without_karma']))
        #for update in data['critpath_without_karma']:
        #    print "   * %s submitted by %s" % (update.title, update.submitter)
        print " * Time spent in testing:"
        print "   * mean = %d days" % (data['accumulative'].days /
                len(data['deltas']))
        print "   * median = %d days" % (
                data['deltas'][len(data['deltas']) / 2].days)
        print "   * mode = %d days" % (
                sorted(data['occurrences'].items(), key=itemgetter(1))[-1][0])
        #for package in sorted(data['packages'].items(), key=itemgetter(1), reverse=True):
        #    print "    * %s: %d" % (package[0].name, package[1])
        print

    print
    print "Out of %d total updates, %d received feedback (%0.2f%%)" % (
            num_updates, feedback, (float(feedback) / num_updates * 100))
    print "Out of %d total unique commenters, the top 50 are:" % (
            len(karma))
    for submitter in sorted(karma.iteritems(), key=itemgetter(1), reverse=True)[:50]:
        print " * %s (%d)" % (submitter[0], submitter[1])
Example #12
0
        num_updates = PackageUpdate.select(
                PackageUpdate.q.releaseID==release.id).count()
        num_stable = len(stable_updates[release.name])
        num_unstable = len(unstable_updates[release.name])
        num_testing = len(unstable_deltas) + len(stable_deltas)
        print " * %d updates automatically unpushed due to karma (%0.2f%%)" % (
                num_unstable, float(num_unstable) / num_updates * 100)
        print "   * %d of which were critical path updates" % (
                unstable_critpath[release.name])
        print " * %d updates automatically pushed due to karma (%0.2f%%)" % (
                num_stable, float(num_stable) / num_updates * 100)
        print "   * %d of which were critical path updates" % (
                stable_critpath[release.name])

        print " * Time spent in testing of updates that were pushed by karma:"
        print "   * mean = %d days" % (stable_accum.days / len(stable_deltas))
        print "   * median = %d days" % stable_deltas[len(stable_deltas)/2].days
        print "   * mode = %d days" % sorted(stable_occur.items(),
                                             key=itemgetter(1))[-1][0]

        print " * Time spent in testing of updates that were unpushed by karma:"
        print "   * mean = %d days" % (unstable_accum.days / len(unstable_deltas))
        print "   * median = %d days" % unstable_deltas[len(unstable_deltas)/2].days
        print "   * mode = %d days" % sorted(unstable_occur.items(),
                                             key=itemgetter(1))[-1][0]


if __name__ == '__main__':
    load_config()
    main()
Example #13
0
                    PackageUpdate.q.status == 'testing',
                    PackageUpdate.q.request == None)):
            for build in update.builds:
                if build.nvr not in testing_nvrs:
                    latest_testing = None
                    latest_stable = None
                    for testing in testing_nvrs:
                        if testing.startswith(build.package.name + '-'):
                            latest_testing = testing
                            break
                    for stable in stable_nvrs:
                        if stable.startswith(build.package.name + '-'):
                            latest_stable = stable
                            break
                    if latest_testing:
                        koji_build = koji.getBuild(build.nvr)
                        latest_build = koji.getBuild(latest_testing)
                        if rpm.labelCompare(build_evr(koji_build),
                                            build_evr(latest_build)) < 0:
                            print "%s in testing, latest_testing = %s, latest_stable = %s" % (
                                update.title, latest_testing, latest_stable)
                            if untag:
                                print "Obsoleting %s" % update.title
                                update.obsolete(newer=latest_testing)


if __name__ == '__main__':
    load_config()
    turbomail.start_extension()
    clean_testing_builds('--untag' in sys.argv)
Example #14
0
def main():
    load_config()
    stats = {}  # {release: {'stat': ...}}
    feedback = 0  # total number of updates that received feedback
    karma = defaultdict(int)  # {username: # of karma submissions}
    num_updates = PackageUpdate.select().count()
    proventesters = set()

    for release in Release.select():
        print header(release.long_name)
        updates = PackageUpdate.select(PackageUpdate.q.releaseID == release.id)
        stats[release.name] = {
            'num_updates':
            updates.count(),
            'num_tested':
            0,
            'num_tested_without_karma':
            0,
            'num_feedback':
            0,
            'num_anon_feedback':
            0,
            'num_critpath':
            0,
            'num_critpath_approved':
            0,
            'num_critpath_unapproved':
            0,
            'num_stablekarma':
            0,
            'num_testingtime':
            0,
            'critpath_without_karma':
            set(),
            'conflicted_proventesters': [],
            'critpath_positive_karma_including_proventesters': [],
            'critpath_positive_karma_negative_proventesters': [],
            'stable_with_negative_karma':
            PackageUpdate.select(
                AND(PackageUpdate.q.releaseID == release.id,
                    PackageUpdate.q.status == 'stable',
                    PackageUpdate.q.karma < 0)).count(),
            'bugs':
            set(),
            'karma':
            defaultdict(int),
            'deltas': [],
            'occurrences': {},
            'accumulative':
            timedelta(),
            'packages':
            defaultdict(int),
            'proventesters':
            set(),
            'proventesters_1':
            0,
            'proventesters_0':
            0,
            'proventesters_-1':
            0,
            # for tracking number of types of karma
            '1':
            0,
            '0':
            0,
            '-1':
            0,
        }
        data = stats[release.name]

        for status in statuses:
            data['num_%s' % status] = PackageUpdate.select(
                AND(PackageUpdate.q.releaseID == release.id,
                    PackageUpdate.q.status == status)).count()

        for type in types:
            data['num_%s' % type] = PackageUpdate.select(
                AND(PackageUpdate.q.releaseID == release.id,
                    PackageUpdate.q.type == type)).count()

        for update in release.updates:
            for build in update.builds:
                data['packages'][build.package] += 1
            for bug in update.bugs:
                data['bugs'].add(bug.bz_id)

            feedback_done = False
            testingtime_done = False

            for comment in update.comments:
                if comment.author_name in ('autoqa', 'taskotron'):
                    continue

                # Track the # of +1's, -1's, and +0's.
                if comment.author_name != 'bodhi':
                    data[str(comment.karma)] += 1

                if comment.author_group == 'proventesters':
                    data['proventesters'].add(comment.author_name)
                    data['proventesters_%d' % comment.karma] += 1

                if comment.text == 'This update has reached the stable karma threshold and will be pushed to the stable updates repository':
                    data['num_stablekarma'] += 1
                elif comment.text and comment.text.endswith(
                        'days in testing and can be pushed to stable now if the maintainer wishes'
                ):
                    data['num_testingtime'] += 1

                # For figuring out if an update has received feedback or not
                if not feedback_done:
                    if (not comment.author.startswith('bodhi')
                            and comment.karma != 0 and not comment.anonymous):
                        data[
                            'num_feedback'] += 1  # per-release tracking of feedback
                        feedback += 1  # total number of updates that have received feedback
                        feedback_done = True  # so we don't run this for each comment

                # Tracking per-author karma & anonymous feedback
                if not comment.author.startswith('bodhi'):
                    if comment.anonymous:
                        # @@: should we track anon +0 comments as "feedback"?
                        if comment.karma != 0:
                            data['num_anon_feedback'] += 1
                    else:
                        author = comment.author_name
                        data['karma'][author] += 1
                        karma[author] += 1

                if (not testingtime_done and comment.text
                        == 'This update has been pushed to testing'):
                    for othercomment in update.comments:
                        if othercomment.text == 'This update has been pushed to stable':
                            delta = othercomment.timestamp - comment.timestamp
                            data['deltas'].append(delta)
                            data['occurrences'][delta.days] = \
                                data['occurrences'].setdefault(
                                        delta.days, 0) + 1
                            data['accumulative'] += delta
                            testingtime_done = True
                            break

            if update.critpath:
                if update.critpath_approved or update.status == 'stable':
                    data['num_critpath_approved'] += 1
                else:
                    if status in ('testing', 'pending'):
                        data['num_critpath_unapproved'] += 1
                data['num_critpath'] += 1
                #if not feedback_done:
                if update.status == 'stable' and update.karma == 0:
                    data['critpath_without_karma'].add(update)

                # Proventester metrics
                proventester_karma = defaultdict(int)  # {username: karma}
                positive_proventesters = 0
                negative_proventesters = 0
                for comment in update.comments:
                    if comment.author_group == 'proventesters':
                        proventester_karma[
                            comment.author_name] += comment.karma
                for _karma in proventester_karma.values():
                    if _karma > 0:
                        positive_proventesters += 1
                    elif _karma < 0:
                        negative_proventesters += 1

                # Conflicting proventesters
                if positive_proventesters and negative_proventesters:
                    data['conflicted_proventesters'] += [short_url(update)]

                # Track updates with overall positive karma, including positive
                # karma from a proventester
                if update.karma > 0 and positive_proventesters:
                    data[
                        'critpath_positive_karma_including_proventesters'] += [
                            short_url(update)
                        ]

                # Track updates with overall positive karma, including negative
                # karma from a proventester
                if update.karma > 0 and negative_proventesters:
                    data['critpath_positive_karma_negative_proventesters'] += [
                        short_url(update)
                    ]

            if testingtime_done:
                data['num_tested'] += 1
                if not feedback_done:
                    data['num_tested_without_karma'] += 1

        data['deltas'].sort()

        print " * %d updates" % data['num_updates']
        print " * %d packages updated" % (len(data['packages']))
        for status in statuses:
            print " * %d %s updates" % (data['num_%s' % status], status)
        for type in types:
            print " * %d %s updates (%0.2f%%)" % (
                data['num_%s' % type], type,
                float(data['num_%s' % type]) / data['num_updates'] * 100)
        print " * %d bugs resolved" % len(data['bugs'])
        print " * %d critical path updates (%0.2f%%)" % (
            data['num_critpath'],
            float(data['num_critpath']) / data['num_updates'] * 100)
        print " * %d approved critical path updates" % (
            data['num_critpath_approved'])
        print " * %d unapproved critical path updates" % (
            data['num_critpath_unapproved'])
        print " * %d updates received feedback (%0.2f%%)" % (
            data['num_feedback'],
            (float(data['num_feedback']) / data['num_updates'] * 100))
        print " * %d +0 comments" % data['0']
        print " * %d +1 comments" % data['1']
        print " * %d -1 comments" % data['-1']
        print " * %d unique authenticated karma submitters" % (len(
            data['karma']))
        print " * %d proventesters" % len(data['proventesters'])
        print "   * %d +1's from proventesters" % data['proventesters_1']
        print "   * %d -1's from proventesters" % data['proventesters_-1']
        if data['num_critpath']:
            print " * %d critpath updates with conflicting proventesters (%0.2f%% of critpath)" % (
                len(data['conflicted_proventesters']),
                float(len(data['conflicted_proventesters'])) /
                data['num_critpath'] * 100)
            for u in data['conflicted_proventesters']:
                print "   * " + u
            print " * %d critpath updates with positive karma and negative proventester feedback (%0.2f%% of critpath)" % (
                len(data['critpath_positive_karma_negative_proventesters']),
                float(
                    len(data['critpath_positive_karma_negative_proventesters'])
                ) / data['num_critpath'] * 100)
            for u in data['critpath_positive_karma_negative_proventesters']:
                print "   * " + u
            print " * %d critpath updates with positive karma and positive proventester feedback (%0.2f%% of critpath)" % (
                len(data['critpath_positive_karma_including_proventesters']),
                float(
                    len(data['critpath_positive_karma_including_proventesters']
                        )) / data['num_critpath'] * 100)
        print " * %d anonymous users gave feedback (%0.2f%%)" % (
            data['num_anon_feedback'], float(data['num_anon_feedback']) /
            (data['num_anon_feedback'] + sum(data['karma'].values())) * 100)
        # This does not take into account updates that reach stablekarma before being pushed to testing!
        #        print " * %d out of %d stable updates went through testing (%0.2f%%)" %(
        #                data['num_tested'], data['num_stable'],
        #                float(data['num_tested']) / data['num_stable'] * 100)
        print " * %d updates reached the stable karma threshold (%0.2f%%)" % (
            data['num_stablekarma'],
            float(data['num_stablekarma']) / data['num_stable'] * 100)
        print " * %d updates reached the minimum time in testing threshold (%0.2f%%)" % (
            data['num_testingtime'],
            float(data['num_testingtime']) / data['num_stable'] * 100)
        print " * %d went from testing to stable *without* karma (%0.2f%%)" % (
            data['num_tested_without_karma'],
            float(data['num_tested_without_karma']) / data['num_tested'] * 100)
        print " * %d updates were pushed to stable with negative karma (%0.2f%%)" % (
            data['stable_with_negative_karma'],
            float(data['stable_with_negative_karma']) / data['num_stable'] *
            100)
        print " * %d critical path updates pushed to stable *without* karma" % (
            len(data['critpath_without_karma']))
        #for update in data['critpath_without_karma']:
        #    print "   * %s submitted by %s" % (update.title, update.submitter)
        print " * Time spent in testing:"
        print "   * mean = %d days" % (data['accumulative'].days /
                                       len(data['deltas']))
        print "   * median = %d days" % (data['deltas'][len(data['deltas']) /
                                                        2].days)
        print "   * mode = %d days" % (sorted(data['occurrences'].items(),
                                              key=itemgetter(1))[-1][0])
        #for package in sorted(data['packages'].items(), key=itemgetter(1), reverse=True):
        #    print "    * %s: %d" % (package[0].name, package[1])
        print

    print
    print "Out of %d total updates, %d received feedback (%0.2f%%)" % (
        num_updates, feedback, (float(feedback) / num_updates * 100))
    print "Out of %d total unique commenters, the top 50 are:" % (len(karma))
    for submitter in sorted(karma.iteritems(), key=itemgetter(1),
                            reverse=True)[:50]:
        print " * %s (%d)" % (submitter[0], submitter[1])
Example #15
0
def main():
    load_config()
    __connection__ = hub = PackageHub("bodhi")
    koji = get_session()
    tasks = []
    broke = set()

    # Clean up any stray pending tags
    for release in Release.select():
        print "Finding all pending-testing builds..."
        if release.name.startswith('EL'):
            continue

        tag = release.pending_testing_tag
        tagged = [build['nvr'] for build in koji.listTagged(tag)]
        for nvr in tagged:
            try:
                build = PackageBuild.byNvr(nvr)
                for update in build.updates:
                    if update.status in ('testing', 'stable', 'obsolete'):
                        print "%s %s" % (nvr, update.status)
                        if '--fix' in sys.argv:
                            print "Untagging %s" % nvr
                            koji.untagBuild(tag, nvr, force=True)
            except SQLObjectNotFound:
                print "Can't find build for %s" % nvr
                if '--fix' in sys.argv:
                    print "Untagging %s" % nvr
                    koji.untagBuild(tag, nvr, force=True)

        tag = release.pending_stable_tag
        tagged = [build['nvr'] for build in koji.listTagged(tag)]
        for nvr in tagged:
            try:
                build = PackageBuild.byNvr(nvr)
                for update in build.updates:
                    if update.status in ('pending', 'obsolete'):
                        print "%s %s" % (nvr, update.status)
                        if '--fix' in sys.argv:
                            print "Untagging %s" % nvr
                            koji.untagBuild(tag, nvr, force=True)
            except SQLObjectNotFound:
                print "Can't find build for %s" % nvr
                if '--fix' in sys.argv:
                    print "Untagging %s" % nvr
                    koji.untagBuild(tag, nvr, force=True)

    # Check for testing updates that aren't tagged properly
    for update in PackageUpdate.select(PackageUpdate.q.status=='testing'):
        dest_tag = update.release.testing_tag
        for build in update.builds:
            tags = [tag['name'] for tag in koji.listTags(build=build.nvr)]
            if dest_tag not in tags:
                print "%s marked as testing, but tagged with %s" % (build.nvr,
                                                                    tags)
                if '--fix' in sys.argv:
                    broke.add((tags[0], dest_tag, build.nvr))

    # Check all candidate updates to see if they are in a different bodhi state
    for release in Release.select():
        tag = release.candidate_tag
        tagged = [build['nvr'] for build in koji.listTagged(tag, latest=True)]
        for nvr in tagged:
            try:
                build = PackageBuild.byNvr(nvr)
                for update in build.updates:
                    if update.status in ('testing', 'stable'):
                        print "%s %s but tagged as %s" % (nvr,
                                                          update.status,
                                                          tag)
                        if '--fix' in sys.argv:
                            dest = release.testing_tag
                            if update.status == 'stable':
                                dest = release.stable_tag
                            elif update.status == 'obsolete':
                                dest = release.candidate_tag
                            broke.add((tag, dest, nvr))
            except SQLObjectNotFound:
                pass

    # Make sure that all builds in koji tagged as an update exist
    # in bodhi, and are in the expect state.
    for release in Release.select():
        for tag in (release.testing_tag, release.stable_tag):
            tagged = [build['nvr'] for build in koji.listTagged(tag, latest=True)]
            for nvr in tagged:
                try:
                    build = PackageBuild.byNvr(nvr)
                except SQLObjectNotFound:
                    print "PackageUpdate(%s) not found!" % nvr
                    continue
                if not len(build.updates):
                    print "PackageBuild(%s) has no updates" % (build.nvr)
                status = 'testing' in tag and 'testing' or 'stable'
                for update in build.updates:
                    if update.status != status:
                        print "%s is %s in bodhi but tagged as %s in koji" % (
                                update.title, update.status, tag)
                        if '--fix' in sys.argv:
                            dest = release.testing_tag
                            if update.status == 'stable':
                                dest = release.stable_tag
                            elif update.status == 'obsolete':
                                dest = release.candidate_tag
                            for b in update.builds:
                                broke.add((tag, dest, b.nvr))

    if broke:
        print " ** Fixing broken tags! **"
        koji.multicall = True
        for tag, dest, build in broke:
            print "Moving %s from %s to %s" % (build, tag, dest)
            koji.moveBuild(tag, dest, build, force=True)
        print "Running koji.multiCall()"
        results = koji.multiCall()
        success = False
        print "Waiting for tasks"
        bad_tasks = wait_for_tasks([task[0] for task in results])
        if bad_tasks == 0:
            success = True
        if success:
            print "Tags successfully moved!"
        else:
            print "Error moving tags!"
            print "bad_tasks = %r" % bad_tasks
Example #16
0
def main():
    load_config()
    hub.begin()

    print "Finding updates with duplicate IDs..."
    if os.path.exists('dupes.pickle'):
        out = file('dupes.pickle')
        dupes = cPickle.load(out)
        out.close()
        highest_fedora = int(file('highest_fedora').read())
        highest_epel = int(file('highest_epel').read())
    else:
        dupes = set()
        highest_fedora = 0
        highest_epel = 0

        for update in PackageUpdate.select(PackageUpdate.q.updateid != None):
            if '-2010-' in update.updateid:
                if update.release.id_prefix == 'FEDORA':
                    if update.updateid_int > highest_fedora:
                        highest_fedora = update.updateid_int
                else:
                    if update.updateid_int > highest_epel:
                        highest_epel = update.updateid_int

            updates = PackageUpdate.select(
                AND(PackageUpdate.q.updateid == update.updateid,
                    PackageUpdate.q.title != update.title))
            if updates.count():
                # Maybe TODO?: ensure these dupes have a date_pushed less tahn update?!
                # this way, the new ID is based on the oldest update
                for u in updates:
                    dupes.add(u.title)

        out = file('dupes.pickle', 'w')
        cPickle.dump(dupes, out)
        out.close()
        print "Wrote dupes.pickle"

        file('highest_fedora', 'w').write(str(highest_fedora))
        file('highest_epel', 'w').write(str(highest_epel))

    # verify what we really found the highest IDs
    assert PackageUpdate.select(PackageUpdate.q.updateid == 'FEDORA-2010-%d' %
                                (highest_fedora + 1)).count() == 0
    assert PackageUpdate.select(
        PackageUpdate.q.updateid == 'FEDORA-EPEL-2010-%d' %
        (highest_epel + 1)).count() == 0

    # Should be 740?
    print "%d dupes" % len(dupes)

    print "Highest FEDORA ID:", highest_fedora
    print "Highest FEDORA-EPEL ID:", highest_epel

    # Reassign the update IDs on all of our dupes
    for dupe in dupes:
        up = PackageUpdate.byTitle(dupe)
        #print "%s *was* %s" % (up.title, up.updateid)
        up.updateid = None

        # TODO: save & restore this value after new id assignment?!
        #up.date_pushed = None

    # Tweak the date_pushed to on the updates with the highest IDs
    PackageUpdate.select(PackageUpdate.q.updateid == 'FEDORA-2010-%d' %
                         highest_fedora).date_pushed = datetime.now()
    PackageUpdate.select(PackageUpdate.q.updateid == 'FEDORA-EPEL-2010-%d' %
                         highest_epel).date_pushed = datetime.now()

    #hub.commit()

    for dupe in dupes:
        up = PackageUpdate.byTitle(dupe)
        up.assign_id()
        ups = PackageUpdate.select(PackageUpdate.q.updateid == up.updateid)
        if ups.count() == 1:
            print "Still a dupe!!"
            for update in ups:
                if update.title == up.title:
                    continue
                else:
                    if update.title in dupes:
                        print "%s in dupes, yet shares an updateid %s" % (
                            update.title, update.updateid)
                    else:
                        print "%s is not in dupes, but dupes %s" % (
                            update.title, updateid)

    print "Checking to ensure we have no more dupes..."
    dupes = set()
    for update in PackageUpdate.select(PackageUpdate.q.updateid != None):
        updates = PackageUpdate.select(
            AND(PackageUpdate.q.updateid == update.updateid,
                PackageUpdate.q.title != update.title))
        if updates.count():
            dupes.add(update.title)
    print "%d dupes (should be 0)" % len(dupes)
Example #17
0
def main():
    load_config()
    hub.begin()

    print "Finding updates with duplicate IDs..."
    if os.path.exists('dupes.pickle'):
        out = file('dupes.pickle')
        dupes = cPickle.load(out)
        out.close()
        highest_fedora = int(file('highest_fedora').read())
        highest_epel = int(file('highest_epel').read())
    else:
        dupes = set()
        highest_fedora = 0
        highest_epel = 0

        for update in PackageUpdate.select(PackageUpdate.q.updateid!=None):
            if '-2010-' in update.updateid:
                if update.release.id_prefix == 'FEDORA':
                    if update.updateid_int > highest_fedora:
                        highest_fedora = update.updateid_int
                else:
                    if update.updateid_int > highest_epel:
                        highest_epel = update.updateid_int

            updates = PackageUpdate.select(
                    AND(PackageUpdate.q.updateid == update.updateid,
                        PackageUpdate.q.title != update.title))
            if updates.count():
                # Maybe TODO?: ensure these dupes have a date_pushed less tahn update?!
                # this way, the new ID is based on the oldest update
                for u in updates:
                    dupes.add(u.title)

        out = file('dupes.pickle', 'w')
        cPickle.dump(dupes, out)
        out.close()
        print "Wrote dupes.pickle"

        file('highest_fedora', 'w').write(str(highest_fedora))
        file('highest_epel', 'w').write(str(highest_epel))

    # verify what we really found the highest IDs
    assert PackageUpdate.select(PackageUpdate.q.updateid=='FEDORA-2010-%d' % (highest_fedora + 1)).count() == 0
    assert PackageUpdate.select(PackageUpdate.q.updateid=='FEDORA-EPEL-2010-%d' % (highest_epel + 1)).count() == 0

    # Should be 740?
    print "%d dupes" % len(dupes)

    print "Highest FEDORA ID:", highest_fedora
    print "Highest FEDORA-EPEL ID:", highest_epel

    # Reassign the update IDs on all of our dupes
    for dupe in dupes:
        up = PackageUpdate.byTitle(dupe)
        #print "%s *was* %s" % (up.title, up.updateid)
        up.updateid = None

        # TODO: save & restore this value after new id assignment?!
        #up.date_pushed = None

    # Tweak the date_pushed to on the updates with the highest IDs
    PackageUpdate.select(PackageUpdate.q.updateid=='FEDORA-2010-%d' % highest_fedora).date_pushed = datetime.now()
    PackageUpdate.select(PackageUpdate.q.updateid=='FEDORA-EPEL-2010-%d' % highest_epel).date_pushed = datetime.now()

    #hub.commit()

    for dupe in dupes:
        up = PackageUpdate.byTitle(dupe)
        up.assign_id()
        ups = PackageUpdate.select(PackageUpdate.q.updateid == up.updateid)
        if ups.count() == 1:
            print "Still a dupe!!"
            for update in ups:
                if update.title == up.title:
                    continue
                else:
                    if update.title in dupes:
                        print "%s in dupes, yet shares an updateid %s" % (
                                update.title, update.updateid)
                    else:
                        print "%s is not in dupes, but dupes %s" % (
                                update.title, updateid)

    print "Checking to ensure we have no more dupes..."
    dupes = set()
    for update in PackageUpdate.select(PackageUpdate.q.updateid != None):
        updates = PackageUpdate.select(
                AND(PackageUpdate.q.updateid == update.updateid,
                    PackageUpdate.q.title != update.title))
        if updates.count():
            dupes.add(update.title)
    print "%d dupes (should be 0)" % len(dupes)