diff --git a/src/sentry/api/endpoints/source_map_debug.py b/src/sentry/api/endpoints/source_map_debug.py index 316875b94443..3145657c0976 100644 --- a/src/sentry/api/endpoints/source_map_debug.py +++ b/src/sentry/api/endpoints/source_map_debug.py @@ -14,6 +14,7 @@ from sentry.api.base import cell_silo_endpoint from sentry.api.bases.project import ProjectEndpoint from sentry.apidocs.constants import RESPONSE_FORBIDDEN, RESPONSE_NOT_FOUND, RESPONSE_UNAUTHORIZED +from sentry.apidocs.examples.source_map_debug_examples import SourceMapDebugExamples from sentry.apidocs.parameters import EventParams, GlobalParams from sentry.apidocs.utils import inline_sentry_response_serializer from sentry.debug_files.release_files import maybe_renew_releasefiles @@ -128,7 +129,7 @@ class SourceMapDebugResponse(TypedDict): @extend_schema(tags=["Events"]) class SourceMapDebugEndpoint(ProjectEndpoint): publish_status = { - "GET": ApiPublishStatus.PRIVATE, + "GET": ApiPublishStatus.PUBLIC, } owner = ApiOwner.WEB_FRONTEND_SDKS @@ -147,6 +148,7 @@ class SourceMapDebugEndpoint(ProjectEndpoint): 403: RESPONSE_FORBIDDEN, 404: RESPONSE_NOT_FOUND, }, + examples=SourceMapDebugExamples.GET_SOURCE_MAP_DEBUG, ) def get(self, request: Request, project: Project, event_id: str) -> Response: """ diff --git a/src/sentry/api/urls.py b/src/sentry/api/urls.py index dcd2207b54c9..918564ccaf21 100644 --- a/src/sentry/api/urls.py +++ b/src/sentry/api/urls.py @@ -2766,6 +2766,12 @@ def create_group_urls(name_prefix: str) -> list[URLPattern | URLResolver]: name="sentry-api-0-event-owners", ), re_path( + r"^(?P[^/]+)/(?P[^/]+)/events/(?P[^/]+)/source-map-debug/$", + SourceMapDebugEndpoint.as_view(), + name="sentry-api-0-event-source-map-debug", + ), + re_path( + # Legacy alias the frontend still hardcodes; remove once it migrates to source-map-debug/. r"^(?P[^/]+)/(?P[^/]+)/events/(?P[^/]+)/source-map-debug-blue-thunder-edition/$", SourceMapDebugEndpoint.as_view(), name="sentry-api-0-event-source-map-debug-blue-thunder-edition", diff --git a/src/sentry/apidocs/examples/source_map_debug_examples.py b/src/sentry/apidocs/examples/source_map_debug_examples.py new file mode 100644 index 000000000000..87271d02ff28 --- /dev/null +++ b/src/sentry/apidocs/examples/source_map_debug_examples.py @@ -0,0 +1,56 @@ +from drf_spectacular.utils import OpenApiExample + +SOURCE_MAP_DEBUG = { + "dist": "1.0.0", + "release": "frontend@1.0.0", + "exceptions": [ + { + "frames": [ + { + "debug_id_process": { + "debug_id": "f206e0e7-3d0c-41cb-bccc-11b716728e27", + "uploaded_source_file_with_correct_debug_id": True, + "uploaded_source_map_with_correct_debug_id": True, + }, + "release_process": { + "abs_path": "https://example.com/static/js/main.js", + "matching_source_file_names": ["~/static/js/main.js"], + "matching_source_map_name": "~/static/js/main.js.map", + "source_map_reference": "main.js.map", + "source_file_lookup_result": "found", + "source_map_lookup_result": "found", + }, + "scraping_process": { + "source_file": { + "url": "https://example.com/static/js/main.js", + "status": "success", + }, + "source_map": { + "url": "https://example.com/static/js/main.js.map", + "status": "success", + }, + }, + } + ] + } + ], + "has_debug_ids": True, + "min_debug_id_sdk_version": "7.56.0", + "sdk_version": "7.60.0", + "project_has_some_artifact_bundle": True, + "release_has_some_artifact": True, + "has_uploaded_some_artifact_with_a_debug_id": True, + "sdk_debug_id_support": "full", + "has_scraping_data": True, +} + + +class SourceMapDebugExamples: + GET_SOURCE_MAP_DEBUG = [ + OpenApiExample( + "Source map debug information for an event", + value=SOURCE_MAP_DEBUG, + response_only=True, + status_codes=["200"], + ) + ] diff --git a/src/sentry/apidocs/hooks.py b/src/sentry/apidocs/hooks.py index b46f48bd61e0..010af18b0704 100644 --- a/src/sentry/apidocs/hooks.py +++ b/src/sentry/apidocs/hooks.py @@ -38,6 +38,8 @@ class EndpointRegistryType(TypedDict): "/api/0/monitors/", # Issue URLS have an expression of group|issue that resolves to `var` "/api/0/{var}/{issue_id}/", + # Legacy alias of source-map-debug/; documented only at the canonical path. + "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/events/{event_id}/source-map-debug-blue-thunder-edition/", ] diff --git a/static/app/utils/api/knownSentryApiUrls.generated.ts b/static/app/utils/api/knownSentryApiUrls.generated.ts index e7066df5ad5d..c5def5868f87 100644 --- a/static/app/utils/api/knownSentryApiUrls.generated.ts +++ b/static/app/utils/api/knownSentryApiUrls.generated.ts @@ -626,6 +626,7 @@ export type KnownSentryApiUrls = | '/projects/$organizationIdOrSlug/$projectIdOrSlug/events/$eventId/owners/' | '/projects/$organizationIdOrSlug/$projectIdOrSlug/events/$eventId/reprocessable/' | '/projects/$organizationIdOrSlug/$projectIdOrSlug/events/$eventId/source-map-debug-blue-thunder-edition/' + | '/projects/$organizationIdOrSlug/$projectIdOrSlug/events/$eventId/source-map-debug/' | '/projects/$organizationIdOrSlug/$projectIdOrSlug/files/artifact-bundles/' | '/projects/$organizationIdOrSlug/$projectIdOrSlug/files/difs/assemble/' | '/projects/$organizationIdOrSlug/$projectIdOrSlug/files/dsyms/' diff --git a/tests/apidocs/endpoints/events/test_source_map_debug.py b/tests/apidocs/endpoints/events/test_source_map_debug.py new file mode 100644 index 000000000000..cf6d8579eb75 --- /dev/null +++ b/tests/apidocs/endpoints/events/test_source_map_debug.py @@ -0,0 +1,28 @@ +from django.test.client import RequestFactory +from django.urls import reverse + +from fixtures.apidocs_test_case import APIDocsTestCase + + +class SourceMapDebugDocs(APIDocsTestCase): + endpoint = "sentry-api-0-event-source-map-debug" + + def setUp(self) -> None: + event = self.create_event("a") + + self.url = reverse( + self.endpoint, + kwargs={ + "organization_id_or_slug": self.project.organization.slug, + "project_id_or_slug": self.project.slug, + "event_id": event.event_id, + }, + ) + + self.login_as(user=self.user) + + def test_get(self) -> None: + response = self.client.get(self.url) + request = RequestFactory().get(self.url) + + self.validate_schema(request, response)