From 06b899172b8c69783f531ddd51f2d7ababc3254c Mon Sep 17 00:00:00 2001 From: lfjnascimento Date: Fri, 12 Jul 2024 17:08:18 -0300 Subject: [PATCH] feat: add enpoint for tree details closes #85 --- backend/kernelCI_app/serializers.py | 14 +++++ backend/kernelCI_app/urls.py | 3 +- backend/kernelCI_app/views.py | 88 ++++++++++++++++++++++++++++- 3 files changed, 102 insertions(+), 3 deletions(-) diff --git a/backend/kernelCI_app/serializers.py b/backend/kernelCI_app/serializers.py index ffa6a71..334fa57 100644 --- a/backend/kernelCI_app/serializers.py +++ b/backend/kernelCI_app/serializers.py @@ -67,3 +67,17 @@ def get_test_status(self, obj): "null": obj.null_tests, "total": obj.total_tests } + + +class TreeDetailsSerializer(serializers.Serializer): + id = serializers.CharField() + architecture = serializers.CharField() + config_name = serializers.CharField() + valid = serializers.BooleanField() + start_time = serializers.CharField() + duration = serializers.CharField() + compiler = serializers.CharField() + config_url = serializers.CharField() + log_url = serializers.CharField() + test_status = serializers.DictField() + misc = serializers.JSONField() diff --git a/backend/kernelCI_app/urls.py b/backend/kernelCI_app/urls.py index 7084c79..0ee011c 100644 --- a/backend/kernelCI_app/urls.py +++ b/backend/kernelCI_app/urls.py @@ -3,5 +3,6 @@ urlpatterns = [ - path('tree/', views.TreeView.as_view(), name='tree') + path('tree/', views.TreeView.as_view(), name='tree'), + path('tree/', views.TreeDetails.as_view(), name='treeDetails') ] diff --git a/backend/kernelCI_app/views.py b/backend/kernelCI_app/views.py index 82f3544..9816083 100644 --- a/backend/kernelCI_app/views.py +++ b/backend/kernelCI_app/views.py @@ -1,8 +1,8 @@ from django.http import JsonResponse from django.views import View -from kernelCI_app.models import Checkouts -from kernelCI_app.serializers import TreeSerializer +from kernelCI_app.models import Checkouts, Builds +from kernelCI_app.serializers import TreeSerializer, TreeDetailsSerializer from kernelCI_app.utils import get_visible_record_identifiers @@ -46,3 +46,87 @@ def get(self, _): serializer = TreeSerializer(checkouts, many=True) resp = JsonResponse(serializer.data, safe=False) return resp + + +class TreeDetails(View): + + def create_default_status(self): + return {"valid": 0, "invalid": 0, "null": 0} + + def create_summary(self, builds_dict): + status_map = {True: 'valid', False: 'invalid', None: 'null'} + + build_summ = self.create_default_status() + config_summ = {} + arch_summ = {} + + for build in builds_dict: + status_key = status_map[build['valid']] + build_summ[status_key] += 1 + + if config := build['config_name']: + status = config_summ.get(config) + if not status: + status = self.create_default_status() + config_summ[config] = status + status[status_key] += 1 + + if arch := build['architecture']: + status = arch_summ.setdefault(arch, self.create_default_status()) + status[status_key] += 1 + compiler = build['compiler'] + if compiler and compiler not in status.setdefault('compilers', []): + status['compilers'].append(compiler) + + return {"builds": build_summ, "configs": config_summ, "architectures": arch_summ} + + def get_test_staus(self, build_id): + status_keys = ["fail_tests", "error_tests", "miss_tests", "pass_tests", + "done_tests", "skip_tests", "null_tests", "total_tests"] + builds = Builds.objects.raw( + """ + SELECT + builds.id, + COUNT(CASE WHEN tests.status = 'FAIL' THEN 1 END) AS fail_tests, + COUNT(CASE WHEN tests.status = 'ERROR' THEN 1 END) AS error_tests, + COUNT(CASE WHEN tests.status = 'MISS' THEN 1 END) AS miss_tests, + COUNT(CASE WHEN tests.status = 'PASS' THEN 1 END) AS pass_tests, + COUNT(CASE WHEN tests.status = 'DONE' THEN 1 END) AS done_tests, + COUNT(CASE WHEN tests.status = 'SKIP' THEN 1 END) AS skip_tests, + SUM(CASE WHEN tests.status IS NULL AND tests.id IS NOT NULL THEN 1 ELSE 0 END) + AS null_tests, + COUNT(tests.id) AS total_tests + FROM + builds + LEFT JOIN + tests ON tests.build_id = builds.id + WHERE builds.id = %s + GROUP BY builds.id; + """, + [build_id] + ) + return {k: getattr(builds[0], k) for k in status_keys} + + def get(self, request, commit_hash): + builds = Builds.objects.raw( + """ + SELECT + builds.id, builds.architecture, builds.config_name, builds.misc, + builds.config_url, builds.compiler, builds.valid, + builds.start_time, builds.duration, builds.log_url + FROM + builds + INNER JOIN + checkouts ON checkouts.id = builds.checkout_id + WHERE checkouts.git_commit_hash = %s; + """, + [commit_hash] + ) + + for build in builds: + build.test_status = self.get_test_staus(build.id) + + data = TreeDetailsSerializer(builds, many=True).data + summary = self.create_summary(data) + resp = {"builds": data, "summary": summary} + return JsonResponse(resp, safe=False)