k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/experiment/find_developers.py (about) 1 #!/usr/bin/env python3 2 3 # Copyright 2017 The Kubernetes Authors. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 # Need to figure out why this only fails on travis 18 # pylint: disable=bad-continuation 19 20 21 """Selects a random sample of kubernetes developers.""" 22 23 import json 24 import os 25 import random 26 import sys 27 import functools 28 29 import requests 30 31 def download_content(): 32 """Downloads contributor data from github.""" 33 resp = requests.get('https://api.github.com/repos/kubernetes/kubernetes/stats/contributors') 34 resp.raise_for_status() 35 data = resp.content 36 return data 37 38 39 def load_content(data): 40 """Parse the json response.""" 41 users = [User(b) for b in json.loads(data)] 42 return users 43 44 45 @functools.total_ordering 46 class User: # pylint: disable=too-few-public-methods 47 """Store .user and number of .total and .recent commits.""" 48 def __init__(self, blob): 49 self.user = blob['author']['login'] 50 weeks = blob['weeks'] 51 self.recent = sum(k['c'] for k in weeks[-12:]) 52 self.total = sum(k['c'] for k in weeks) 53 54 def __eq__(self, other): 55 return (self.recent, self.total, self.user) == (other.recent, other.total, other.user) 56 57 def __lt__(self, other): 58 return (self.recent, self.total, self.user) < (other.recent, other.total, other.user) 59 60 61 def find_users(users, num, top, middle, bottom): 62 """Selects num users from top, middle, bottom thirds with specified biases.""" 63 total = len(users) 64 if num >= total: 65 return users 66 third = int(total/3.0) 67 # pylint: disable=invalid-name 68 p3 = random.sample(users[:third], int(num * bottom)) 69 p5 = random.sample(users[third:-third], int(num * middle)) 70 p7 = random.sample(users[-third:], int(num * top)) 71 # pylint: enable=invalid-name 72 have = [] 73 have.extend(p3) 74 have.extend(p5) 75 have.extend(p7) 76 if len(have) < num: 77 missing = num - len(have) 78 remaining = [u for u in users if u not in have] 79 extra = random.sample(remaining, missing) 80 have.extend(extra) 81 return have 82 83 84 def main(path=None, num=35, top=0.6, middle=0.2, bottom=0.2): 85 """Select users to survey.""" 86 if not path: 87 data = download_content() 88 else: 89 with open(os.path.expanduser(path)) as fp: 90 data = fp.read() 91 users = sorted(load_content(data)) 92 for user in find_users(users, num, top, middle, bottom): 93 print('%s (%d recent commits, %d total)' % (user.user, user.recent, user.total)) 94 95 96 if __name__ == '__main__': 97 main(*sys.argv[1:])