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:])