scripts and useful references to track contributions by users.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

get_active_commiters.py 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #!/usr/bin/env python
  2. # Copyright (C) 2013-2014 OpenStack Foundation
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  13. # implied.
  14. #
  15. # See the License for the specific language governing permissions and
  16. # limitations under the License.
  17. #
  18. # Soren Hansen wrote the original version of this script.
  19. # James Blair hacked it up to include email addresses from gerrit.
  20. # Jeremy Stanley overhauled it for gerrit 2.8 and our governance repo.
  21. # Tom Fifield cut it to pieces as a quick hack for the UC recognition to be
  22. # replaced with something nicer at the earliest possible time
  23. import datetime
  24. import json
  25. import optparse
  26. import os
  27. import os.path
  28. import re
  29. import io
  30. import paramiko
  31. MAILTO_RE = re.compile('mailto:(.*)')
  32. USERNAME_RE = re.compile('username:(.*)')
  33. class Account(object):
  34. def __init__(self, num):
  35. self.num = num
  36. self.full_name = ''
  37. self.emails = []
  38. self.username = None
  39. def get_account(accounts, num):
  40. a = accounts.get(num)
  41. if not a:
  42. a = Account(num)
  43. accounts[num] = a
  44. return a
  45. def repo_stats(repo, output, begin, end, keyfile, user):
  46. username_accounts = {}
  47. atcs = []
  48. QUERY = "project:%s status:merged" % repo
  49. client = paramiko.SSHClient()
  50. client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  51. client.load_system_host_keys()
  52. client.connect(
  53. 'review.openstack.org', port=29418,
  54. key_filename=os.path.expanduser(keyfile), username=user)
  55. stdin, stdout, stderr = client.exec_command(
  56. 'gerrit query %s --all-approvals --format JSON' % QUERY)
  57. done = False
  58. last_sortkey = ''
  59. begin_time = datetime.datetime(
  60. int(begin[0:4]), int(begin[4:6]), int(begin[6:8]),
  61. int(begin[8:10]), int(begin[10:12]), int(begin[12:14]))
  62. end_time = datetime.datetime(
  63. int(end[0:4]), int(end[4:6]), int(end[6:8]),
  64. int(end[8:10]), int(end[10:12]), int(end[12:14]))
  65. count = 0
  66. earliest = datetime.datetime.now()
  67. while not done:
  68. for l in stdout:
  69. data = json.loads(l)
  70. if 'rowCount' in data:
  71. if data['rowCount'] < 500:
  72. done = True
  73. continue
  74. count += 1
  75. if 'sortKey' in data.keys():
  76. last_sortkey = data['sortKey']
  77. if 'owner' not in data:
  78. continue
  79. if 'username' not in data['owner']:
  80. continue
  81. account = Account(None)
  82. account.username = data['owner']['username']
  83. account.emails = [data['owner']['email']]
  84. account.full_name = data['owner']['name']
  85. approved = False
  86. for ps in data['patchSets']:
  87. if 'approvals' not in ps:
  88. continue
  89. for aprv in ps['approvals']:
  90. if aprv['type'] != 'SUBM':
  91. continue
  92. ts = datetime.datetime.fromtimestamp(aprv['grantedOn'])
  93. if ts < begin_time or ts > end_time:
  94. continue
  95. approved = True
  96. if ts < earliest:
  97. earliest = ts
  98. if approved and account not in atcs:
  99. atcs.append(account)
  100. if not done:
  101. stdin, stdout, stderr = client.exec_command(
  102. 'gerrit query %s resume_sortkey:%s --all-approvals'
  103. ' --format JSON' % (QUERY, last_sortkey))
  104. print 'repo: %s' % repo
  105. print 'examined %s changes' % count
  106. print 'earliest timestamp: %s' % earliest
  107. output_file = io.open(output, 'w', encoding='UTF-8')
  108. for a in atcs:
  109. output_file.write(a.username + ","+ a.full_name + "," + a.emails[0] + "\n")
  110. output_file.close()
  111. def main():
  112. now = ''.join(
  113. '%02d' % x for x in datetime.datetime.utcnow().utctimetuple()[:6])
  114. optparser = optparse.OptionParser()
  115. optparser.add_option(
  116. '-b', '--begin', help='begin date/time (e.g. 20131017000000)')
  117. optparser.add_option(
  118. '-e', '--end', default=now, help='end date/time (default is now)')
  119. optparser.add_option(
  120. '-k', '--keyfile', default='~/.ssh/id_rsa',
  121. help='SSH key (default is ~/.ssh/id_rsa)')
  122. optparser.add_option(
  123. '-u', '--user', default=os.environ['USER'],
  124. help='SSH username (default is $USER)')
  125. options, args = optparser.parse_args()
  126. projects = ['openstack/ops-tags-team',
  127. 'openstack/osops-tools-monitoring',
  128. 'openstack/osops-tools-generic',
  129. 'openstack/osops-example-configs',
  130. 'openstack/osops-tools-logging',
  131. 'openstack/osops-tools-contrib',
  132. 'openstack/openstack-user-stories',
  133. 'openstack/uc-recognition',
  134. 'openstack/osops-coda']
  135. for repo in projects:
  136. output = '%s.csv' % repo.split('/')[-1]
  137. repo_stats(repo, output, options.begin, options.end,
  138. options.keyfile, options.user)
  139. if __name__ == "__main__":
  140. main()