1111from requests .adapters import HTTPAdapter
1212from urllib3 .util .retry import Retry
1313
14- from flask import Response , request , g
14+ from flask import request , g , jsonify
1515from pyinfraboxutils .ibflask import app
1616
1717from pyinfraboxutils import get_env , get_logger
2323logger = get_logger ("github" )
2424
2525def res (status , message ):
26- Response .status = status
27- return {"message" : message }
26+ return jsonify ({"message" : message }), status
2827
2928def remove_ref (ref ):
3029 return "/" .join (ref .split ("/" )[2 :])
@@ -189,7 +188,7 @@ def create_push(self, c, repository, branch, tag):
189188
190189 if not result :
191190 status_url = repository ['statuses_url' ].format (sha = c ['id' ])
192- result = self .execute ('''
191+ self .execute ('''
193192 INSERT INTO "commit" (
194193 id, message, repository_id, timestamp,
195194 author_name, author_email, author_username,
@@ -200,7 +199,7 @@ def create_push(self, c, repository, branch, tag):
200199 %s, %s, %s,
201200 %s, %s, %s,
202201 %s, %s, %s)
203- RETURNING id
202+ ON CONFLICT DO NOTHING
204203 ''' , [c ['id' ],
205204 c ['message' ],
206205 repo_id ,
@@ -215,7 +214,7 @@ def create_push(self, c, repository, branch, tag):
215214 branch ,
216215 project_id ,
217216 tag ,
218- status_url ])
217+ status_url ], fetch = False )
219218
220219 build_id = self .create_build (commit_id , project_id )
221220 clone_url = repository ['clone_url' ]
@@ -297,24 +296,29 @@ def handle_pull_request(self, event):
297296 return res (200 , 'no token' )
298297
299298
300- commits = get_commits (event ['pull_request' ]['commits_url' ], token )
299+ for _ in range (0 , 3 ):
300+ commits = get_commits (event ['pull_request' ]['commits_url' ], token )
301+ hc = None
302+ for commit in commits :
303+ if commit ['sha' ] == event ['pull_request' ]['head' ]['sha' ]:
304+ hc = commit
305+ break
301306
302- hc = None
303- for commit in commits :
304- if commit [ 'sha' ] == event [ 'pull_request' ][ 'head' ][ 'sha' ]:
305- hc = commit
306- break
307+ if not hc :
308+ # We might receive the pr event before the push event.
309+ # this may lead to a situation that we cannot yet
310+ # find the actual commit. Wait some time and retry.
311+ eventlet . sleep ( 1 )
307312
308313 if not hc :
309314 logger .error ('Head commit not found: %s' , event ['pull_request' ]['head' ]['sha' ])
310- logger .error (json .dumps (commits , indent = 4 ))
311315 return res (500 , 'Internal Server Error' )
312316
313317 is_fork = event ['pull_request' ]['head' ]['repo' ]['fork' ]
314318
315319 result = self .execute ('''
316320 SELECT id FROM pull_request WHERE project_id = %s and github_pull_request_id = %s
317- ''' , [repo_id , event ['pull_request' ]['id' ]])
321+ ''' , [project_id , event ['pull_request' ]['id' ]])
318322
319323 if not result :
320324 result = self .execute ('''
@@ -327,13 +331,8 @@ def handle_pull_request(self, event):
327331 event ['pull_request' ]['html_url' ]
328332 ])
329333 pr_id = result [0 ][0 ]
330-
331- result = self .execute ('''
332- SELECT id
333- FROM "commit"
334- WHERE id = %s
335- AND project_id = %s
336- ''' , [hc ['sha' ], project_id ])
334+ else :
335+ pr_id = result [0 ][0 ]
337336
338337 committer_login = None
339338 if hc .get ('committer' , None ):
@@ -362,48 +361,67 @@ def handle_pull_request(self, event):
362361 author_name = author .get ('name' , 'unkown' )
363362 author_date = author .get ('date' , datetime .now ())
364363
365- if not result :
366- result = self .execute ('''
367- INSERT INTO "commit" (
368- id, message, repository_id, timestamp,
369- author_name, author_email, author_username,
370- committer_name, committer_email, committer_username, url, project_id,
371- branch, pull_request_id, github_status_url)
372- VALUES (%s, %s, %s,
373- %s, %s, %s,
374- %s, %s, %s,
375- %s, %s, %s,
376- %s, %s, %s)
377- RETURNING id
378- ''' , [hc ['sha' ], hc ['commit' ]['message' ],
379- repo_id , author_date , author_name ,
380- author_email , author_login ,
381- hc ['commit' ]['committer' ]['name' ],
382- hc ['commit' ]['committer' ]['email' ],
383- committer_login , hc ['html_url' ], project_id , branch , pr_id ,
384- event ['pull_request' ]['statuses_url' ]])
385- else :
364+ commit_id = hc ['sha' ]
365+ result = self .execute ('''
366+ SELECT id
367+ FROM "commit"
368+ WHERE id = %s
369+ AND project_id = %s
370+ ''' , [commit_id , project_id ])
371+
372+ if result :
386373 if event ['action' ] == 'opened' :
387374 return res (200 , 'build already triggered' )
388375
389- commit_id = result [0 ][0 ]
390-
391- if self .has_active_build (commit_id , project_id ):
392- return res (200 , 'build already triggered' )
393-
394- build_id = self .create_build (commit_id , project_id )
395-
396- clone_url = event ['repository' ]['clone_url' ]
397-
398- if event ['repository' ]['private' ]:
399- clone_url = event ['repository' ]['ssh_url' ]
400-
401- self .create_job (event ['pull_request' ]['head' ]['sha' ],
402- clone_url ,
403- build_id , project_id , None , env = env , fork = is_fork )
376+ self .execute ('''
377+ INSERT INTO "commit" (
378+ id, message, repository_id, timestamp,
379+ author_name, author_email, author_username,
380+ committer_name, committer_email, committer_username, url, project_id,
381+ branch, pull_request_id, github_status_url)
382+ VALUES (%s, %s, %s,
383+ %s, %s, %s,
384+ %s, %s, %s,
385+ %s, %s, %s,
386+ %s, %s, %s)
387+ ON CONFLICT ON CONSTRAINT commit_pkey DO UPDATE
388+ SET pull_request_id = %s
389+ ''' , [hc ['sha' ], hc ['commit' ]['message' ],
390+ repo_id , author_date , author_name ,
391+ author_email , author_login ,
392+ hc ['commit' ]['committer' ]['name' ],
393+ hc ['commit' ]['committer' ]['email' ],
394+ committer_login , hc ['html_url' ], project_id , branch , pr_id ,
395+ event ['pull_request' ]['statuses_url' ], pr_id ], fetch = False )
396+
397+ # Abort jobs which are still running on the same PR
398+ self .execute ('''
399+ INSERT INTO abort
400+ SELECT j.id, null
401+ FROM job j
402+ JOIN build b
403+ ON b.id = j.build_id
404+ JOIN commit c
405+ ON b.commit_id = c.id
406+ AND b.project_id = c.project_id
407+ WHERE
408+ c.pull_request_id = %s AND
409+ j.state in ('queued', 'scheduled', 'running') AND
410+ c.id != %s
411+ ''' , [pr_id , commit_id ], fetch = False )
412+
413+ if not self .has_active_build (commit_id , project_id ):
414+ build_id = self .create_build (commit_id , project_id )
415+ clone_url = event ['repository' ]['clone_url' ]
416+
417+ if event ['repository' ]['private' ]:
418+ clone_url = event ['repository' ]['ssh_url' ]
419+
420+ self .create_job (event ['pull_request' ]['head' ]['sha' ],
421+ clone_url ,
422+ build_id , project_id , None , env = env , fork = is_fork )
404423
405424 g .db .commit ()
406-
407425 return res (200 , 'ok' )
408426
409427
0 commit comments