1- from flask import Flask , request , abort
1+ from datetime import datetime , timedelta
2+ from logging .config import dictConfig
3+
4+ from flask import Flask , abort , request
25
3- import logging
46from const import GithubHeaders
5- from datetime import datetime , timedelta
67
7- _LOGGER = logging .getLogger (__name__ )
8+ dictConfig (
9+ {
10+ "version" : 1 ,
11+ "formatters" : {
12+ "default" : {
13+ "format" : "[%(asctime)s]: %(levelname)s| %(message)s" ,
14+ }
15+ },
16+ "handlers" : {
17+ "wsgi" : {
18+ "class" : "logging.StreamHandler" ,
19+ "stream" : "ext://flask.logging.wsgi_errors_stream" ,
20+ "formatter" : "default" ,
21+ }
22+ },
23+ "root" : {"level" : "INFO" , "handlers" : ["wsgi" ]},
24+ }
25+ )
826
927app = Flask (__name__ )
1028
1129jobs = dict ()
1230
31+
1332def parse_datetime (date : str ) -> datetime :
1433 exp = "%Y-%m-%dT%H:%M:%SZ"
1534 return datetime .strptime (date , exp )
1635
36+
37+ def prune_jobs ():
38+ # if the first job is older than 2 days, prune all jobs older than 2 days
39+ # this might happen due to not completed jobs
40+ if datetime .fromtimestamp (list (jobs .values ())[0 ]) > datetime .now () - timedelta (
41+ days = 2
42+ ):
43+ app .logger .info ("Pruning jobs" )
44+ for job_id , timestamp in jobs .items ():
45+ if (datetime .now () - datetime .fromtimestamp (timestamp )).days >= 2 :
46+ del jobs [job_id ]
47+
48+
1749def validate_origin_github () -> bool :
1850 userAgent = request .headers .get ("User-Agent" )
1951 if not userAgent .startswith ("GitHub-Hookshot" ):
20- _LOGGER .warning ("User-Agent is {userAgent}" )
52+ app . logger .warning ("User-Agent is {userAgent}" )
2153 return False
2254
2355 if request .headers .get ("Content-Type" ) != "application/json" :
24- _LOGGER .warning ("Content is not JSON" )
56+ app . logger .warning ("Content is not JSON" )
2557 return False
2658
2759 if not request .headers .get (GithubHeaders .EVENT .value ):
28- _LOGGER .warning ("No GitHub Event received!" )
60+ app . logger .warning ("No GitHub Event received!" )
2961 return False
3062
3163 return True
3264
65+
3366def process_workflow_job ():
3467 job = request .get_json ()
3568
3669 job_id = job ["workflow_job" ]["run_id" ]
37- name = job ["workflow_job" ]["workflow_name" ]
70+ workflow = job ["workflow_job" ]["workflow_name" ]
3871 time_start = parse_datetime (job ["workflow_job" ]["started_at" ])
3972 repository = job ["repository" ]["full_name" ]
4073 action = job ["action" ]
41- NOW = datetime .now ()
4274
4375 if action == "queued" :
4476 # add to memory as timestamp
4577 jobs [job_id ] = int (time_start .timestamp ())
46- msg = f"{ NOW } { action = } { repository = } workflow={ name } { job_id = } { time_start = } "
78+ msg = f"{ action = } { repository = } { workflow = } { job_id = } "
79+ prune_jobs ()
4780
4881 elif action == "in_progress" :
49- job_requested = jobs .get (job_id , None )
82+ job_requested = jobs .get (job_id )
5083 if not job_requested :
51- _LOGGER .warning (f"Job { job_id } is { action } but not stored!" )
84+ app . logger .warning (f"Job { job_id } is { action } but not stored!" )
5285 time_to_start = 0
5386 else :
54- time_to_start = (
55- time_start - datetime .fromtimestamp (job_requested )
56- ).seconds
57- msg = f"{ NOW } { action = } { repository = } workflow={ name } { job_id = } { time_to_start = } "
87+ time_to_start = (time_start - datetime .fromtimestamp (job_requested )).seconds
88+ msg = f"{ action = } { repository = } { workflow = } { job_id = } { time_to_start = } "
5889
5990 elif action == "completed" :
60- job_requested = jobs .get (job_id , None )
91+ job_requested = jobs .get (job_id )
6192 if not job_requested :
62- _LOGGER .warning (f"Job { job_id } is { action } but not stored!" )
93+ app . logger .warning (f"Job { job_id } is { action } but not stored!" )
6394 time_to_finish = 0
6495 else :
6596 time_to_finish = (
66- time_start - datetime . fromtimestamp ( job_requested )
97+ parse_datetime ( job [ "workflow_job" ][ "completed_at" ]) - time_start
6798 ).seconds
6899 # delete from memory
69100 del jobs [job_id ]
70-
71- msg = f"{ NOW } { action = } { repository = } workflow={ name } { job_id = } { time_to_finish = } "
72101
73- print ( msg )
102+ msg = f" { action = } { repository = } { workflow = } { job_id = } { time_to_finish = } "
74103
104+ app .logger .info (msg )
75105 return True
76106
107+
77108@app .route ("/github-webhook" , methods = ["POST" ])
78109def github_webhook_process ():
79110 if not validate_origin_github ():
@@ -82,16 +113,14 @@ def github_webhook_process():
82113 event = request .headers .get (GithubHeaders .EVENT .value )
83114 command = f"process_{ event } "
84115
85- #if hasattr(command) and callable(getattr(command)):
86116 if command == "process_workflow_job" :
87- _LOGGER .debug (f"Calling function { command } " )
88- #response = getattr(command)()
117+ app .logger .debug (f"Calling function { command } " )
89118 response = process_workflow_job ()
90119
91120 if not response :
92- _LOGGER .error (f"Error calling { event } function" )
121+ app . logger .error (f"Error calling { event } function" )
93122 return abort (500 )
94123 return "OK"
95124
96- _LOGGER .error (f"Unknown event type { event } , can't handle" )
125+ app . logger .error (f"Unknown event type { event } , can't handle" )
97126 return abort (405 )
0 commit comments