12
12
import gzip
13
13
cgitb .enable ()
14
14
15
- def is_new_contributor (username , stats ):
16
- for contributor in stats :
17
- if contributor ['login' ] == username :
18
- return False
19
- return True
20
-
21
- contributors_url = "https://api.github.com/repos/%s/%s/contributors?per_page=400"
22
- collaborators_url = "https://api.github.com/repos/%s/%s/collaborators"
15
+ # Maximum per page is 100. Sorted by number of commits, so most of the time the
16
+ # contributor will happen early,
17
+ contributors_url = "https://api.github.com/repos/%s/%s/contributors?per_page=100"
23
18
post_comment_url = "https://api.github.com/repos/%s/%s/issues/%s/comments"
24
19
25
20
welcome_msg = "Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @%s (or someone else) soon."
26
21
warning_summary = '<img src="http://www.joshmatthews.net/warning.svg" alt="warning" height=20> **Warning** <img src="http://www.joshmatthews.net/warning.svg" alt="warning" height=20>\n \n %s'
27
22
unsafe_warning_msg = 'These commits modify **unsafe code**. Please review it carefully!'
28
23
24
+
29
25
def api_req (method , url , data = None , username = None , token = None , media_type = None ):
30
- data = None if not data else json .dumps (data )
31
- headers = {} if not data else {'Content-Type' : 'application/json' }
32
- req = urllib2 .Request (url , data , headers )
33
- req .get_method = lambda : method
34
- if token :
35
- base64string = base64 .standard_b64encode ('%s:x-oauth-basic' % (token )).replace ('\n ' , '' )
36
- req .add_header ("Authorization" , "Basic %s" % base64string )
37
-
38
- if media_type :
39
- req .add_header ("Accept" , media_type )
40
- f = urllib2 .urlopen (req )
41
- if f .info ().get ('Content-Encoding' ) == 'gzip' :
42
- buf = StringIO (f .read ())
43
- f = gzip .GzipFile (fileobj = buf )
44
- return f .read ()
26
+ data = None if not data else json .dumps (data )
27
+ headers = {} if not data else {'Content-Type' : 'application/json' }
28
+ req = urllib2 .Request (url , data , headers )
29
+ req .get_method = lambda : method
30
+ if token :
31
+ base64string = base64 .standard_b64encode ('%s:x-oauth-basic' % (token )).replace ('\n ' , '' )
32
+ req .add_header ("Authorization" , "Basic %s" % base64string )
33
+
34
+ if media_type :
35
+ req .add_header ("Accept" , media_type )
36
+ f = urllib2 .urlopen (req )
37
+ header = f .info ()
38
+ if header .get ('Content-Encoding' ) == 'gzip' :
39
+ buf = StringIO (f .read ())
40
+ f = gzip .GzipFile (fileobj = buf )
41
+ body = f .read ()
42
+ return { "header" : header , "body" : body }
43
+
44
+ def post_comment (body , owner , repo , issue , user , token ):
45
+ global post_comment_url
46
+ try :
47
+ result = api_req ("POST" , post_comment_url % (owner , repo , issue ), {"body" : body }, user , token )['body' ]
48
+ except urllib2 .HTTPError , e :
49
+ if e .code == 201 :
50
+ pass
51
+ else :
52
+ raise e
53
+
54
+ # This function is adapted from https://github.com/kennethreitz/requests/blob/209a871b638f85e2c61966f82e547377ed4260d9/requests/utils.py#L562
55
+ # Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
56
+ def parse_header_links (value ):
57
+ if not value :
58
+ return None
59
+
60
+ links = {}
61
+ replace_chars = " '\" "
62
+ for val in value .split ("," ):
63
+ try :
64
+ url , params = val .split (";" , 1 )
65
+ except ValueError :
66
+ url , params = val , ''
67
+
68
+ url = url .strip ("<> '\" " )
69
+
70
+ for param in params .split (";" ):
71
+ try :
72
+ key , value = param .split ("=" )
73
+ except ValueError :
74
+ break
75
+ key = key .strip (replace_chars )
76
+ if key == 'rel' :
77
+ links [value .strip (replace_chars )] = url
78
+
79
+ return links
80
+
81
+ def is_new_contributor (username , owner , repo , user , token ):
82
+ # iterate through the pages to try and find the contributor
83
+ url = contributors_url % (owner , repo )
84
+ while True :
85
+ print 'looking for contribs on ' + url
86
+ stats_raw = api_req ("GET" , url , None , user , token )
87
+ stats = json .loads (stats_raw ['body' ])
88
+ links = parse_header_links (stats_raw ['header' ].get ('Link' ))
89
+
90
+ for contributor in stats :
91
+ if contributor ['login' ] == username :
92
+ return False
93
+
94
+ if not links or 'next' not in links :
95
+ return True
96
+ url = links ['next' ]
97
+
98
+
45
99
46
100
print "Content-Type: text/html;charset=utf-8"
47
101
print
@@ -55,34 +109,22 @@ def api_req(method, url, data=None, username=None, token=None, media_type=None):
55
109
payload_raw = post .getfirst ("payload" ,'' )
56
110
payload = json .loads (payload_raw )
57
111
if payload ["action" ] != "opened" :
58
- sys .exit (0 )
112
+ sys .exit (0 )
59
113
60
114
owner = payload ['pull_request' ]['base' ]['repo' ]['owner' ]['login' ]
61
115
repo = payload ['pull_request' ]['base' ]['repo' ]['name' ]
62
- stats_raw = api_req ("GET" , contributors_url % (owner , repo ), None , user , token )
63
- stats = json .loads (stats_raw )
64
116
65
117
author = payload ["pull_request" ]['user' ]['login' ]
66
118
issue = str (payload ["number" ])
67
119
68
- def post_comment (body , owner , repo , issue , user , token ):
69
- global post_comment_url
70
- try :
71
- result = api_req ("POST" , post_comment_url % (owner , repo , issue ), {"body" : body }, user , token )
72
- except urllib2 .HTTPError , e :
73
- if e .code == 201 :
74
- pass
75
- else :
76
- raise e
77
-
78
- if is_new_contributor (author , stats ):
79
- collaborators = ['brson' , 'nikomatsakis' , 'pcwalton' , 'alexcrichton' , 'aturon' , 'huonw' ] if repo == 'rust' and owner == 'rust-lang' else ['test_user_selection_ignore_this' ]
80
- random .seed ()
81
- to_notify = random .choice (collaborators )
82
- post_comment (welcome_msg % to_notify , owner , repo , issue , user , token )
120
+ if is_new_contributor (author , owner , repo , user , token ):
121
+ collaborators = ['brson' , 'nikomatsakis' , 'pcwalton' , 'alexcrichton' , 'aturon' , 'huonw' ] if repo == 'rust' and owner == 'rust-lang' else ['test_user_selection_ignore_this' ]
122
+ random .seed ()
123
+ to_notify = random .choice (collaborators )
124
+ post_comment (welcome_msg % to_notify , owner , repo , issue , user , token )
83
125
84
126
warn_unsafe = False
85
- diff = api_req ("GET" , payload ["pull_request" ]["diff_url" ])
127
+ diff = api_req ("GET" , payload ["pull_request" ]["diff_url" ])[ 'body' ]
86
128
for line in diff .split ('\n ' ):
87
129
if line .startswith ('+' ) and not line .startswith ('+++' ) and line .find ('unsafe' ) > - 1 :
88
130
warn_unsafe = True
@@ -93,3 +135,4 @@ def post_comment(body, owner, repo, issue, user, token):
93
135
94
136
if warnings :
95
137
post_comment (warning_summary % '\n ' .join (map (lambda x : '* ' + x , warnings )), owner , repo , issue , user , token )
138
+
0 commit comments