-
Notifications
You must be signed in to change notification settings - Fork 0
/
user.py
288 lines (261 loc) · 10.2 KB
/
user.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
'''
List all inactive user of a GitHub organization
See user.py --help for usage.
Partially inspired by https://gist.github.com/morido/9817399
'''
import sys # to use sys.stdout
import os
from datetime import datetime
from time import strftime
import datetime
import json
import urllib2
import argparse
import base64
import pprint
import requests
import string
from urlparse import urlparse, parse_qs
def printf(format, *args):
sys.stdout.write(format % args)
def githubDateToUSdate(date):
dt = datetime.strptime(date, "%Y-%m-%dT%H:%M:%SZ")
return dt
if hasattr(__builtins__, 'raw_input'):
input = raw_input
# Turn off console output buffering
buf_arg = 0
if sys.version_info[0] == 3:
os.environ['PYTHONUNBUFFERED'] = '1'
buf_arg = 1
try:
sys.stdout = os.fdopen(sys.stdout.fileno(), 'a+', buf_arg)
sys.stderr = os.fdopen(sys.stderr.fileno(), 'a+', buf_arg)
except:
pass
parser = argparse.ArgumentParser(description='''
List all repository of a GitHub organization.''')
parser.add_argument('-u',metavar='USER', dest='github_user', action='store', required=False,
help='GitHub user',
default=None)
parser.add_argument('-p',metavar='PASSWORD', dest='github_pass', action='store', required=False,
help='GitHub password',
default=None)
parser.add_argument('-o',metavar='ORG', dest='github_org', action='store', required=False,
help='GitHub organization to list. Default %(default)s',
default='D4UDigitalPlatform')
parser.add_argument('-w',metavar='WEEKS', dest='weeks', action='store', required=False,
help='Time of interests, in weeks. Default %(default)s',
default='52')
parser.add_argument('--repo',metavar='REPONAME', dest='repo', action='store', required=False,
help='GitHub repository name (without orga name)',
default=None)
parser.add_argument('--userdetails', dest='repo', action='store', required=False,
help='Show detailed information about each organization users',
default=False)
parser.add_argument('--url',metavar='URL', dest='github_url', action='store', required=False,
help='GitHub API url. Default %(default)s',
default='https://api.github.com')
args = parser.parse_args()
if (args.github_user == None):
args.github_user = input("GitHub Username :")
if (args.github_pass == None):
print "GitHub Password (sorry, it will be displayed in the console. Use -p instead"
args.github_pass = input(":")
time_of_interest_in_weeks = int(args.weeks)
time_of_interest_in_weeks_absolute = datetime.datetime.today() - datetime.timedelta(weeks = time_of_interest_in_weeks)
base64string = base64.b64encode(args.github_user + ':' + args.github_pass )
#headers = {"Authorization": "Basic %s" % base64string, "Accept": "application/vnd.github.inertia-preview+json"}
headers = {"Authorization": "Basic %s" % base64string, "Accept": "application/vnd.github.mercy-preview+json"}
printf("Find inactive user :\n\tSince %s\n\tFor organization %s\n\tFor %s repo\n\tUsing authent provided by %s\n",
time_of_interest_in_weeks_absolute,
args.github_org,
"all" if args.repo == None else args.repo,
args.github_user
)
url = args.github_url + "/orgs/" + args.github_org
print "Get organization information ..."
res=requests.get(url,headers=headers)
if (res.status_code <> 200):
printf("ERROR : API reply HTTP code %d\n", res.status_code)
sys.exit(res.status_code)
repos=res.json()
printf("Organization informations :\n")
printf("\tDisk usage : %d\n", repos.get("disk_usage"))
printf("\tTotal privat repo : %d\n", repos.get("total_private_repos"))
printf("\tCollaborators : %d\n", repos.get("collaborators"))
printf("\tPlan name : %s\n", repos.get("plan")['name'])
printf("\tPlan max repo : %d\n", repos.get("plan")['private_repos'])
printf("\tPlan used space : %d\n", repos.get("plan")['space'])
#
#See https://developer.github.com/v3/repos/#list-organization-repositories
#
url = args.github_url + "/orgs/"+args.github_org+"/members?per_page=100"
print "Get all users member of the organization"
members = [] # all members subscribe to the orga
activemembers = [] # all orga members with activity
inactivemembers = []# all orga member without activity
def get_user_info(login):
url = args.github_url + "/users/" + login
res=requests.get(url,headers=headers)
mem=res.json()
return ({
'login': mem.get('login'),
'location': "" if (mem.get('location')==None) else mem.get('location').encode('utf-8').encode('ascii', 'backslashreplace'),
'name':"" if (mem.get('name') == None) else mem.get('name').encode('ascii', 'backslashreplace'),
'email': "" if (mem.get('email') == None) else mem.get('email'),
'created_at':mem.get('created_at')
})
# create the members list containing all member subribing the orga
while True:
res=requests.get(url,headers=headers)
mem=res.json()
for member in mem:
login = member.get('login')
members.append(login)
#info = get_user_info(login)
#printf("%s;%s;%s;%s;%s\n", info.get('login'), info.get('location'), info.get('name'), info.get('email'), info.get('created_at'))
printf("%d members fetched...\r", len(members))
if 'next' in res.links.keys():
url = res.links['next']['url']
else:
break
printf("Found %d members \n", len(members))
def get_contributors_from_contributors_url(url, headers):
contributors = []
while True:
res=requests.get(url+"?per_page=100",headers=headers)
if (res.status_code == 204):
break
ctr=res.json()
for contributor in ctr:
contributors.append({
'login':contributor.get('login'),
'contributions':contributor.get('contributions')
})
#printf("%d contributors fetched...\r", len(contributors))
if 'next' in res.links.keys():
url = res.links['next']['url']
else:
break
return contributors
def get_nbcommits_from(url, author, since, header):
url = string.replace(url, "{/sha}", "")
url = url + "?per_page=1&since="+since.isoformat()+"&author="+author # Do I need urlencode here ?
nbcommits = 0
res=requests.get(url,headers=headers)
com = res.json()
nbcommits = len(com)
if (len(com) != 0):
prevurl = res.links['last']['url']
parsed_url = urlparse(prevurl)
qs = parse_qs(parsed_url.query)
nbcommits = int(qs.get('page')[0])
return nbcommits
def get_commits_from(url, author, since, header):
# {/sha}
url = string.replace(url, "{/sha}", "")
url = url + "?per_page=100&since="+since.isoformat()
if (author != None):
url = url + "&author="+author # Do I need urlencode here ?
commits=[]
while True:
res=requests.get(url,headers=headers)
com = res.json()
if (res.status_code == 409):
return []
for commit in com:
author = "" if (commit.get('author') == None) else commit.get('author').get('login')
committer = commit.get('commit').get('committer').get('name')
commit_author = commit.get('commit').get('author').get('name')
committer_login = "" if (commit.get('committer') == None) else commit.get('committer').get('login')
sha = commit.get('sha')
if author == "" or author == None:
author = committer_login
if author == "" or author == None:
author = commit_author
if author == "" or author == None:
author = committer
#printf("%s %s %s %s %s\n", sha, author, committer, commit_author, committer_login)
commits.append({
'login':author.encode('ascii', 'backslashreplace'),
'sha':sha,
'date':commit.get('commit').get('committer').get('date')
})
if 'next' in res.links.keys():
url = res.links['next']['url']
else:
break
return commits
# for each repo of the orga,
# fetch all commits since a date.
# for each commit, extract committer and add it to the active list if he is memeber of the orga
print "Get all users of repo of the organization"
url = args.github_url + "/orgs/"+args.github_org+"/repos?type=all&per_page=100"
repos = []
nonmembers = []
while True:
res=requests.get(url,headers=headers)
rep=res.json()
for repo in rep:
reponame = repo.get('name')
repos.append(reponame)
printf("- %s\n", reponame)
if (args.repo == None or reponame == args.repo):
commits = get_commits_from(repo.get('commits_url'), None, time_of_interest_in_weeks_absolute, headers) #Get all commits since a date
printf("\tFound %5d commits ", len(commits))
nbcommit_by_login = {}
for com in commits:
login = com.get('login')
if (login in nbcommit_by_login) :
nbcommit_by_login[login] = nbcommit_by_login[login] + 1
else :
nbcommit_by_login[login] = 1
printf("by %d users\n", len(nbcommit_by_login))
for login,nbcom in sorted(nbcommit_by_login.iteritems(), key=lambda (k,v): (v,k), reverse=True):
printf("\t\t%20s : %5d commits", login, nbcom)
if (login in members):
if (login not in activemembers):
activemembers.append(login)
else:
printf(" not in organization")
printf("\n")
'''
contributors_url = repo.get('contributors_url')
contributors = get_contributors_from_contributors_url(contributors_url, headers)
printf("\t%d contributors :\n", len(contributors))
for c in contributors:
login = c.get('login')
printf("\t\t%20s (%5d total contributions) ", login, c.get('contributions'))
if login not in members and login not in nonmembers:
nonmembers.append(login)
# if login not in activemembers and login in members:
# activemembers.append(login)
#commits = get_commits_from(repo.get('commits_url'), login, time_of_interest_in_weeks_absolute, headers)
#printf("%5d commits\n", len(commits))
if (login in members):
nbcommit = get_nbcommits_from(repo.get('commits_url'), login, time_of_interest_in_weeks_absolute, headers)
#if (nbcommit > 0):
# printf("had commited\n")
#else:
# printf("did not commit\n")
printf("%4d commits\n", nbcommit)
else:
printf("not in organization\n")
if (nbcommit > 0 and login in members and login not in activemembers):
activemembers.append(login)
printf("\n")
'''
if 'next' in res.links.keys():
url = res.links['next']['url']
else:
break
inactivemembers = members
for m in activemembers:
inactivemembers.remove(m)
printf("Found %4d members of the organization\n", len(members))
printf("Found %4d contributors not existing anymore in organization\n", len(nonmembers))
printf("Found %4d active member of the organization\n", len(activemembers))
printf("Found %4d inactive member of the organization :\n", len(inactivemembers))
for m in inactivemembers:
printf("%s\n", m)