#!/usr/bin/python # Copyright (C) 2013 OpenStack Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # # See the License for the specific language governing permissions and # limitations under the License. # # Soren Hansen wrote the original version of this script. # James Blair hacked it up to include email addresses from gerrit. import calendar import datetime import json import optparse import paramiko from pprint import pprint import sys import csv import re MAILTO_RE = re.compile('mailto:(.*)') USERNAME_RE = re.compile('username:(.*)') accounts = {} class Account(object): def __init__(self, num): self.num = num self.full_name = '' self.emails = [] self.username = None def get_account(num): a = accounts.get(num) if not a: a = Account(num) accounts[num] = a return a for row in csv.reader(open('emails.csv')): num, email, pw, external = row num = int(num) a = get_account(num) if email and email != '\\N' and email not in a.emails: a.emails.append(email) m = MAILTO_RE.match(external) if m: if m.group(1) not in a.emails: a.emails.append(m.group(1)) m = USERNAME_RE.match(external) if m: if a.username: print a.num print a.username raise Exception("Already a username") a.username = m.group(1) for row in csv.reader(open('accounts.csv')): num = int(row[-1]) name = row[1] a = get_account(num) a.full_name = name username_accounts = {} for a in accounts.values(): username_accounts[a.username] = a atcs = [] optparser = optparse.OptionParser() optparser.add_option('-p', '--project', default='nova', help='Project to generate stats for') optparser.add_option('-o', '--output', default='out.csv', help='Output file') options, args = optparser.parse_args() QUERY = "project:%s status:merged" % options.project client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.load_system_host_keys() client.connect('review.openstack.org', port=29418, key_filename='/home/corvus/.ssh/id_rsa', username='CHANGME') stdin, stdout, stderr = client.exec_command('gerrit query %s --all-approvals --format JSON' % QUERY) changes = [] done = False last_sortkey = '' tz = datetime.tzinfo start_date = datetime.datetime(2012, 9, 27, 0, 0, 0) end_date = datetime.datetime(2013, 7, 30, 0, 0, 0) count = 0 earliest = datetime.datetime.now() while not done: for l in stdout: data = json.loads(l) if 'rowCount' in data: if data['rowCount'] < 500: done = True continue count += 1 last_sortkey = data['sortKey'] if 'owner' not in data: continue if 'username' not in data['owner']: continue account = username_accounts[data['owner']['username']] approved = False for ps in data['patchSets']: if 'approvals' not in ps: continue for aprv in ps['approvals']: if aprv['type'] != 'SUBM': continue ts = datetime.datetime.fromtimestamp(aprv['grantedOn']) if ts < start_date or ts > end_date: continue approved = True if ts < earliest: earliest = ts if approved and account not in atcs: atcs.append(account) if not done: stdin, stdout, stderr = client.exec_command('gerrit query %s resume_sortkey:%s --all-approvals --format JSON' % (QUERY, last_sortkey)) print 'project: %s' % options.project print 'examined %s changes' % count print 'earliest timestamp: %s' % earliest writer = csv.writer(open(options.output, 'w')) for a in atcs: writer.writerow([a.username, a.full_name] + a.emails) print