#!/usr/bin/python import datetime import json import sys import time import conf def patch_list_as_html(l): out = [] for p in sorted(l): number, patch = p.split(',') out.append('%s,%s' % (number, patch, number, patch)) return ', '.join(out) def report(project_filter, user_filter, prefix): with open('patchsets.json') as f: patchsets = json.loads(f.read()) if not user_filter: user_filter = conf.CI_SYSTEM[prefix] elif user_filter and not 'Jenkins' in user_filter: user_filter_new = ['Jenkins'] user_filter_new.extend(user_filter) user_filter = user_filter_new # This is more complicated than it looks because we need to handle # patchsets which are uploaded so rapidly that older patchsets aren't # finished testing. total_patches = 0 total_votes = {} missed_votes = {} sentiments = {} passed_votes = {} failed_votes = {} unparsed_votes = {} for number in patchsets: if patchsets[number].get('__exemption__'): continue if project_filter != '*': if patchsets[number].get('__project__') != project_filter: continue patches = sorted(patchsets[number].keys()) valid_patches = [] # Determine how long a patch was valid for. If it wasn't valid for # at least three hours, disgard. for patch in patches: if not '__created__' in patchsets[number][patch]: continue uploaded = datetime.datetime.fromtimestamp( patchsets[number][patch]['__created__']) obsoleted = datetime.datetime.fromtimestamp( patchsets[number].get(str(int(patch) + 1), {}).get( '__created__', time.time())) valid_for = obsoleted - uploaded if valid_for < datetime.timedelta(hours=3): continue valid_patches.append(patch) total_patches += len(valid_patches) for patch in valid_patches: for author in patchsets[number][patch]: if author == '__created__': continue if author not in user_filter: continue total_votes.setdefault(author, 0) total_votes[author] += 1 for vote, msg, sentiment in patchsets[number][patch][author]: if sentiment.startswith('Positive'): passed_votes.setdefault(author, 0) passed_votes[author] += 1 elif sentiment.startswith('Negative'): failed_votes.setdefault(author, 0) failed_votes[author] += 1 else: unparsed_votes.setdefault(author, 0) unparsed_votes[author] += 1 sentiments.setdefault(author, {}) sentiments[author].setdefault(sentiment, []) sentiments[author][sentiment].append( '%s,%s' % (number, patch)) for author in user_filter: if not author in patchsets[number][patch]: missed_votes.setdefault(author, []) missed_votes[author].append('%s,%s' % (number, patch)) with open('%s-cireport.html' % prefix, 'w') as f: f.write('Valid patches in report period: %d

What is this report? Why is it so wrong? This report is a quick hack done by Michael Still to visualize the performance of CI systems voting on OpenStack changes. For help, please email him at mikal@stillhq.com.

') if __name__ == '__main__': report('openstack/nova', None, 'nova') report('openstack/neutron', None, 'neutron') for user in conf.CI_USERS: report('*', [user], user.replace(' ', '_'))