Skip to content

Commit 9cd79d2

Browse files
committed
refactor: unify treeLatest and treeLatestHash
Turns the commit_hash to an optional query parameter, allowing the endpoints to be combined. Updated types, documentation, integration tests, and frontend api call. Closes #1476
1 parent 0aa0114 commit 9cd79d2

File tree

8 files changed

+70
-196
lines changed

8 files changed

+70
-196
lines changed

backend/kernelCI_app/tests/integrationTests/treeLatest_test.py

Lines changed: 10 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -33,52 +33,26 @@
3333
"android-mainline",
3434
{
3535
"origin": "maestro",
36-
"git_commit_hash": "1064be81d694bc2b3c308de6b2951c21a3f89677",
36+
"commit_hash": "1064be81d694bc2b3c308de6b2951c21a3f89677",
3737
},
3838
False,
3939
),
40-
],
41-
)
42-
def test_tree_latest(tree_name, git_branch, query, has_error_body):
43-
response = client.get_tree_latest(
44-
tree_name=tree_name, git_branch=git_branch, query=query
45-
)
46-
content = string_to_json(response.content.decode())
47-
assert_status_code_and_error_response(
48-
response=response,
49-
content=content,
50-
status_code=HTTPStatus.OK,
51-
should_error=has_error_body,
52-
)
53-
54-
55-
@pytest.mark.parametrize(
56-
"tree_name, git_branch, commit_hash, query, has_error_body",
57-
[
58-
(
59-
"android",
60-
"android-mainline",
61-
"8dec85f986c74f6c94895d3b56f518de02f9e820",
62-
{},
63-
False,
64-
),
6540
(
6641
"mainline",
6742
"master",
68-
"c4dce0c094a89b1bc8fde1163342bd6fe29c0370",
69-
{"origin": "microsoft"},
43+
{
44+
"origin": "microsoft",
45+
"commit_hash": "c4dce0c094a89b1bc8fde1163342bd6fe29c0370",
46+
},
7047
False,
7148
),
72-
("android", "android-mainline", "wrong_hash", {}, True),
73-
("invalid_tree_name", "invalid_branch", "any_hash", {}, True),
49+
("android", "android-mainline", {"commit_hash": "wrong_hash"}, True),
50+
("invalid_tree_name", "invalid_branch", {"commit_hash": "any_hash"}, True),
7451
],
7552
)
76-
def test_tree_latest_hash(tree_name, git_branch, commit_hash, query, has_error_body):
77-
response = client.get_tree_latest_hash(
78-
tree_name=tree_name,
79-
git_branch=git_branch,
80-
commit_hash=commit_hash,
81-
query=query,
53+
def test_tree_latest(tree_name, git_branch, query, has_error_body):
54+
response = client.get_tree_latest(
55+
tree_name=tree_name, git_branch=git_branch, query=query
8256
)
8357
content = string_to_json(response.content.decode())
8458
assert_status_code_and_error_response(

backend/kernelCI_app/tests/utils/client/treeClient.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,6 @@ def get_tree_latest(
3434
url = self.get_endpoint(path=path, query=query)
3535
return requests.get(url)
3636

37-
def get_tree_latest_hash(
38-
self, *, tree_name: str, git_branch: str, commit_hash: str, query: dict
39-
) -> requests.Response:
40-
path = reverse(
41-
"treeLatestHash",
42-
kwargs={
43-
"tree_name": tree_name,
44-
"git_branch": git_branch,
45-
"commit_hash": commit_hash,
46-
},
47-
)
48-
url = self.get_endpoint(path=path, query=query)
49-
return requests.get(url)
50-
5137
def get_tree_details_summary(
5238
self,
5339
*,

backend/kernelCI_app/typeModels/treeDetails.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@
1616
class TreeLatestPathParameters(BaseModel):
1717
tree_name: str = Field(description=DocStrings.TREE_LATEST_TREE_NAME_DESCRIPTION)
1818
git_branch: str = Field(description=DocStrings.TREE_LATEST_GIT_BRANCH_DESCRIPTION)
19-
commit_hash: Optional[str] = Field(
20-
description=DocStrings.TREE_LATEST_COMMIT_HASH_DESCRIPTION
21-
)
2219

2320

2421
class TreeLatestQueryParameters(BaseModel):
2522
origin: str = Field(
2623
DEFAULT_ORIGIN, description=DocStrings.TREE_LATEST_ORIGIN_DESCRIPTION
2724
)
25+
commit_hash: Optional[str] = Field(
26+
None, description=DocStrings.TREE_LATEST_COMMIT_HASH_DESCRIPTION
27+
)
2828

2929

3030
class TreeLatestResponse(BaseCheckouts):

backend/kernelCI_app/urls.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,8 @@ def view_cache(view):
8686
name="treeDetailsTestsDirectView",
8787
),
8888
path(
89-
"tree/<str:tree_name>/<str:git_branch>/<str:commit_hash>",
90-
view_cache(views.TreeCheckoutInfo),
91-
name="treeLatestHash",
92-
),
93-
path(
94-
"tree/<str:tree_name>/<str:git_branch>",
95-
view_cache(views.TreeLatestCheckout),
89+
"tree/<str:tree_name>/<path:git_branch>",
90+
view_cache(views.TreeLatest),
9691
name="treeLatest",
9792
),
9893
path("build/<str:build_id>", view_cache(views.BuildDetails), name="buildDetails"),
Lines changed: 29 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
from http import HTTPStatus
2-
from typing import Optional
32
from urllib.parse import urlencode
43
from drf_spectacular.utils import extend_schema
54
from rest_framework.response import Response
65
from rest_framework.views import APIView
76

8-
from django.http import JsonResponse
7+
from django.http import HttpRequest, JsonResponse
98
from django.urls import reverse
109
from pydantic import ValidationError
1110

1211
from kernelCI_app.constants.general import DEFAULT_ORIGIN
13-
from kernelCI_app.helpers.errorHandling import create_api_error_response
1412
from kernelCI_app.queries.tree import get_latest_tree
1513
from kernelCI_app.typeModels.commonOpenApiParameters import (
16-
COMMIT_HASH_PATH_PARAM,
1714
GIT_BRANCH_PATH_PARAM,
1815
TREE_NAME_PATH_PARAM,
1916
)
@@ -25,46 +22,57 @@
2522
from kernelCI_app.constants.localization import ClientStrings
2623

2724

28-
class BaseTreeLatest(APIView):
29-
25+
class TreeLatest(APIView):
26+
@extend_schema(
27+
responses=TreeLatestResponse,
28+
parameters=[
29+
TREE_NAME_PATH_PARAM,
30+
GIT_BRANCH_PATH_PARAM,
31+
TreeLatestQueryParameters,
32+
],
33+
methods=["GET"],
34+
)
3035
def get(
3136
self,
32-
request,
37+
request: HttpRequest,
3338
tree_name: str,
3439
git_branch: str,
35-
commit_hash: Optional[str] = None,
3640
) -> JsonResponse:
3741
try:
3842
parsed_params = TreeLatestPathParameters(
39-
tree_name=tree_name, git_branch=git_branch, commit_hash=commit_hash
43+
tree_name=tree_name, git_branch=git_branch
4044
)
45+
query_params = TreeLatestQueryParameters(**request.GET.dict())
4146
except ValidationError as e:
4247
return Response(data=e.json, status=HTTPStatus.BAD_REQUEST)
4348

44-
tree_not_found_error_message = ClientStrings.TREE_NOT_FOUND
45-
origin = request.GET.get("origin")
46-
if origin is None:
47-
origin = DEFAULT_ORIGIN
48-
tree_not_found_error_message += (
49-
f"{ClientStrings.TREE_LATEST_DEFAULT_ORIGIN} {DEFAULT_ORIGIN}"
50-
)
49+
origin = query_params.origin
5150

5251
tree_data = get_latest_tree(
5352
tree_name=parsed_params.tree_name,
5453
git_branch=parsed_params.git_branch,
5554
origin=origin,
56-
git_commit_hash=parsed_params.commit_hash,
55+
git_commit_hash=query_params.commit_hash,
5756
)
5857

5958
if tree_data is None:
60-
return create_api_error_response(
61-
error_message=tree_not_found_error_message,
62-
status_code=HTTPStatus.OK,
59+
tree_not_found_error_message = ClientStrings.TREE_NOT_FOUND
60+
if request.GET.get("origin") is None:
61+
tree_not_found_error_message += (
62+
f" {ClientStrings.TREE_LATEST_DEFAULT_ORIGIN} {DEFAULT_ORIGIN}"
63+
)
64+
65+
params = parsed_params.model_dump()
66+
params.update(query_params.model_dump())
67+
68+
return Response(
69+
data={"error": tree_not_found_error_message, "params": params},
70+
status=HTTPStatus.OK,
6371
)
6472

6573
# The `old_api_url` is only used in the backend response in order to
6674
# keep compatibility with the full treeDetails endpoint in case someone
67-
# expects this format. It should be removed soon.
75+
# expects this format. It should be removed when we drop the support for the old format.
6876
# TODO: remove this field from the response.
6977
old_base_url = reverse(
7078
"treeDetailsView",
@@ -106,48 +114,3 @@ def get(
106114
return Response(data=e.json(), status=HTTPStatus.INTERNAL_SERVER_ERROR)
107115

108116
return Response(valid_response.model_dump())
109-
110-
111-
class TreeCheckoutInfo(BaseTreeLatest):
112-
@extend_schema(
113-
responses=TreeLatestResponse,
114-
parameters=[
115-
COMMIT_HASH_PATH_PARAM,
116-
TREE_NAME_PATH_PARAM,
117-
GIT_BRANCH_PATH_PARAM,
118-
TreeLatestQueryParameters,
119-
],
120-
methods=["GET"],
121-
)
122-
def get(
123-
self,
124-
request,
125-
tree_name: str,
126-
git_branch: str,
127-
commit_hash: str,
128-
) -> JsonResponse:
129-
return super().get(
130-
request=request,
131-
commit_hash=commit_hash,
132-
tree_name=tree_name,
133-
git_branch=git_branch,
134-
)
135-
136-
137-
class TreeLatestCheckout(BaseTreeLatest):
138-
@extend_schema(
139-
responses=TreeLatestResponse,
140-
parameters=[
141-
TREE_NAME_PATH_PARAM,
142-
GIT_BRANCH_PATH_PARAM,
143-
TreeLatestQueryParameters,
144-
],
145-
methods=["GET"],
146-
)
147-
def get(
148-
self,
149-
request,
150-
tree_name: str,
151-
git_branch: str,
152-
) -> JsonResponse:
153-
return super().get(request=request, tree_name=tree_name, git_branch=git_branch)
Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,26 @@
1-
http 'http://localhost:8000/api/tree/android/android-mainline'
2-
3-
# For more specific results, you can use origin parameter or add a git_commit_hash to the route
4-
http 'http://localhost:8000/api/tree/mainline/master/a33b5a08cbbdd7aadff95f40cbb45ab86841679e' origin==microsoft
1+
http 'http://localhost:8000/api/tree/mainline/master' origin==microsoft commit_hash==a33b5a08cbbdd7aadff95f40cbb45ab86841679e
52

63
# HTTP/1.1 200 OK
74
# Allow: GET, HEAD, OPTIONS
85
# Cache-Control: max-age=0
9-
# Content-Length: 489
6+
# Content-Length: 578
107
# Content-Type: application/json
118
# Cross-Origin-Opener-Policy: same-origin
12-
# Date: Thu, 26 Jun 2025 11:51:01 GMT
13-
# Expires: Thu, 26 Jun 2025 11:51:01 GMT
9+
# Date: Wed, 17 Sep 2025 11:59:45 GMT
10+
# Expires: Wed, 17 Sep 2025 11:59:45 GMT
1411
# Referrer-Policy: same-origin
1512
# Server: WSGIServer/0.2 CPython/3.12.7
1613
# Vary: Accept, Cookie, origin
1714
# X-Content-Type-Options: nosniff
1815
# X-Frame-Options: DENY
1916

2017
# {
21-
# "api_url": "/api/tree/mainline/master/a33b5a08cbbdd7aadff95f40cbb45ab86841679e/full?origin=microsoft&git_url=https%3A%2F%2Fgit.kernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git&git_branch=master",
18+
# "api_url": "/api/tree/mainline/master/a33b5a08cbbdd7aadff95f40cbb45ab86841679e/full?origin=microsoft",
2219
# "git_commit_hash": "a33b5a08cbbdd7aadff95f40cbb45ab86841679e",
2320
# "git_commit_name": "v6.15-rc3-8-ga33b5a08cbbd",
2421
# "git_repository_branch": "master",
2522
# "git_repository_url": "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git",
23+
# "old_api_url": "/api/tree/a33b5a08cbbdd7aadff95f40cbb45ab86841679e/full?origin=microsoft&git_url=https%3A%2F%2Fgit.kernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git&git_branch=master",
2624
# "origin": "microsoft",
2725
# "tree_name": "mainline"
28-
# }
26+
# }

backend/schema.yml

Lines changed: 11 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,48 +1286,15 @@ paths:
12861286
get:
12871287
operationId: tree_retrieve_2
12881288
parameters:
1289-
- in: path
1290-
name: git_branch
1291-
schema:
1292-
type: string
1293-
description: Git branch name of the tree
1294-
required: true
12951289
- in: query
1296-
name: origin
1297-
schema:
1298-
default: maestro
1299-
title: Origin
1300-
type: string
1301-
description: Origin filter to retrieve tree information
1302-
- in: path
1303-
name: tree_name
1304-
schema:
1305-
type: string
1306-
description: Name of the tree
1307-
required: true
1308-
tags:
1309-
- tree
1310-
security:
1311-
- cookieAuth: []
1312-
- basicAuth: []
1313-
- {}
1314-
responses:
1315-
'200':
1316-
content:
1317-
application/json:
1318-
schema:
1319-
$ref: '#/components/schemas/TreeLatestResponse'
1320-
description: ''
1321-
/api/tree/{tree_name}/{git_branch}/{commit_hash}:
1322-
get:
1323-
operationId: tree_retrieve_3
1324-
parameters:
1325-
- in: path
13261290
name: commit_hash
13271291
schema:
1328-
type: string
1329-
description: Commit hash of the tree
1330-
required: true
1292+
anyOf:
1293+
- type: string
1294+
- type: 'null'
1295+
default: null
1296+
title: Commit Hash
1297+
description: Commit hash to retrieve tree information
13311298
- in: path
13321299
name: git_branch
13331300
schema:
@@ -3185,9 +3152,11 @@ components:
31853152
additionalProperties:
31863153
additionalProperties:
31873154
additionalProperties:
3188-
items:
3189-
$ref: '#/components/schemas/RegressionHistoryItem'
3190-
type: array
3155+
additionalProperties:
3156+
items:
3157+
$ref: '#/components/schemas/RegressionHistoryItem'
3158+
type: array
3159+
type: object
31913160
type: object
31923161
type: object
31933162
type: object

0 commit comments

Comments
 (0)