-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathcfbot_api.py
More file actions
157 lines (133 loc) · 4.69 KB
/
Copy pathcfbot_api.py
File metadata and controls
157 lines (133 loc) · 4.69 KB
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
import cfbot_github
import cfbot_config
import cfbot_util
import logging
import secrets
from flask import Flask
from flask import request
from flask import jsonify
# extremely primitive approach to connection re-use; need to learn more flask
# philosophy and do better!
conn = cfbot_util.db()
def error_cleanup():
try:
conn.rollback()
except:
pass
try:
conn.close()
except:
pass
conn = cfbot_util.db()
app = Flask("cfbot_api")
# This URL is registered with Github to receive workflow_job events,
# from both postgresql-cfbot/postgres (for cf/* branches) and
# postgres/postgres (for master, REL_* branches).
@app.route("/api/github-webhook", methods=["POST"])
def github_webhook():
try:
# This UUID can be found under the Github WebHook settings
# "Recent Deliveries" tab, with all the details and our
# response.
event_uuid = request.headers.get("X-Github-Delivery")
event_type = request.headers.get("X-Github-Event")
logging.info("Github webhook: delivery = %s, type = %s", event_uuid, event_type)
try:
event = request.json
except ValueError:
logging.info("could not decode JSON: %s", request.get_data(as_text=True))
raise
if event_type == "workflow_job":
cfbot_github.handle_workflow_job_webhook(conn, event)
conn.commit()
return "OK"
elif event_type == "workflow_run":
cfbot_github.handle_workflow_run_webhook(conn, event)
conn.commit()
return "OK"
elif event_type == "push":
cfbot_github.handle_push_webhook(conn, event)
conn.commit()
return "OK"
else:
return "unhandled event type " + event_type
except:
error_cleanup()
logging.exception("Error processing webhook")
return "NOT OK"
@app.route("/api/requeue-patch", methods=["POST"])
def rerun_patch():
"""API endpoint to requeue a specific patch for processing.
This resets the last_branch_message_id so that the periodic job
will pick it up and process it on the next run.
Expected JSON payload:
{
"commitfest_id": 123,
"submission_id": 456,
"shared_secret": "secret_token"
}
"""
if not request.json:
return jsonify({"error": "Invalid request, JSON payload required"}), 400
# Extract parameters
commitfest_id = request.json.get("commitfest_id")
submission_id = request.json.get("submission_id")
shared_secret = request.json.get("shared_secret")
# Validate required parameters
if not commitfest_id or not submission_id:
return jsonify({"error": "commitfest_id and submission_id are required"}), 400
# Check authentication if shared secret is configured
if (
hasattr(cfbot_config, "COMMITFEST_SHARED_SECRET")
and cfbot_config.COMMITFEST_SHARED_SECRET
):
if not shared_secret or not secrets.compare_digest(
shared_secret, cfbot_config.COMMITFEST_SHARED_SECRET
):
logging.warning(
"Invalid shared secret for rerun request: cf=%s, sub=%s",
commitfest_id,
submission_id,
)
return jsonify({"error": "Invalid authentication"}), 403
# Check if submission exists and get current state
cursor = conn.cursor()
cursor.execute(
"""SELECT name, last_message_id
FROM submission
WHERE commitfest_id = %s AND submission_id = %s""",
(commitfest_id, submission_id),
)
row = cursor.fetchone()
if not row:
return jsonify({"error": "Submission not found"}), 404
name, last_message_id = row
# Check if there's actually a message to process
if not last_message_id:
return jsonify(
{
"error": "No patches found for this submission",
"commitfest_id": commitfest_id,
"submission_id": submission_id,
}
), 400
logging.info(
"API request to requeue patch: cf=%s, sub=%s, name=%s",
commitfest_id,
submission_id,
name,
)
# Reset last_branch_message_id to trigger reprocessing
# This makes the submission appear as if it has a new patch that hasn't been built yet
cursor.execute(
"""UPDATE submission
SET last_branch_message_id = NULL,
backoff_until = NULL
WHERE commitfest_id = %s AND submission_id = %s""",
(commitfest_id, submission_id),
)
conn.commit()
return jsonify({"status": "success"})
# Easy way to run this locally for development.
if __name__ == "__main__":
app.run(debug=True)