argus-alm 0.12.2__py3-none-any.whl → 0.12.4b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- argus/backend/cli.py +1 -1
- argus/backend/controller/admin_api.py +26 -0
- argus/backend/controller/api.py +26 -1
- argus/backend/controller/main.py +21 -0
- argus/backend/controller/testrun_api.py +132 -1
- argus/backend/controller/view_api.py +162 -0
- argus/backend/models/web.py +16 -0
- argus/backend/plugins/core.py +28 -5
- argus/backend/plugins/driver_matrix_tests/controller.py +39 -0
- argus/backend/plugins/driver_matrix_tests/model.py +252 -4
- argus/backend/plugins/driver_matrix_tests/raw_types.py +27 -0
- argus/backend/plugins/driver_matrix_tests/service.py +18 -0
- argus/backend/plugins/driver_matrix_tests/udt.py +14 -13
- argus/backend/plugins/generic/model.py +6 -3
- argus/backend/plugins/loader.py +2 -2
- argus/backend/plugins/sct/controller.py +31 -0
- argus/backend/plugins/sct/plugin.py +2 -1
- argus/backend/plugins/sct/service.py +101 -3
- argus/backend/plugins/sct/testrun.py +8 -2
- argus/backend/plugins/sct/types.py +18 -0
- argus/backend/plugins/sct/udt.py +6 -0
- argus/backend/plugins/sirenada/model.py +1 -1
- argus/backend/service/argus_service.py +116 -11
- argus/backend/service/build_system_monitor.py +37 -7
- argus/backend/service/jenkins_service.py +176 -1
- argus/backend/service/release_manager.py +14 -0
- argus/backend/service/stats.py +179 -21
- argus/backend/service/testrun.py +44 -5
- argus/backend/service/views.py +258 -0
- argus/backend/template_filters.py +7 -0
- argus/backend/util/common.py +14 -2
- argus/client/driver_matrix_tests/cli.py +110 -0
- argus/client/driver_matrix_tests/client.py +56 -193
- argus/client/sct/client.py +34 -0
- argus_alm-0.12.4b1.dist-info/METADATA +129 -0
- {argus_alm-0.12.2.dist-info → argus_alm-0.12.4b1.dist-info}/RECORD +39 -36
- {argus_alm-0.12.2.dist-info → argus_alm-0.12.4b1.dist-info}/WHEEL +1 -1
- {argus_alm-0.12.2.dist-info → argus_alm-0.12.4b1.dist-info}/entry_points.txt +1 -0
- argus_alm-0.12.2.dist-info/METADATA +0 -206
- {argus_alm-0.12.2.dist-info → argus_alm-0.12.4b1.dist-info}/LICENSE +0 -0
argus/backend/cli.py
CHANGED
|
@@ -22,7 +22,7 @@ def sync_models_command():
|
|
|
22
22
|
LOGGER.info("Synchronizing plugin type %s...", user_type.__name__)
|
|
23
23
|
sync_type(ks_name=cluster.config["SCYLLA_KEYSPACE_NAME"], type_model=user_type)
|
|
24
24
|
LOGGER.info("Synchronizing plugin models...")
|
|
25
|
-
for model in all_plugin_models():
|
|
25
|
+
for model in all_plugin_models(True):
|
|
26
26
|
LOGGER.info("Synchronizing plugin model %s...", model.__name__)
|
|
27
27
|
sync_table(model=model, keyspaces=[cluster.config["SCYLLA_KEYSPACE_NAME"]])
|
|
28
28
|
|
|
@@ -261,3 +261,29 @@ def get_tests_for_group():
|
|
|
261
261
|
"status": "ok",
|
|
262
262
|
"response": tests
|
|
263
263
|
}
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
@bp.route("/release/test/state/toggle", methods=["POST"])
|
|
267
|
+
@check_roles(UserRoles.Admin)
|
|
268
|
+
@api_login_required
|
|
269
|
+
def quick_toggle_test_enabled():
|
|
270
|
+
|
|
271
|
+
payload = get_payload(request)
|
|
272
|
+
res = ReleaseManagerService().toggle_test_enabled(test_id=payload["entityId"], new_state=payload["state"])
|
|
273
|
+
return {
|
|
274
|
+
"status": "ok",
|
|
275
|
+
"response": res
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
@bp.route("/release/group/state/toggle", methods=["POST"])
|
|
280
|
+
@check_roles(UserRoles.Admin)
|
|
281
|
+
@api_login_required
|
|
282
|
+
def quick_toggle_group_enabled():
|
|
283
|
+
|
|
284
|
+
payload = get_payload(request)
|
|
285
|
+
res = ReleaseManagerService().toggle_group_enabled(group_id=payload["entityId"], new_state=payload["state"])
|
|
286
|
+
return {
|
|
287
|
+
"status": "ok",
|
|
288
|
+
"response": res
|
|
289
|
+
}
|
argus/backend/controller/api.py
CHANGED
|
@@ -12,7 +12,8 @@ from argus.backend.controller.notification_api import bp as notifications_bp
|
|
|
12
12
|
from argus.backend.controller.client_api import bp as client_bp
|
|
13
13
|
from argus.backend.controller.testrun_api import bp as testrun_bp
|
|
14
14
|
from argus.backend.controller.team import bp as team_bp
|
|
15
|
-
from argus.backend.
|
|
15
|
+
from argus.backend.controller.view_api import bp as view_bp
|
|
16
|
+
from argus.backend.service.argus_service import ArgusService, ScheduleUpdateRequest
|
|
16
17
|
from argus.backend.service.user import UserService, api_login_required
|
|
17
18
|
from argus.backend.service.stats import ReleaseStatsCollector
|
|
18
19
|
from argus.backend.models.web import ArgusRelease, ArgusGroup, ArgusTest, User, UserOauthToken
|
|
@@ -23,6 +24,7 @@ bp.register_blueprint(notifications_bp)
|
|
|
23
24
|
bp.register_blueprint(client_bp)
|
|
24
25
|
bp.register_blueprint(testrun_bp)
|
|
25
26
|
bp.register_blueprint(team_bp)
|
|
27
|
+
bp.register_blueprint(view_bp)
|
|
26
28
|
bp.register_error_handler(Exception, handle_api_exception)
|
|
27
29
|
LOGGER = logging.getLogger(__name__)
|
|
28
30
|
|
|
@@ -227,6 +229,8 @@ def release_schedules_submit():
|
|
|
227
229
|
groups=payload["groups"],
|
|
228
230
|
assignees=payload["assignees"],
|
|
229
231
|
tag=payload["tag"],
|
|
232
|
+
comments=payload.get("comments"),
|
|
233
|
+
group_ids=payload.get("groupIds"),
|
|
230
234
|
)
|
|
231
235
|
|
|
232
236
|
return jsonify({
|
|
@@ -251,6 +255,27 @@ def release_schedules_delete():
|
|
|
251
255
|
})
|
|
252
256
|
|
|
253
257
|
|
|
258
|
+
@bp.route("/release/schedules/update", methods=["POST"])
|
|
259
|
+
@api_login_required
|
|
260
|
+
def release_schedule_update():
|
|
261
|
+
payload = get_payload(request)
|
|
262
|
+
req = ScheduleUpdateRequest(**payload)
|
|
263
|
+
service = ArgusService()
|
|
264
|
+
update_result = service.update_schedule(
|
|
265
|
+
release_id=req.release_id,
|
|
266
|
+
schedule_id=req.schedule_id,
|
|
267
|
+
old_tests=req.old_tests,
|
|
268
|
+
new_tests=req.new_tests,
|
|
269
|
+
comments=req.comments,
|
|
270
|
+
assignee=req.assignee
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
return jsonify({
|
|
274
|
+
"status": "ok",
|
|
275
|
+
"response": update_result
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
|
|
254
279
|
@bp.route("/groups", methods=["GET"])
|
|
255
280
|
@api_login_required
|
|
256
281
|
def argus_groups():
|
argus/backend/controller/main.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import json
|
|
1
3
|
import logging
|
|
2
4
|
from uuid import UUID
|
|
3
5
|
from flask import (
|
|
@@ -8,6 +10,7 @@ from argus.backend.controller.team_ui import bp as teams_bp
|
|
|
8
10
|
from argus.backend.service.argus_service import ArgusService
|
|
9
11
|
from argus.backend.models.web import WebFileStorage
|
|
10
12
|
from argus.backend.service.user import UserService, login_required
|
|
13
|
+
from argus.backend.service.views import UserViewService
|
|
11
14
|
|
|
12
15
|
LOGGER = logging.getLogger(__name__)
|
|
13
16
|
|
|
@@ -55,6 +58,24 @@ def releases():
|
|
|
55
58
|
return render_template("releases.html.j2", releases=all_releases)
|
|
56
59
|
|
|
57
60
|
|
|
61
|
+
@bp.route("/views")
|
|
62
|
+
@login_required
|
|
63
|
+
def views():
|
|
64
|
+
service = UserViewService()
|
|
65
|
+
all_views = service.get_all_views()
|
|
66
|
+
return render_template("views.html.j2", views=sorted(all_views, key=lambda view: view.created or datetime.datetime.fromtimestamp(0), reverse=True))
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@bp.route("/view/<string:view_name>")
|
|
70
|
+
@login_required
|
|
71
|
+
def view_dashboard(view_name: str):
|
|
72
|
+
service = UserViewService()
|
|
73
|
+
view = service.get_view_by_name(view_name=view_name)
|
|
74
|
+
data_json = view
|
|
75
|
+
view["widget_settings"] = json.loads(view["widget_settings"])
|
|
76
|
+
return render_template("view_dashboard.html.j2", data=data_json)
|
|
77
|
+
|
|
78
|
+
|
|
58
79
|
@bp.route("/alert_debug")
|
|
59
80
|
@login_required
|
|
60
81
|
def alert_debug():
|
|
@@ -6,6 +6,7 @@ from flask import (
|
|
|
6
6
|
)
|
|
7
7
|
|
|
8
8
|
from argus.backend.error_handlers import handle_api_exception
|
|
9
|
+
from argus.backend.models.web import ArgusTest
|
|
9
10
|
from argus.backend.service.jenkins_service import JenkinsService
|
|
10
11
|
from argus.backend.service.testrun import TestRunService
|
|
11
12
|
from argus.backend.service.user import api_login_required
|
|
@@ -288,6 +289,22 @@ def ignore_jobs():
|
|
|
288
289
|
}
|
|
289
290
|
|
|
290
291
|
|
|
292
|
+
@bp.route("/get_runs_by_test_id_run_id", methods=["POST"])
|
|
293
|
+
@api_login_required
|
|
294
|
+
def get_runs_by_test_id_run_id():
|
|
295
|
+
payload: list[tuple[UUID, UUID]] = get_payload(request)
|
|
296
|
+
service = TestRunService()
|
|
297
|
+
|
|
298
|
+
result = service.resolve_run_build_id_and_number_multiple(payload)
|
|
299
|
+
|
|
300
|
+
return {
|
|
301
|
+
"status": "ok",
|
|
302
|
+
"response": {
|
|
303
|
+
"runs": result
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
|
|
291
308
|
@bp.route("/jenkins/params", methods=["POST"])
|
|
292
309
|
@api_login_required
|
|
293
310
|
def get_jenkins_job_params():
|
|
@@ -336,4 +353,118 @@ def get_queue_info():
|
|
|
336
353
|
"response": {
|
|
337
354
|
"queueItem": result
|
|
338
355
|
}
|
|
339
|
-
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
@bp.route("/jenkins/clone/targets")
|
|
360
|
+
@api_login_required
|
|
361
|
+
def get_clone_targets():
|
|
362
|
+
test_id = request.args.get("testId")
|
|
363
|
+
if not test_id:
|
|
364
|
+
raise Exception("No testId provided")
|
|
365
|
+
service = JenkinsService()
|
|
366
|
+
result = service.get_releases_for_clone(test_id)
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
"status": "ok",
|
|
370
|
+
"response": {
|
|
371
|
+
"targets": result
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
@bp.route("/jenkins/clone/groups")
|
|
377
|
+
@api_login_required
|
|
378
|
+
def get_groups_for_target():
|
|
379
|
+
target_id = request.args.get("targetId")
|
|
380
|
+
if not target_id:
|
|
381
|
+
raise Exception("No targetId provided")
|
|
382
|
+
service = JenkinsService()
|
|
383
|
+
result = service.get_groups_for_release(target_id)
|
|
384
|
+
|
|
385
|
+
return {
|
|
386
|
+
"status": "ok",
|
|
387
|
+
"response": {
|
|
388
|
+
"groups": result
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
@bp.route("/jenkins/clone/create", methods=["POST"])
|
|
394
|
+
@api_login_required
|
|
395
|
+
def clone_jenkins_job():
|
|
396
|
+
|
|
397
|
+
payload = get_payload(request)
|
|
398
|
+
service = JenkinsService()
|
|
399
|
+
|
|
400
|
+
result = service.clone_job(
|
|
401
|
+
current_test_id=payload["currentTestId"],
|
|
402
|
+
new_name=payload["newName"],
|
|
403
|
+
target=payload["target"],
|
|
404
|
+
group=payload["group"],
|
|
405
|
+
advanced_settings=payload["advancedSettings"],
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
return {
|
|
409
|
+
"status": "ok",
|
|
410
|
+
"response": result
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
@bp.route("/jenkins/clone/build", methods=["POST"])
|
|
415
|
+
@api_login_required
|
|
416
|
+
def clone_build_jenkins_job():
|
|
417
|
+
|
|
418
|
+
payload = get_payload(request)
|
|
419
|
+
service = JenkinsService()
|
|
420
|
+
|
|
421
|
+
result = service.clone_build_job(build_id=payload["buildId"], params=payload["parameters"])
|
|
422
|
+
|
|
423
|
+
return {
|
|
424
|
+
"status": "ok",
|
|
425
|
+
"response": result
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
@bp.route("/jenkins/clone/settings")
|
|
430
|
+
@api_login_required
|
|
431
|
+
def get_clone_job_advanced_settings():
|
|
432
|
+
build_id = request.args.get("buildId")
|
|
433
|
+
if not build_id:
|
|
434
|
+
raise Exception("No testId provided")
|
|
435
|
+
service = JenkinsService()
|
|
436
|
+
result = service.get_advanced_settings(build_id)
|
|
437
|
+
|
|
438
|
+
return {
|
|
439
|
+
"status": "ok",
|
|
440
|
+
"response": result
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
@bp.route("/jenkins/clone/settings/change", methods=["POST"])
|
|
445
|
+
@api_login_required
|
|
446
|
+
def set_job_settings():
|
|
447
|
+
payload = get_payload(request)
|
|
448
|
+
service = JenkinsService()
|
|
449
|
+
test = ArgusTest.get(build_system_id=payload["buildId"])
|
|
450
|
+
result = service.adjust_job_settings(build_id=test.build_system_id, plugin_name=test.plugin_name, settings=payload["settings"])
|
|
451
|
+
|
|
452
|
+
return {
|
|
453
|
+
"status": "ok",
|
|
454
|
+
"response": result
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
@bp.route("/jenkins/clone/settings/validate", methods=["POST"])
|
|
459
|
+
@api_login_required
|
|
460
|
+
def clone_validate_new_settings():
|
|
461
|
+
|
|
462
|
+
payload = get_payload(request)
|
|
463
|
+
service = JenkinsService()
|
|
464
|
+
|
|
465
|
+
result = service.verify_job_settings(build_id=payload["buildId"], new_settings=payload["newSettings"])
|
|
466
|
+
|
|
467
|
+
return {
|
|
468
|
+
"status": "ok",
|
|
469
|
+
"response": result
|
|
470
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from uuid import UUID
|
|
3
|
+
from flask import (
|
|
4
|
+
Blueprint,
|
|
5
|
+
jsonify,
|
|
6
|
+
request,
|
|
7
|
+
)
|
|
8
|
+
from argus.backend.error_handlers import handle_api_exception
|
|
9
|
+
from argus.backend.models.web import User
|
|
10
|
+
from argus.backend.service.stats import ViewStatsCollector
|
|
11
|
+
from argus.backend.service.user import api_login_required
|
|
12
|
+
from argus.backend.service.views import UserViewService
|
|
13
|
+
from argus.backend.util.common import get_payload
|
|
14
|
+
|
|
15
|
+
bp = Blueprint('view_api', __name__, url_prefix='/views')
|
|
16
|
+
LOGGER = logging.getLogger(__name__)
|
|
17
|
+
bp.register_error_handler(Exception, handle_api_exception)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ViewApiException(Exception):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@bp.route("/", methods=["GET"])
|
|
25
|
+
@api_login_required
|
|
26
|
+
def index():
|
|
27
|
+
return {
|
|
28
|
+
"status": "ok",
|
|
29
|
+
"response": {
|
|
30
|
+
"version": "v1",
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@bp.route("/create", methods=["POST"])
|
|
36
|
+
@api_login_required
|
|
37
|
+
def create_view():
|
|
38
|
+
payload = get_payload(request)
|
|
39
|
+
service = UserViewService()
|
|
40
|
+
view = service.create_view(
|
|
41
|
+
name=payload["name"],
|
|
42
|
+
items=payload["items"],
|
|
43
|
+
widget_settings=payload["settings"],
|
|
44
|
+
description=payload.get("description"),
|
|
45
|
+
display_name=payload.get("displayName")
|
|
46
|
+
)
|
|
47
|
+
return {
|
|
48
|
+
"status": "ok",
|
|
49
|
+
"response": view
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@bp.route("/get", methods=["GET"])
|
|
54
|
+
@api_login_required
|
|
55
|
+
def get_view():
|
|
56
|
+
view_id = request.args.get("viewId")
|
|
57
|
+
if not view_id:
|
|
58
|
+
raise ViewApiException("No viewId provided.")
|
|
59
|
+
service = UserViewService()
|
|
60
|
+
view = service.get_view(UUID(view_id))
|
|
61
|
+
return {
|
|
62
|
+
"status": "ok",
|
|
63
|
+
"response": view
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@bp.route("/all", methods=["GET"])
|
|
68
|
+
@api_login_required
|
|
69
|
+
def get_all_views():
|
|
70
|
+
user_id = request.args.get("userId")
|
|
71
|
+
if user_id:
|
|
72
|
+
user = User.get(id=user_id)
|
|
73
|
+
else:
|
|
74
|
+
user = None
|
|
75
|
+
service = UserViewService()
|
|
76
|
+
views = service.get_all_views(user)
|
|
77
|
+
return {
|
|
78
|
+
"status": "ok",
|
|
79
|
+
"response": views
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@bp.route("/update", methods=["POST"])
|
|
84
|
+
@api_login_required
|
|
85
|
+
def update_view():
|
|
86
|
+
payload = get_payload(request)
|
|
87
|
+
service = UserViewService()
|
|
88
|
+
res = service.update_view(view_id=payload["viewId"], update_data=payload["updateData"])
|
|
89
|
+
return {
|
|
90
|
+
"status": "ok",
|
|
91
|
+
"response": res
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@bp.route("/delete", methods=["POST"])
|
|
96
|
+
@api_login_required
|
|
97
|
+
def delete_view():
|
|
98
|
+
payload = get_payload(request)
|
|
99
|
+
service = UserViewService()
|
|
100
|
+
res = service.delete_view(payload["viewId"])
|
|
101
|
+
return {
|
|
102
|
+
"status": "ok",
|
|
103
|
+
"response": res
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@bp.route("/search", methods=["GET"])
|
|
108
|
+
@api_login_required
|
|
109
|
+
def search_tests():
|
|
110
|
+
query = request.args.get("query")
|
|
111
|
+
service = UserViewService()
|
|
112
|
+
if query:
|
|
113
|
+
res = service.test_lookup(query)
|
|
114
|
+
else:
|
|
115
|
+
res = []
|
|
116
|
+
return {
|
|
117
|
+
"status": "ok",
|
|
118
|
+
"response": {
|
|
119
|
+
"hits": res,
|
|
120
|
+
"total": len(res)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@bp.route("/stats", methods=["GET"])
|
|
125
|
+
@api_login_required
|
|
126
|
+
def view_stats():
|
|
127
|
+
view_id = request.args.get("viewId")
|
|
128
|
+
if not view_id:
|
|
129
|
+
raise ViewApiException("No view id provided.")
|
|
130
|
+
limited = bool(int(request.args.get("limited", 0)))
|
|
131
|
+
version = request.args.get("productVersion", None)
|
|
132
|
+
include_no_version = bool(int(request.args.get("includeNoVersion", True)))
|
|
133
|
+
force = bool(int(request.args.get("force", 0)))
|
|
134
|
+
collector = ViewStatsCollector(view_id=view_id, filter=version)
|
|
135
|
+
stats = collector.collect(limited=limited, force=force, include_no_version=include_no_version)
|
|
136
|
+
|
|
137
|
+
res = jsonify({
|
|
138
|
+
"status": "ok",
|
|
139
|
+
"response": stats
|
|
140
|
+
})
|
|
141
|
+
res.cache_control.max_age = 300
|
|
142
|
+
return res
|
|
143
|
+
|
|
144
|
+
@bp.route("/<string:view_id>/versions", methods=["GET"])
|
|
145
|
+
@api_login_required
|
|
146
|
+
def view_versions(view_id: str):
|
|
147
|
+
service = UserViewService()
|
|
148
|
+
res = service.get_versions_for_view(view_id)
|
|
149
|
+
return {
|
|
150
|
+
"status": "ok",
|
|
151
|
+
"response": res
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@bp.route("/<string:view_id>/resolve", methods=["GET"])
|
|
155
|
+
@api_login_required
|
|
156
|
+
def view_resolve(view_id: str):
|
|
157
|
+
service = UserViewService()
|
|
158
|
+
res = service.resolve_view_for_edit(view_id)
|
|
159
|
+
return {
|
|
160
|
+
"status": "ok",
|
|
161
|
+
"response": res
|
|
162
|
+
}
|
argus/backend/models/web.py
CHANGED
|
@@ -146,6 +146,20 @@ class ArgusGroup(Model):
|
|
|
146
146
|
return super().__eq__(other)
|
|
147
147
|
|
|
148
148
|
|
|
149
|
+
class ArgusUserView(Model):
|
|
150
|
+
id = columns.UUID(primary_key=True, partition_key=True, default=uuid4)
|
|
151
|
+
name = columns.Text(required=True, index=True)
|
|
152
|
+
display_name = columns.Text()
|
|
153
|
+
description = columns.Text()
|
|
154
|
+
user_id = columns.UUID(required=True, index=True)
|
|
155
|
+
tests = columns.List(value_type=columns.UUID, default=lambda: [])
|
|
156
|
+
release_ids = columns.List(value_type=columns.UUID, default=lambda: [])
|
|
157
|
+
group_ids = columns.List(value_type=columns.UUID, default=lambda: [])
|
|
158
|
+
created = columns.DateTime(default=datetime.utcnow)
|
|
159
|
+
last_updated = columns.DateTime(default=datetime.utcnow)
|
|
160
|
+
widget_settings = columns.Text(required=True)
|
|
161
|
+
|
|
162
|
+
|
|
149
163
|
class ArgusTest(Model):
|
|
150
164
|
__table_name__ = "argus_test_v2"
|
|
151
165
|
id = columns.UUID(primary_key=True, default=uuid4)
|
|
@@ -180,6 +194,7 @@ class ArgusTestRunComment(Model):
|
|
|
180
194
|
test_run_id = columns.UUID(required=True, index=True)
|
|
181
195
|
user_id = columns.UUID(required=True, index=True)
|
|
182
196
|
release_id = columns.UUID(required=True, index=True)
|
|
197
|
+
test_id = columns.UUID(required=True, index=True)
|
|
183
198
|
posted_at = columns.Integer(
|
|
184
199
|
required=True, clustering_order="desc", primary_key=True)
|
|
185
200
|
message = columns.Text(min_length=1, max_length=65535)
|
|
@@ -350,6 +365,7 @@ USED_MODELS: list[Model] = [
|
|
|
350
365
|
Team,
|
|
351
366
|
WebFileStorage,
|
|
352
367
|
ArgusRelease,
|
|
368
|
+
ArgusUserView,
|
|
353
369
|
ArgusGroup,
|
|
354
370
|
ArgusTest,
|
|
355
371
|
ArgusTestRunComment,
|
argus/backend/plugins/core.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from datetime import datetime
|
|
3
|
+
from math import ceil
|
|
3
4
|
from uuid import UUID
|
|
4
5
|
from time import time
|
|
5
6
|
|
|
@@ -16,8 +17,10 @@ from argus.backend.models.web import (
|
|
|
16
17
|
ArgusSchedule,
|
|
17
18
|
ArgusScheduleTest,
|
|
18
19
|
ArgusScheduleAssignee,
|
|
20
|
+
ArgusUserView,
|
|
19
21
|
User
|
|
20
22
|
)
|
|
23
|
+
from argus.backend.util.common import chunk
|
|
21
24
|
from argus.backend.util.enums import TestInvestigationStatus, TestStatus
|
|
22
25
|
|
|
23
26
|
LOGGER = logging.getLogger(__name__)
|
|
@@ -27,7 +30,7 @@ class PluginModelBase(Model):
|
|
|
27
30
|
_plugin_name = "unknown"
|
|
28
31
|
# Metadata
|
|
29
32
|
build_id = columns.Text(required=True, partition_key=True)
|
|
30
|
-
start_time = columns.DateTime(required=True, primary_key=True, clustering_order="DESC", default=datetime.
|
|
33
|
+
start_time = columns.DateTime(required=True, primary_key=True, clustering_order="DESC", default=datetime.utcnow, custom_index=True)
|
|
31
34
|
id = columns.UUID(index=True, required=True)
|
|
32
35
|
release_id = columns.UUID(index=True)
|
|
33
36
|
group_id = columns.UUID(index=True)
|
|
@@ -132,13 +135,18 @@ class PluginModelBase(Model):
|
|
|
132
135
|
return bound_query
|
|
133
136
|
|
|
134
137
|
@classmethod
|
|
135
|
-
def get_stats_for_release(cls, release: ArgusRelease):
|
|
138
|
+
def get_stats_for_release(cls, release: ArgusRelease, build_ids=list[str]):
|
|
136
139
|
cluster = ScyllaCluster.get()
|
|
137
140
|
query = cluster.prepare(cls._stats_query())
|
|
138
|
-
|
|
141
|
+
futures = []
|
|
142
|
+
step_size = 90
|
|
139
143
|
|
|
140
|
-
|
|
144
|
+
for step in range(0, ceil(len(build_ids) / step_size)):
|
|
145
|
+
start_pos = step*step_size
|
|
146
|
+
next_slice = build_ids[start_pos:start_pos+step_size]
|
|
147
|
+
futures.append(cluster.session.execute_async(query=query, parameters=(next_slice,)))
|
|
141
148
|
|
|
149
|
+
return futures
|
|
142
150
|
@classmethod
|
|
143
151
|
def get_run_meta_by_build_id(cls, build_id: str, limit: int = 10):
|
|
144
152
|
cluster = ScyllaCluster.get()
|
|
@@ -169,6 +177,21 @@ class PluginModelBase(Model):
|
|
|
169
177
|
def get_distinct_product_versions(cls, release: ArgusRelease) -> list[str]:
|
|
170
178
|
raise NotImplementedError()
|
|
171
179
|
|
|
180
|
+
@classmethod
|
|
181
|
+
def get_distinct_versions_for_view(cls, tests: list[ArgusTest]) -> list[str]:
|
|
182
|
+
cluster = ScyllaCluster.get()
|
|
183
|
+
statement = cluster.prepare(f"SELECT scylla_version FROM {cls.table_name()} WHERE build_id IN ?")
|
|
184
|
+
futures = []
|
|
185
|
+
for batch in chunk(tests):
|
|
186
|
+
futures.append(cluster.session.execute_async(query=statement, parameters=([t.build_system_id for t in batch],)))
|
|
187
|
+
|
|
188
|
+
rows = []
|
|
189
|
+
for future in futures:
|
|
190
|
+
rows.extend(future.result())
|
|
191
|
+
unique_versions = {r["scylla_version"] for r in rows if r["scylla_version"]}
|
|
192
|
+
|
|
193
|
+
return sorted(list(unique_versions), reverse=True)
|
|
194
|
+
|
|
172
195
|
def update_heartbeat(self):
|
|
173
196
|
self.heartbeat = int(time())
|
|
174
197
|
|
|
@@ -181,7 +204,7 @@ class PluginModelBase(Model):
|
|
|
181
204
|
def submit_product_version(self, version: str):
|
|
182
205
|
raise NotImplementedError()
|
|
183
206
|
|
|
184
|
-
def
|
|
207
|
+
def set_full_version(self, version: str):
|
|
185
208
|
self.product_version = version
|
|
186
209
|
|
|
187
210
|
def submit_logs(self, logs: list[dict]):
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
from flask import Blueprint, request
|
|
2
2
|
|
|
3
3
|
from argus.backend.error_handlers import handle_api_exception
|
|
4
|
+
from argus.backend.plugins.driver_matrix_tests.raw_types import DriverMatrixSubmitEnvRequest, DriverMatrixSubmitFailureRequest, DriverMatrixSubmitResultRequest
|
|
4
5
|
from argus.backend.service.user import api_login_required
|
|
5
6
|
from argus.backend.plugins.driver_matrix_tests.service import DriverMatrixService
|
|
7
|
+
from argus.backend.util.common import get_payload
|
|
6
8
|
|
|
7
9
|
bp = Blueprint("driver_matrix_api", __name__, url_prefix="/driver_matrix")
|
|
8
10
|
bp.register_error_handler(Exception, handle_api_exception)
|
|
@@ -22,3 +24,40 @@ def driver_matrix_test_report():
|
|
|
22
24
|
"status": "ok",
|
|
23
25
|
"response": result
|
|
24
26
|
}
|
|
27
|
+
|
|
28
|
+
@bp.route("/result/submit", methods=["POST"])
|
|
29
|
+
@api_login_required
|
|
30
|
+
def submit_result():
|
|
31
|
+
payload = get_payload(request)
|
|
32
|
+
request_data = DriverMatrixSubmitResultRequest(**payload)
|
|
33
|
+
|
|
34
|
+
result = DriverMatrixService().submit_driver_result(driver_name=request_data.driver_name, driver_type=request_data.driver_type, run_id=request_data.run_id, raw_xml=request_data.raw_xml)
|
|
35
|
+
return {
|
|
36
|
+
"status": "ok",
|
|
37
|
+
"response": result
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@bp.route("/result/fail", methods=["POST"])
|
|
42
|
+
@api_login_required
|
|
43
|
+
def submit_failure():
|
|
44
|
+
payload = get_payload(request)
|
|
45
|
+
request_data = DriverMatrixSubmitFailureRequest(**payload)
|
|
46
|
+
|
|
47
|
+
result = DriverMatrixService().submit_driver_failure(driver_name=request_data.driver_name, driver_type=request_data.driver_type, run_id=request_data.run_id, failure_reason=request_data.failure_reason)
|
|
48
|
+
return {
|
|
49
|
+
"status": "ok",
|
|
50
|
+
"response": result
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@bp.route("/env/submit", methods=["POST"])
|
|
54
|
+
@api_login_required
|
|
55
|
+
def submit_env():
|
|
56
|
+
payload = get_payload(request)
|
|
57
|
+
request_data = DriverMatrixSubmitEnvRequest(**payload)
|
|
58
|
+
|
|
59
|
+
result = DriverMatrixService().submit_env_info(run_id=request_data.run_id, raw_env=request_data.raw_env)
|
|
60
|
+
return {
|
|
61
|
+
"status": "ok",
|
|
62
|
+
"response": result
|
|
63
|
+
}
|