-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstart_server.py
executable file
·174 lines (144 loc) · 5.39 KB
/
start_server.py
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#! venv/bin/python
import global_data
from global_data import app, git
from flask import Response, request, render_template, redirect, url_for
from flask_bootstrap import Bootstrap
from datetime import datetime, timedelta
import hmac
import hashlib
import re
import os
from gc_exceptions import *
import git_commands
import log
import jobs
import db
import agent
import worker
log.debug("---[ STARTING SERVER ]---")
Bootstrap(app)
SUPPORTED_REPO_TYPES = ["github", "bitbucket"]
BRANCH_PATTERN = re.compile(app.config["BRANCH_PATTERN"])
worker.start()
@app.route("/job/<id>", methods=["GET"])
def get_job(id):
job = jobs.get_by_id(id)
if not job:
job = db.find_job(id)
return render_template("job.html", job=job)
@app.route("/jobs", methods=["GET"])
@app.route("/jobs/<int:hours>", methods=["GET"])
def get_jobs(hours=None):
if not hours: hours = 24
since = datetime.now() - timedelta(hours=hours)
jobs = db.find_jobs(since)
return render_template("jobs.html", jobs=jobs, hours=hours)
@app.route("/", methods=["GET"])
@app.route("/current_jobs", methods=['GET'])
@app.route("/current_jobs/<username>", methods=['GET'])
def get_current_jobs(username=None):
return render_template("jobs.html", jobs=jobs.get())
@app.route("/cancel/<branch>", methods=["POST"])
def cancel_job(branch):
job = jobs.get_by_id(branch)
if not job:
raise NotFound("Current job %s does not exist" % branch)
if jobs.is_current(job):
agent.cancel()
else:
jobs.cancel()
return redirect(url_for("get_job", id=branch))
@app.route("/status", methods=['GET'])
def status():
return Response(git.status(), mimetype="text/plain")
@app.route("/tree", methods=['GET'])
def tree():
content = git.tree()
return Response(content, mimetype="text/plain")
@app.route("/log", methods=['GET'])
@app.route("/log/<n>", methods=['GET'])
def getlog(n="500"):
log_content = log.get_lines(n)
return Response(log_content, mimetype="text/plain")
@app.route('/pull', methods=['POST'])
def pull_hook():
if not authenticate(request):
raise Unauthorized()
branch = get_from_complex_request(request, "branch_name")
username = get_from_complex_request(request, "username")
if not re.match(BRANCH_PATTERN, branch):
raise Ignore("Ignoring push to branch %s" % branch)
jobs.add(branch, username)
return ""
@app.route("/pull/<username>/<branch>", methods=['POST'])
def pull_manually(username, branch):
if not username or not branch or branch == app.config["MASTER"]:
raise BadRequest("username and branch must be set and branch cannot be master")
db.delete_job_if_exist(branch)
jobs.add(branch, username)
if "redirect" in request.form:
return redirect(request.form["redirect"])
else:
return redirect(url_for("get_current_jobs"))
@app.route("/config", methods=["GET"])
def get_config():
status = { "remote_problems": git.remote_problems() }
config = { "remote": git.remote }
return render_template("config.html", status=status, config=config)
@app.route("/config", methods=["POST"])
def set_config():
remote = get_from_form(request, "remote")
repo_type = get_from_form(request, "repo_type", str.lower)
if repo_type not in SUPPORTED_REPO_TYPES and False: # This is ignored for now
msg = "Repo type '%s' not supported. Supported types are %s" % (repo_type, SUPPORTED_REPO_TYPES)
raise BadRequest(msg)
git.remote = remote
return redirect(url_for("get_config"))
@app.errorhandler(404)
def not_found(e):
return bad_request_handler(NotFound("Invalid URL"))
@app.errorhandler(GcException)
def bad_request_handler(error):
error.log_exception()
payload = error.to_dict()
return render_template("error.html", code=error.status_code, name=type(error).__name__, payload=payload), error.status_code
def authenticate(request):
if not app.config["HOOK_KEY"]:
return True
digester = hmac.new(app.config["HOOK_KEY"], request.data, hashlib.sha1)
requestHash = "sha1=%s" % digester.hexdigest()
requestSecret = request.headers["X-Hub-Signature"]
diff = sum(i != j for i, j in zip(requestHash, requestSecret))
return diff == 0
def username_github(payload):
return payload["pusher"]["name"]
def username_bitbucket(payload):
return payload["actor"]["username"]
def branch_name_github(payload):
return payload["ref"][len("refs/heads/"):]
def branch_name_bitbucket(payload):
return payload["push"]["changes"][0]["new"]["name"]
payload_accessors = {
"github": { "username": username_github, "branch_name": branch_name_github },
"bitbucket": { "username": username_bitbucket, "branch_name": branch_name_bitbucket }
}
def repo_type(request):
user_agent = request.headers.get("User-Agent").lower()
if "bitbucket" in user_agent:
return "bitbucket"
if "github" in user_agent:
return "github"
raise Exception("Could not determine repo type")
def get_from_form(request, field, convert=lambda x:x):
if not field in request.form:
raise BadRequest("%s not provided" % field)
return convert(str(request.form[field]))
def get_from_complex_request(request, field):
rt = repo_type(request)
try:
payload = request.get_json()
return payload_accessors[rt][field](payload)
except:
raise BadRequest("%s not provided" % field)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, use_reloader=False)