WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 9a1d7a5

Browse files
committed
feat: add treeListingV2 view
Closes #1558
1 parent b683d6d commit 9a1d7a5

File tree

7 files changed

+229
-7
lines changed

7 files changed

+229
-7
lines changed

backend/kernelCI_app/queries/tree.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,49 @@ def get_tree_listing_data_by_checkout_id(*, checkout_ids: list[str]):
290290
return dict_fetchall(cursor=cursor)
291291

292292

293+
def get_tree_listing_data_denormalized(
294+
*, origin: str, interval_in_days: int
295+
) -> Optional[list[tuple]]:
296+
interval_param = f"{interval_in_days} days"
297+
params = {
298+
"origin_param": origin,
299+
"interval_param": interval_param,
300+
}
301+
302+
with connection.cursor() as cursor:
303+
cursor.execute(
304+
"""
305+
SELECT
306+
checkout_id,
307+
origin,
308+
tree_name,
309+
git_repository_url,
310+
git_repository_branch,
311+
git_commit_hash,
312+
git_commit_name,
313+
git_commit_tags,
314+
start_time,
315+
build_pass,
316+
build_failed,
317+
build_inc,
318+
boot_pass,
319+
boot_failed,
320+
boot_inc,
321+
test_pass,
322+
test_failed,
323+
test_inc
324+
FROM
325+
tree_listing
326+
WHERE
327+
start_time BETWEEN
328+
NOW() - INTERVAL %(interval_param)s AND NOW()
329+
AND origin = %(origin_param)s
330+
""",
331+
params,
332+
)
333+
return cursor.fetchall()
334+
335+
293336
def get_tree_details_data(
294337
*,
295338
origin_param: str,

backend/kernelCI_app/typeModels/commonListing.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Annotated
1+
from typing import Annotated, Optional
22
from pydantic import BaseModel, Field
33

44
from kernelCI_app.constants.general import DEFAULT_INTERVAL_IN_DAYS, DEFAULT_ORIGIN
@@ -27,3 +27,9 @@ class ListingQueryParameters(ListingInterval):
2727
),
2828
make_default_validator(DEFAULT_ORIGIN),
2929
]
30+
31+
32+
class StatusCountV2(BaseModel):
33+
PASS: Optional[int] = 0
34+
FAIL: Optional[int] = 0
35+
INCONCLUSIVE: Optional[int] = 0

backend/kernelCI_app/typeModels/hardwareListingV2.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
11
from datetime import datetime
2+
from kernelCI_app.typeModels.commonListing import StatusCountV2
23
from pydantic import BaseModel, BeforeValidator, Field
34
from typing import Annotated, Optional, Union
45

56
from kernelCI_app.constants.general import DEFAULT_ORIGIN
67
from kernelCI_app.constants.localization import DocStrings
78

89

9-
class StatusCountV2(BaseModel):
10-
PASS: Optional[int] = 0
11-
FAIL: Optional[int] = 0
12-
INCONCLUSIVE: Optional[int] = 0
13-
14-
1510
class HardwareItemV2(BaseModel):
1611
hardware: Optional[Union[str, set[str]]]
1712
platform: str

backend/kernelCI_app/typeModels/treeListing.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import List
22
from kernelCI_app.typeModels.common import StatusCount
3+
from kernelCI_app.typeModels.commonListing import StatusCountV2
34
from kernelCI_app.typeModels.databases import (
45
Checkout__GitCommitHash,
56
Checkout__GitCommitName,
@@ -79,3 +80,22 @@ class TreeListingResponse(RootModel):
7980

8081
class TreeListingFastResponse(RootModel):
8182
root: List[CheckoutFast]
83+
84+
85+
class TreeListingItem(BaseModel):
86+
id: Checkout__Id = Field(validation_alias="checkout_id")
87+
build_status: StatusCountV2
88+
boot_status: StatusCountV2
89+
test_status: StatusCountV2
90+
tree_name: Checkout__TreeName
91+
git_commit_tags: Checkout__GitCommitTags
92+
origin: Origin
93+
git_repository_url: Checkout__GitRepositoryUrl
94+
git_repository_branch: Checkout__GitRepositoryBranch
95+
git_commit_hash: Checkout__GitCommitHash
96+
git_commit_name: Checkout__GitCommitName
97+
start_time: Timestamp
98+
99+
100+
class TreeListingResponseV2(RootModel):
101+
root: list[TreeListingItem]

backend/kernelCI_app/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def view_cache(view):
2424
),
2525
path("test/<str:test_id>", view_cache(views.TestDetails), name="testDetails"),
2626
path("tree/", view_cache(views.TreeView), name="tree"),
27+
path("tree-v2/", view_cache(views.TreeViewV2), name="tree-v2"),
2728
path("tree-fast/", view_cache(views.TreeViewFast), name="tree-fast"),
2829
path(
2930
"tree/<str:commit_hash>/full",
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
from http import HTTPStatus
2+
from django.http import HttpRequest
3+
from drf_spectacular.utils import extend_schema
4+
from pydantic import ValidationError
5+
from rest_framework.response import Response
6+
from rest_framework.views import APIView
7+
from kernelCI_app.queries.tree import get_tree_listing_data_denormalized
8+
from kernelCI_app.typeModels.commonListing import ListingQueryParameters, StatusCountV2
9+
from kernelCI_app.typeModels.treeListing import TreeListingItem, TreeListingResponseV2
10+
from kernelCI_app.helpers.errorHandling import create_api_error_response
11+
from kernelCI_app.constants.localization import ClientStrings
12+
13+
14+
class TreeViewV2(APIView):
15+
def _sanitize_records(self, trees_raw: list[tuple]) -> list[TreeListingItem]:
16+
trees = []
17+
for tree in trees_raw:
18+
trees.append(
19+
TreeListingItem(
20+
id=tree[0],
21+
origin=tree[1],
22+
tree_name=tree[2],
23+
git_repository_url=tree[3],
24+
git_repository_branch=tree[4],
25+
git_commit_hash=tree[5],
26+
git_commit_name=tree[6],
27+
git_commit_tags=tree[7],
28+
start_time=tree[8],
29+
build_status=StatusCountV2(
30+
PASS=tree[9],
31+
FAIL=tree[10],
32+
INCONCLUSIVE=tree[11],
33+
),
34+
boot_status=StatusCountV2(
35+
PASS=tree[12],
36+
FAIL=tree[13],
37+
INCONCLUSIVE=tree[14],
38+
),
39+
test_status=StatusCountV2(
40+
PASS=tree[15],
41+
FAIL=tree[16],
42+
INCONCLUSIVE=tree[17],
43+
),
44+
)
45+
)
46+
47+
return trees
48+
49+
@extend_schema(
50+
parameters=[ListingQueryParameters],
51+
responses=TreeListingResponseV2,
52+
)
53+
def get(self, request: HttpRequest):
54+
try:
55+
query_params = ListingQueryParameters(
56+
origin=request.GET.get("origin"),
57+
interval_in_days=request.GET.get("interval_in_days"),
58+
)
59+
except ValidationError as e:
60+
return Response(data=e.json(), status=HTTPStatus.BAD_REQUEST)
61+
62+
trees_raw = get_tree_listing_data_denormalized(
63+
origin=query_params.origin,
64+
interval_in_days=query_params.interval_in_days,
65+
)
66+
67+
if not trees_raw:
68+
return create_api_error_response(
69+
error_message=ClientStrings.NO_TREES_FOUND,
70+
status_code=HTTPStatus.OK,
71+
)
72+
73+
try:
74+
sanitized_records = self._sanitize_records(trees_raw=trees_raw)
75+
result = TreeListingResponseV2(sanitized_records)
76+
except ValidationError as e:
77+
return Response(data=e.json(), status=HTTPStatus.INTERNAL_SERVER_ERROR)
78+
79+
return Response(data=result.model_dump(), status=HTTPStatus.OK)

backend/schema.yml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,38 @@ paths:
10341034
schema:
10351035
$ref: '#/components/schemas/TreeReportResponse'
10361036
description: ''
1037+
/api/tree-v2/:
1038+
get:
1039+
operationId: tree_v2_retrieve
1040+
parameters:
1041+
- in: query
1042+
name: interval_in_days
1043+
schema:
1044+
default: 7
1045+
exclusiveMinimum: 0
1046+
title: Interval In Days
1047+
type: integer
1048+
description: Interval in days for the listing
1049+
- in: query
1050+
name: origin
1051+
schema:
1052+
default: maestro
1053+
title: Origin
1054+
type: string
1055+
description: Origin filter
1056+
tags:
1057+
- tree-v2
1058+
security:
1059+
- cookieAuth: []
1060+
- basicAuth: []
1061+
- {}
1062+
responses:
1063+
'200':
1064+
content:
1065+
application/json:
1066+
schema:
1067+
$ref: '#/components/schemas/TreeListingResponseV2'
1068+
description: ''
10371069
/api/tree/{commit_hash}/boots:
10381070
get:
10391071
operationId: tree_boots_retrieve
@@ -3982,11 +4014,57 @@ components:
39824014
$ref: '#/components/schemas/CheckoutFast'
39834015
title: TreeListingFastResponse
39844016
type: array
4017+
TreeListingItem:
4018+
properties:
4019+
id:
4020+
$ref: '#/components/schemas/Checkout__Id'
4021+
build_status:
4022+
$ref: '#/components/schemas/StatusCountV2'
4023+
boot_status:
4024+
$ref: '#/components/schemas/StatusCountV2'
4025+
test_status:
4026+
$ref: '#/components/schemas/StatusCountV2'
4027+
tree_name:
4028+
$ref: '#/components/schemas/Checkout__TreeName'
4029+
git_commit_tags:
4030+
$ref: '#/components/schemas/Checkout__GitCommitTags'
4031+
origin:
4032+
$ref: '#/components/schemas/Origin'
4033+
git_repository_url:
4034+
$ref: '#/components/schemas/Checkout__GitRepositoryUrl'
4035+
git_repository_branch:
4036+
$ref: '#/components/schemas/Checkout__GitRepositoryBranch'
4037+
git_commit_hash:
4038+
$ref: '#/components/schemas/Checkout__GitCommitHash'
4039+
git_commit_name:
4040+
$ref: '#/components/schemas/Checkout__GitCommitName'
4041+
start_time:
4042+
$ref: '#/components/schemas/Timestamp'
4043+
required:
4044+
- id
4045+
- build_status
4046+
- boot_status
4047+
- test_status
4048+
- tree_name
4049+
- git_commit_tags
4050+
- origin
4051+
- git_repository_url
4052+
- git_repository_branch
4053+
- git_commit_hash
4054+
- git_commit_name
4055+
- start_time
4056+
title: TreeListingItem
4057+
type: object
39854058
TreeListingResponse:
39864059
items:
39874060
$ref: '#/components/schemas/Checkout'
39884061
title: TreeListingResponse
39894062
type: array
4063+
TreeListingResponseV2:
4064+
items:
4065+
$ref: '#/components/schemas/TreeListingItem'
4066+
title: TreeListingResponseV2
4067+
type: array
39904068
TreeReportIssues:
39914069
properties:
39924070
builds:

0 commit comments

Comments
 (0)