5 from flask
import Flask
, render_template
, request
, abort
, jsonify
6 from flask_bootstrap
import Bootstrap
7 from flask_caching
import Cache
8 from flask_migrate
import Migrate
9 from flask_nav
import Nav
10 from flask_nav
.elements
import Navbar
, Text
, View
11 from flask_sqlalchemy
import SQLAlchemy
13 from sqlalchemy
import orm
, func
15 from ui
import gitlab
, config
, models
19 app
.config
.from_object(config
)
21 models
.db
.init_app(app
)
22 migrate
= Migrate(app
, models
.db
)
25 nav
.register_element('top', Navbar(
27 View('Builds', '.web_index'),
28 View('Runners', '.web_runners'),
29 View('Stats', '.web_stats')
32 headers
= {'Private-Token': os
.environ
.get('GITLAB_TOKEN', '')}
35 return os
.environ
.get("VERSION", "dev")[:6]
37 app
.jinja_env
.globals.update(version
=version
)
42 if 'status' in request
.args
:
43 args
['build_status'] = request
.args
.get('status')
44 if 'device' in request
.args
:
45 args
['build_device'] = request
.args
.get('device')
46 if 'version' in request
.args
:
47 args
['build_version'] = request
.args
.get('version')
48 if 'type' in request
.args
:
49 args
['build_type'] = request
.args
.get('type')
50 if 'date' in request
.args
:
51 date
= datetime
.datetime
.strptime(request
.args
.get('date'), '%Y-%m-%d').date()
52 args
['build_date'] = datetime
.datetime
.strptime(request
.args
.get('date'), '%Y-%m-%d').date()
53 if 'id' in request
.args
:
54 args
['build_id'] = request
.args
.get('id')
60 runner_build_times
= models
.Build
.query
.join(models
.Build
.build_runner
).with_entities(
61 models
.Runner
.runner_name
,
62 models
.Build
.build_version
,
63 func
.avg(models
.Build
.build_duration
),
64 func
.max(models
.Build
.build_duration
),
65 func
.min(models
.Build
.build_duration
),
66 func
.sum(models
.Build
.build_duration
)
67 ).group_by(models
.Build
.build_version
, models
.Runner
.runner_name
).all()
69 all_build_times
= models
.Build
.query
.with_entities(
70 models
.Build
.build_version
,
71 func
.avg(models
.Build
.build_duration
),
72 func
.max(models
.Build
.build_duration
),
73 func
.min(models
.Build
.build_duration
),
74 func
.sum(models
.Build
.build_duration
)
75 ).group_by(models
.Build
.build_version
).all()
77 runner_build_status
= models
.Build
.query
.join(models
.Build
.build_runner
).with_entities(
78 models
.Runner
.runner_name
,
79 models
.Build
.build_status
,
80 func
.count(models
.Build
.build_status
)
81 ).group_by(models
.Runner
.runner_name
, models
.Build
.build_status
).all()
93 for build_time
in all_build_times
:
94 stats
['times']['all'][build_time
[0]] = {
95 'avg': build_time
[1] if build_time
[1] else 0,
96 'max': build_time
[2] if build_time
[2] else 0,
97 'min': build_time
[3] if build_time
[3] else 0,
98 'sum': build_time
[4] if build_time
[4] else 0,
101 for build_time
in runner_build_times
:
102 stats
['times'].setdefault(build_time
[0], {})[build_time
[1]] = {
103 'avg': build_time
[2] if build_time
[2] else 0,
104 'max': build_time
[3] if build_time
[3] else 0,
105 'min': build_time
[4] if build_time
[4] else 0,
106 'sum': build_time
[5] if build_time
[5] else 0,
109 for build_status
in runner_build_status
:
110 stats
['builds']['all'].setdefault(build_status
[1], 0)
111 stats
['builds']['all'][build_status
[1]] += build_status
[2]
113 stats
['builds'].setdefault(build_status
[0], {})[build_status
[1]] = build_status
[2]
121 return "Invalid Date", 400
122 builds
= models
.Build
.paginate(args
)
123 return render_template('builds.html', builds
=builds
)
125 @app.route('/runners/<string:runner>')
126 def web_runner(runner
):
130 return "Invalid Date", 400
131 runner
= models
.Runner
.get({'runner_name': runner
}).first()
132 args
['build_runner'] = runner
133 builds
= models
.Build
.paginate(args
)
134 return render_template('runner.html', runner
=runner
, builds
=builds
)
139 runners
= ['all'] + [x
for x
in sorted(stats_
['builds'].keys()) if x
!= 'all']
140 return render_template('stats.html', stats
=stats_
, runners
=runners
)
142 @app.route("/runners/")
144 #select * from runner join (select * from build where build_status = "success" order by build_date) as builds on builds.build_runner_id = runner.runner_id group by build_runner_id;
145 subquery
= models
.Build
.query
.filter(models
.Build
.build_status
== "success").order_by(models
.Build
.build_date
).subquery()
146 runners
= models
.Runner
.query
.outerjoin(
147 subquery
, subquery
.c
.build_runner_id
== models
.Runner
.runner_id
149 models
.Runner
.runner_id
,
150 models
.Runner
.runner_name
,
151 models
.Runner
.runner_sponsor
,
152 models
.Runner
.runner_sponsor_url
,
153 subquery
.c
.build_date
154 ).group_by(models
.Runner
.runner_id
).order_by(subquery
.c
.build_date
.desc(), models
.Runner
.runner_name
).all()
155 return render_template('runners.html', runners
=runners
)
157 @app.route('/api/v1/builds')
162 return jsonify({'error': 'Invalid Date'}), 400
163 builds
= models
.Build
.paginate(args
).items
166 return jsonify([x
.as_dict() for x
in builds
])
168 @app.route('/api/v1/runners')
170 runners
= models
.Runner
.get().all()
173 return jsonify([x
.as_dict() for x
in runners
])
175 @app.route('/api/v1/runners/<string:runner>')
176 def api_runner(runner
):
180 return jsonify({"Invalid Date"}), 400
181 runner
= models
.Runner
.get({"runner_name": runner
}).first()
184 return jsonify(runner
.as_dict())
186 @app.route('/api/v1/stats')
188 return jsonify(stats())
191 @app.route("/webhook", methods
=('POST',))
192 def process_webhook():
193 gitlab
.webhooks
.process(request
)
196 if __name__
== '__main__':
197 app
.run(host
='0.0.0.0', port
=5000)