Skip to content

Commit

Permalink
feat: add IssueListing endpoint
Browse files Browse the repository at this point in the history
Part of #938

Closes #963
  • Loading branch information
MarceloRobert committed Feb 20, 2025
1 parent e56027f commit c8b59ed
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 11 deletions.
3 changes: 3 additions & 0 deletions backend/kernelCI_app/helpers/errorHandling.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ def __init__(self, message, status_code=400):
def getJsonResponse(self):
return self.json_response

def getRestResponse(self):
return Response(data={"error": self.message}, status=self.status_code)


@typing_extensions.deprecated(
'The `create_error_response` method is deprecated; use `create_api_error_response` '
Expand Down
6 changes: 6 additions & 0 deletions backend/kernelCI_app/typeModels/commonListing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from pydantic import BaseModel


class ListingQueryParameters(BaseModel):
origin: str
intervalInDays: int
27 changes: 27 additions & 0 deletions backend/kernelCI_app/typeModels/issueListing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from pydantic import BaseModel

from kernelCI_app.typeModels.databases import (
Issue__Comment,
Issue__CulpritCode,
Issue__CulpritHarness,
Issue__CulpritTool,
Issue__Id,
Issue__Version,
Timestamp,
)
from kernelCI_app.typeModels.issues import FirstIncident


class IssueListingItem(BaseModel):
field_timestamp: Timestamp
id: Issue__Id
comment: Issue__Comment
version: Issue__Version
culprit_code: Issue__CulpritCode
culprit_tool: Issue__CulpritTool
culprit_harness: Issue__CulpritHarness


class IssueListingResponse(BaseModel):
issues: list[IssueListingItem]
extras: dict[str, FirstIncident]
5 changes: 0 additions & 5 deletions backend/kernelCI_app/typeModels/treeListing.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,3 @@ class TreeListingResponse(RootModel):

class TreeListingFastResponse(RootModel):
root: List[CheckoutFast]


class TreeListingQueryParameters(BaseModel):
origin: str
intervalInDays: int
3 changes: 3 additions & 0 deletions backend/kernelCI_app/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ def viewCache(view):
path("hardware/",
viewCache(views.HardwareView),
name="hardware"),
path("issue/",
viewCache(views.IssueView),
name="issue"),
path("issue/extras/",
viewCache(views.IssueExtraDetails),
name="issueExtraDetails"
Expand Down
95 changes: 95 additions & 0 deletions backend/kernelCI_app/views/issueView.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from datetime import datetime, timedelta, timezone
from http import HTTPStatus
from drf_spectacular.utils import extend_schema
from rest_framework.views import APIView
from rest_framework.response import Response
from pydantic import ValidationError

from kernelCI_app.constants.general import DEFAULT_ORIGIN
from kernelCI_app.helpers.date import parseIntervalInDaysGetParameter
from kernelCI_app.helpers.errorHandling import (
ExceptionWithJsonResponse,
create_api_error_response,
)
from kernelCI_app.helpers.issueExtras import assign_issue_first_seen
from kernelCI_app.models import Issues
from kernelCI_app.typeModels.commonListing import ListingQueryParameters
from kernelCI_app.typeModels.issueListing import (
IssueListingResponse,
)
from kernelCI_app.typeModels.issues import FirstIncident, ProcessedExtraDetailedIssues


def get_issue_listing_data(origin: str, interval_date):
issues_records = Issues.objects.values(
"id",
"field_timestamp",
"comment",
"version",
"culprit_code",
"culprit_harness",
"culprit_tool",
).filter(
origin=origin,
field_timestamp__gte=interval_date,
)
return issues_records


class IssueView(APIView):
def __init__(self):
self.issue_records: list[dict[str]] = []
self.processed_extra_issue_details: ProcessedExtraDetailedIssues = {}
self.first_incidents: dict[str, FirstIncident] = {}

def _format_processing_for_response(self) -> None:
for (
issue_extras_id,
issue_extras_data,
) in self.processed_extra_issue_details.items():
self.first_incidents[issue_extras_id] = issue_extras_data["first_incident"]

@extend_schema(
parameters=[ListingQueryParameters],
responses=IssueListingResponse,
methods=["GET"],
)
def get(self, _request) -> Response:
origin_param = _request.GET.get("origin", DEFAULT_ORIGIN)
try:
interval_in_days = parseIntervalInDaysGetParameter(
_request.GET.get("intervalInDays", 7)
)
except ExceptionWithJsonResponse as e:
return e.getRestResponse()

interval_date = datetime.now(timezone.utc) - timedelta(days=interval_in_days)
interval_param = interval_date.replace(
hour=0, minute=0, second=0, microsecond=0
)

self.issue_records = get_issue_listing_data(
origin=origin_param, interval_date=interval_param
)

if len(self.issue_records) == 0:
return create_api_error_response(
error_message="No issues found", status_code=HTTPStatus.OK
)

issue_key_list = [
(issue["id"], issue["version"]) for issue in self.issue_records
]
assign_issue_first_seen(
issue_key_list=issue_key_list,
processed_issues_table=self.processed_extra_issue_details,
)

try:
self._format_processing_for_response()
valid_data = IssueListingResponse(
issues=self.issue_records, extras=self.first_incidents
)
except ValidationError as e:
return Response(data=e.json(), status=HTTPStatus.INTERNAL_SERVER_ERROR)
return Response(data=valid_data.model_dump())
6 changes: 3 additions & 3 deletions backend/kernelCI_app/views/treeView.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from drf_spectacular.utils import extend_schema
from rest_framework.views import APIView
from rest_framework.response import Response
from kernelCI_app.typeModels.commonListing import ListingQueryParameters
from kernelCI_app.utils import getQueryTimeInterval
from kernelCI_app.helpers.errorHandling import (
ExceptionWithJsonResponse,
Expand All @@ -11,7 +12,6 @@
from http import HTTPStatus
from kernelCI_app.typeModels.treeListing import (
TreeListingResponse,
TreeListingQueryParameters,
)
from pydantic import ValidationError
from django.db import connection
Expand Down Expand Up @@ -63,8 +63,8 @@ def _sanitize_tree(self, checkout: Dict) -> Dict:

@extend_schema(
responses=TreeListingResponse,
parameters=[TreeListingQueryParameters],
methods=["GET"],
parameters=[ListingQueryParameters],
methods=["GET"]
)
def get(self, request) -> Response:
origin_param = request.GET.get("origin", DEFAULT_ORIGIN)
Expand Down
4 changes: 2 additions & 2 deletions backend/kernelCI_app/views/treeViewFast.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
from rest_framework.response import Response
from drf_spectacular.utils import extend_schema
from kernelCI_app.models import Checkouts
from kernelCI_app.typeModels.commonListing import ListingQueryParameters
from kernelCI_app.utils import getQueryTimeInterval
from http import HTTPStatus
from kernelCI_app.helpers.errorHandling import create_api_error_response
from kernelCI_app.typeModels.treeListing import (
TreeListingFastResponse,
TreeListingQueryParameters
)
from pydantic import ValidationError

Expand All @@ -17,7 +17,7 @@
class TreeViewFast(APIView):
@extend_schema(
responses=TreeListingFastResponse,
parameters=[TreeListingQueryParameters],
parameters=[ListingQueryParameters],
methods=["GET"]
)
def get(self, request):
Expand Down
75 changes: 75 additions & 0 deletions backend/requests/issue-listing-get.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
http 'localhost:8000/api/issue/?origin=maestro&intervalInDays=1'

# HTTP/1.1 200 OK
# Allow: GET, HEAD, OPTIONS
# Cache-Control: max-age=0
# Content-Length: 27282
# Content-Type: application/json
# Cross-Origin-Opener-Policy: same-origin
# Date: Thu, 20 Feb 2025 11:51:56 GMT
# Expires: Thu, 20 Feb 2025 11:51:56 GMT
# Referrer-Policy: same-origin
# Server: WSGIServer/0.2 CPython/3.12.7
# Vary: Accept, Cookie, origin
# X-Content-Type-Options: nosniff
# X-Frame-Options: DENY

# {
# "extras": {
# "maestro:031929b615e8ecfed14a89cef2b564108c3aa42c": {
# "first_seen": "2025-02-17T20:40:01.251254Z",
# "git_commit_hash": "a1c2670b1577474f7ae60d5dec1d35a053d354f0",
# "git_commit_name": "v6.1.124-16535-ga1c2670b1577",
# "git_repository_branch": "chromeos-6.1",
# "git_repository_url": "https://chromium.googlesource.com/chromiumos/third_party/kernel",
# "tree_name": "chromiumos"
# },
# "maestro:069157741b947b2f589c971be301429c4bb72515": {
# "first_seen": "2025-02-17T20:40:01.251254Z",
# "git_commit_hash": "a1c2670b1577474f7ae60d5dec1d35a053d354f0",
# "git_commit_name": "v6.1.124-16535-ga1c2670b1577",
# "git_repository_branch": "chromeos-6.1",
# "git_repository_url": "https://chromium.googlesource.com/chromiumos/third_party/kernel",
# "tree_name": "chromiumos"
# },
# "maestro:11eb365e0d1a4de6c80b036cd2e7a3fe5c276587": {
# "first_seen": "2024-11-12T10:30:20.456672Z",
# "git_commit_hash": "d145d3aa80067e115a679d903fba256c3d1f39a1",
# "git_commit_name": "v5.4.285-53-gd145d3aa8006",
# "git_repository_branch": "linux-5.4.y",
# "git_repository_url": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git",
# "tree_name": "stable-rc"
# },
# ...
# },
# "issues": [
# {
# "comment": " call to undeclared function 'stack_trace_save_tsk'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] in kernel/sched/core.o (kernel/sched/core.c) [logspec:kbuild,kbuild.compiler.error]",
# "culprit_code": true,
# "culprit_harness": false,
# "culprit_tool": false,
# "field_timestamp": "2025-02-19T22:51:01.778279Z",
# "id": "maestro:87244933628a2612f39e6096115454f1e8bb3e1c",
# "version": 1
# },
# {
# "comment": " implicit declaration of function ‘stack_trace_save_tsk’ [-Werror=implicit-function-declaration] in kernel/sched/core.o (kernel/sched/core.c) [logspec:kbuild,kbuild.compiler.error]",
# "culprit_code": true,
# "culprit_harness": false,
# "culprit_tool": false,
# "field_timestamp": "2025-02-19T23:42:17.982170Z",
# "id": "maestro:2ff8fe94f6d53f39321d4a37fe15801cedc93573",
# "version": 1
# },
# {
# "comment": " implicit declaration of function 'drm_connector_helper_hpd_irq_event' [-Werror,-Wimplicit-function-declaration] in drivers/gpu/drm/rockchip/cdn-dp-core.o (drivers/gpu/drm/rockchip/cdn-dp-core.c) [logspec:kbuild,kbuild.compiler.error]",
# "culprit_code": true,
# "culprit_harness": false,
# "culprit_tool": false,
# "field_timestamp": "2025-02-20T11:50:02.465668Z",
# "id": "maestro:3feccbb8dd7c7976251cf4457318fc92c3eb2efb",
# "version": 1
# },
# ...
# ]
# }
74 changes: 73 additions & 1 deletion backend/schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -309,10 +309,39 @@ paths:
schema:
$ref: '#/components/schemas/HardwareDetailsTestsResponse'
description: ''
/api/issue/{issue_id}:
/api/issue/:
get:
operationId: issue_retrieve
parameters:
- in: query
name: intervalInDays
schema:
title: Intervalindays
type: integer
required: true
- in: query
name: origin
schema:
title: Origin
type: string
required: true
tags:
- issue
security:
- cookieAuth: []
- basicAuth: []
- {}
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/IssueListingResponse'
description: ''
/api/issue/{issue_id}:
get:
operationId: issue_retrieve_2
parameters:
- in: path
name: issue_id
schema:
Expand Down Expand Up @@ -2263,6 +2292,49 @@ components:
- issues
title: IssueExtraDetailsResponse
type: object
IssueListingItem:
properties:
field_timestamp:
$ref: '#/components/schemas/Timestamp'
id:
$ref: '#/components/schemas/Issue__Id'
comment:
$ref: '#/components/schemas/Issue__Comment'
version:
$ref: '#/components/schemas/Issue__Version'
culprit_code:
$ref: '#/components/schemas/Issue__CulpritCode'
culprit_tool:
$ref: '#/components/schemas/Issue__CulpritTool'
culprit_harness:
$ref: '#/components/schemas/Issue__CulpritHarness'
required:
- field_timestamp
- id
- comment
- version
- culprit_code
- culprit_tool
- culprit_harness
title: IssueListingItem
type: object
IssueListingResponse:
properties:
issues:
items:
$ref: '#/components/schemas/IssueListingItem'
title: Issues
type: array
extras:
additionalProperties:
$ref: '#/components/schemas/FirstIncident'
title: Extras
type: object
required:
- issues
- extras
title: IssueListingResponse
type: object
IssueTestItem:
properties:
id:
Expand Down

0 comments on commit c8b59ed

Please sign in to comment.