@@ -141,20 +141,24 @@ def github_build(request):
141
141
142
142
This will search for projects matching either a stripped down HTTP or SSH
143
143
URL. The search is error prone, use the API v2 webhook for new webhooks.
144
+
145
+ Old webhooks may not have specified the content type to POST with, and
146
+ therefore can use ``application/x-www-form-urlencoded`` to pass the JSON
147
+ payload. More information on the API docs here:
148
+ https://developer.github.com/webhooks/creating/#content-type
144
149
"""
145
150
if request .method == 'POST' :
146
151
try :
147
- data = json .loads (request .body )
148
- except (ValueError , TypeError ):
149
- log .error ('Invalid GitHub webhook payload' , exc_info = True )
150
- return HttpResponse ('Invalid request' , status = 400 )
151
- http_url = data ['repository' ]['url' ]
152
- http_search_url = http_url .replace ('http://' , '' ).replace ('https://' , '' )
153
- ssh_url = data ['repository' ]['ssh_url' ]
154
- ssh_search_url = ssh_url .replace ('git@' , '' ).replace ('.git' , '' )
155
- try :
152
+ if request .META ['CONTENT_TYPE' ] == 'application/x-www-form-urlencoded' :
153
+ data = json .loads (request .POST .get ('payload' ))
154
+ else :
155
+ data = json .loads (request .body )
156
+ http_url = data ['repository' ]['url' ]
157
+ http_search_url = http_url .replace ('http://' , '' ).replace ('https://' , '' )
158
+ ssh_url = data ['repository' ]['ssh_url' ]
159
+ ssh_search_url = ssh_url .replace ('git@' , '' ).replace ('.git' , '' )
156
160
branches = [data ['ref' ].replace ('refs/heads/' , '' )]
157
- except KeyError :
161
+ except ( ValueError , TypeError , KeyError ) :
158
162
log .error ('Invalid GitHub webhook payload' , exc_info = True )
159
163
return HttpResponse ('Invalid request' , status = 400 )
160
164
try :
@@ -178,7 +182,7 @@ def github_build(request):
178
182
log .error ('Project match not found: url=%s' , http_search_url )
179
183
return HttpResponseNotFound ('Project not found' )
180
184
else :
181
- return HttpResponse ('Method not allowed' , status = 405 )
185
+ return HttpResponse ('Method not allowed, POST is required ' , status = 405 )
182
186
183
187
184
188
@csrf_exempt
@@ -191,12 +195,12 @@ def gitlab_build(request):
191
195
if request .method == 'POST' :
192
196
try :
193
197
data = json .loads (request .body )
194
- except (ValueError , TypeError ):
198
+ url = data ['project' ]['http_url' ]
199
+ search_url = re .sub (r'^https?://(.*?)(?:\.git|)$' , '\\ 1' , url )
200
+ branches = [data ['ref' ].replace ('refs/heads/' , '' )]
201
+ except (ValueError , TypeError , KeyError ):
195
202
log .error ('Invalid GitLab webhook payload' , exc_info = True )
196
203
return HttpResponse ('Invalid request' , status = 400 )
197
- url = data ['project' ]['http_url' ]
198
- search_url = re .sub (r'^https?://(.*?)(?:\.git|)$' , '\\ 1' , url )
199
- branches = [data ['ref' ].replace ('refs/heads/' , '' )]
200
204
log .info (
201
205
'GitLab webhook search: url=%s branches=%s' ,
202
206
search_url ,
@@ -209,49 +213,52 @@ def gitlab_build(request):
209
213
log .error ('Project match not found: url=%s' , search_url )
210
214
return HttpResponseNotFound ('Project match not found' )
211
215
else :
212
- return HttpResponse ('Method not allowed' , status = 405 )
216
+ return HttpResponse ('Method not allowed, POST is required ' , status = 405 )
213
217
214
218
215
219
@csrf_exempt
216
220
def bitbucket_build (request ):
217
221
"""Consume webhooks from multiple versions of Bitbucket's API
218
222
223
+ New webhooks are set up with v2, but v1 webhooks will still point to this
224
+ endpoint. There are also "services" that point here and submit
225
+ ``application/x-www-form-urlencoded`` data.
226
+
219
227
API v1
220
228
https://confluence.atlassian.com/bitbucket/events-resources-296095220.html
221
229
222
230
API v2
223
231
https://confluence.atlassian.com/bitbucket/event-payloads-740262817.html#EventPayloads-Push
232
+
233
+ Services
234
+ https://confluence.atlassian.com/bitbucket/post-service-management-223216518.html
224
235
"""
225
236
if request .method == 'POST' :
226
237
try :
227
- data = json . loads ( request .body )
228
- except ( TypeError , ValueError ):
229
- log . error ( 'Invalid Bitbucket webhook payload' , exc_info = True )
230
- return HttpResponse ( 'Invalid request' , status = 400 )
238
+ if request .META [ 'CONTENT_TYPE' ] == 'application/x-www-form-urlencoded' :
239
+ data = json . loads ( request . POST . get ( 'payload' ))
240
+ else :
241
+ data = json . loads ( request . body )
231
242
232
- version = 2 if request .META .get ('HTTP_USER_AGENT' ) == 'Bitbucket-Webhooks/2.0' else 1
233
- if version == 1 :
234
- try :
243
+ version = 2 if request .META .get ('HTTP_USER_AGENT' ) == 'Bitbucket-Webhooks/2.0' else 1
244
+ if version == 1 :
235
245
branches = [commit .get ('branch' , '' )
236
246
for commit in data ['commits' ]]
237
247
repository = data ['repository' ]
238
248
search_url = 'bitbucket.org{0}' .format (
239
249
repository ['absolute_url' ].rstrip ('/' )
240
250
)
241
- except KeyError :
242
- log .error ('Invalid Bitbucket webhook payload' , exc_info = True )
243
- return HttpResponse ('Invalid request' , status = 400 )
244
- elif version == 2 :
245
- try :
251
+ elif version == 2 :
246
252
changes = data ['push' ]['changes' ]
247
253
branches = [change ['new' ]['name' ]
248
254
for change in changes ]
249
255
search_url = 'bitbucket.org/{0}' .format (
250
256
data ['repository' ]['full_name' ]
251
257
)
252
- except KeyError :
253
- log .error ('Invalid Bitbucket webhook payload' , exc_info = True )
254
- return HttpResponse ('Invalid request' , status = 400 )
258
+ except (TypeError , ValueError , KeyError ):
259
+ log .error ('Invalid Bitbucket webhook payload' , exc_info = True )
260
+ return HttpResponse ('Invalid request' , status = 400 )
261
+
255
262
log .info (
256
263
'Bitbucket webhook search: url=%s branches=%s' ,
257
264
search_url ,
@@ -265,7 +272,7 @@ def bitbucket_build(request):
265
272
log .error ('Project match not found: url=%s' , search_url )
266
273
return HttpResponseNotFound ('Project match not found' )
267
274
else :
268
- return HttpResponse ('Method not allowed' , status = 405 )
275
+ return HttpResponse ('Method not allowed, POST is required ' , status = 405 )
269
276
270
277
271
278
@csrf_exempt
0 commit comments