diff --git a/src/sentry/api/endpoints/issues/related_issues.py b/src/sentry/api/endpoints/issues/related_issues.py index b722f179f5b32..4387521c3c486 100644 --- a/src/sentry/api/endpoints/issues/related_issues.py +++ b/src/sentry/api/endpoints/issues/related_issues.py @@ -33,11 +33,4 @@ def get(self, _: Request, group: Group) -> Response: :pparam string group_id: the ID of the issue """ related_issues = find_related_issues(group) - return Response( - { - "data": [ - {"type": related_set["type"], "data": related_set["data"]} - for related_set in related_issues - ] - } - ) + return Response({"data": [related_set for related_set in related_issues]}) diff --git a/src/sentry/issues/related/__init__.py b/src/sentry/issues/related/__init__.py index 8847774232ed7..3148714d42ec1 100644 --- a/src/sentry/issues/related/__init__.py +++ b/src/sentry/issues/related/__init__.py @@ -13,9 +13,10 @@ } -def find_related_issues(group: Group) -> list[dict[str, list[int] | str]]: - related_issues: list[dict[str, list[int] | str]] = [] +def find_related_issues(group: Group) -> list[dict[str, str | list[int] | dict[str, str]]]: + related_issues: list[dict[str, str | list[int] | dict[str, str]]] = [] for key, func in RELATED_ISSUES_ALGORITHMS.items(): - related_issues.append({"type": key, "data": func(group)}) + data, meta = func(group) + related_issues.append({"type": key, "data": data, "meta": meta}) return related_issues diff --git a/src/sentry/issues/related/same_root_cause.py b/src/sentry/issues/related/same_root_cause.py index 8e848cb1cffbb..aa822488bc80b 100644 --- a/src/sentry/issues/related/same_root_cause.py +++ b/src/sentry/issues/related/same_root_cause.py @@ -7,7 +7,7 @@ from sentry.utils.query import RangeQuerySetWrapper -def same_root_cause_analysis(group: Group) -> list[int]: +def same_root_cause_analysis(group: Group) -> tuple[list[int], dict[str, str]]: """Analyze and create a group set if the group was caused by the same root cause.""" # Querying the data field (which is a GzippedDictField) cannot be done via # Django's ORM, thus, we do so via compare_groups @@ -16,7 +16,7 @@ def same_root_cause_analysis(group: Group) -> list[int]: limit=100, ) same_error_type_groups = [g.id for g in project_groups if compare_groups(g, group)] - return same_error_type_groups or [] + return same_error_type_groups or [], {} def compare_groups(groupA: Group, groupB: Group) -> bool: diff --git a/src/sentry/issues/related/trace_connected.py b/src/sentry/issues/related/trace_connected.py index b237fd59c0eb8..1fdf88876cd17 100644 --- a/src/sentry/issues/related/trace_connected.py +++ b/src/sentry/issues/related/trace_connected.py @@ -11,10 +11,11 @@ from sentry.utils.snuba import bulk_snuba_queries -def trace_connected_analysis(group: Group) -> list[int]: +def trace_connected_analysis(group: Group) -> tuple[list[int], dict[str, str]]: + """Determine if the group has a trace connected to it and return other issues that were part of it.""" event = group.get_recommended_event_for_environments() if not event or event.trace_id is None: - return [] + return [], {} org_id = group.project.organization_id # XXX: Test without a list and validate the data type @@ -40,4 +41,4 @@ def trace_connected_analysis(group: Group) -> list[int]: if datum["issue.id"] != group.id # Exclude itself } ) - return transformed_results + return transformed_results, {"event_id": event.event_id, "trace_id": event.trace_id} diff --git a/tests/sentry/api/endpoints/issues/test_related_issues.py b/tests/sentry/api/endpoints/issues/test_related_issues.py index 8dbce03749d03..7fd5c60be299a 100644 --- a/tests/sentry/api/endpoints/issues/test_related_issues.py +++ b/tests/sentry/api/endpoints/issues/test_related_issues.py @@ -46,14 +46,18 @@ def test_same_root_related_issues(self) -> None: # https://us.sentry.io/api/0/organizations/sentry/issues-stats/?groups=4741828952&groups=4489703641&statsPeriod=24h assert response.json() == { "data": [ - {"type": "same_root_cause", "data": [5]}, - {"type": "trace_connected", "data": []}, + {"type": "same_root_cause", "data": [5], "meta": {}}, + {"type": "trace_connected", "data": [], "meta": {}}, ], } def test_trace_connected_errors(self) -> None: error_event, _, another_proj_event = self.load_errors(self.project, uuid4().hex[:16]) + group = error_event.group self.group_id = error_event.group_id # type: ignore[assignment] + recommended_event = group.get_recommended_event_for_environments() # type: ignore[union-attr] + assert recommended_event is not None # It helps with typing + assert error_event.group_id != another_proj_event.group_id assert error_event.project.id != another_proj_event.project.id assert error_event.trace_id == another_proj_event.trace_id @@ -61,7 +65,15 @@ def test_trace_connected_errors(self) -> None: response = self.get_success_response() assert response.json() == { "data": [ - {"type": "same_root_cause", "data": []}, - {"type": "trace_connected", "data": [another_proj_event.group_id]}, + {"type": "same_root_cause", "data": [], "meta": {}}, + { + "type": "trace_connected", + # This is the other issue in the trace that it is not itself + "data": [another_proj_event.group_id], + "meta": { + "event_id": recommended_event.event_id, + "trace_id": error_event.trace_id, + }, + }, ] }