Browse Source

feat(sourcemaps): Add bundle information to the artifact bundle files endpoint (#46032)

Riccardo Busetti 2 years ago
parent
commit
225bd889d4

+ 25 - 18
src/sentry/api/endpoints/project_artifact_bundle_files.py

@@ -59,24 +59,21 @@ class ProjectArtifactBundleFilesEndpoint(ProjectEndpoint):
         query = request.GET.get("query")
         query = request.GET.get("query")
 
 
         try:
         try:
-            artifact_bundle = ArtifactBundle.objects.get(
-                organization_id=project.organization.id, bundle_id=bundle_id
-            )
-        except ArtifactBundle.DoesNotExist:
-            return Response(
-                {"error": f"The artifact bundle with {bundle_id} does not exist"}, status=404
-            )
-
-        try:
-            ProjectArtifactBundle.objects.get(
-                project_id=project.id, artifact_bundle=artifact_bundle
-            )
-        except ProjectArtifactBundle.DoesNotExist:
+            project_artifact_bundle = ProjectArtifactBundle.objects.filter(
+                organization_id=project.organization.id,
+                project_id=project.id,
+                artifact_bundle__bundle_id=bundle_id,
+            ).select_related("artifact_bundle__file")[0]
+        except IndexError:
             return Response(
             return Response(
-                {"error": f"The artifact bundle with {bundle_id} is not bound to this project"},
+                {
+                    "error": f"The artifact bundle with {bundle_id} is not bound to this project or doesn't exist"
+                },
                 status=400,
                 status=400,
             )
             )
 
 
+        artifact_bundle = project_artifact_bundle.artifact_bundle
+
         try:
         try:
             # We open the archive to fetch the number of files.
             # We open the archive to fetch the number of files.
             archive = ArtifactBundleArchive(artifact_bundle.file.getfile(), build_memory_map=False)
             archive = ArtifactBundleArchive(artifact_bundle.file.getfile(), build_memory_map=False)
@@ -103,12 +100,22 @@ class ProjectArtifactBundleFilesEndpoint(ProjectEndpoint):
             }
             }
 
 
         def serialize_results(r):
         def serialize_results(r):
-            serialized_results = serialize(
-                [expose_artifact_bundle_file(file_path, info) for file_path, info in r],
-                request.user,
+            artifact_bundle_files = [
+                expose_artifact_bundle_file(file_path, info) for file_path, info in r
+            ]
+            release, dist = ArtifactBundle.get_release_dist_pair(
+                project.organization.id, artifact_bundle
             )
             )
 
 
-            return serialized_results
+            return serialize(
+                {
+                    "bundleId": str(artifact_bundle.bundle_id),
+                    "release": release,
+                    "dist": dist if dist != "" else None,
+                    "files": artifact_bundle_files,
+                },
+                request.user,
+            )
 
 
         try:
         try:
             return self.paginate(
             return self.paginate(

+ 13 - 0
src/sentry/models/artifactbundle.py

@@ -59,6 +59,19 @@ class ArtifactBundle(Model):
 
 
         unique_together = (("organization_id", "bundle_id"),)
         unique_together = (("organization_id", "bundle_id"),)
 
 
+    @classmethod
+    def get_release_dist_pair(
+        cls, organization_id: int, artifact_bundle: "ArtifactBundle"
+    ) -> Tuple[Optional[str], Optional[str]]:
+        try:
+            release_artifact_bundle = ReleaseArtifactBundle.objects.filter(
+                organization_id=organization_id, artifact_bundle=artifact_bundle
+            )[0]
+
+            return release_artifact_bundle.release_name, release_artifact_bundle.dist_name
+        except IndexError:
+            return None, None
+
 
 
 @region_silo_only_model
 @region_silo_only_model
 class ReleaseArtifactBundle(Model):
 class ReleaseArtifactBundle(Model):

+ 167 - 121
tests/sentry/api/endpoints/test_project_artifact_bundle_files.py

@@ -1,7 +1,7 @@
 from django.urls import reverse
 from django.urls import reverse
 from freezegun import freeze_time
 from freezegun import freeze_time
 
 
-from sentry.models import ProjectArtifactBundle
+from sentry.models import ProjectArtifactBundle, ReleaseArtifactBundle
 from sentry.testutils import APITestCase
 from sentry.testutils import APITestCase
 from sentry.testutils.silo import region_silo_test
 from sentry.testutils.silo import region_silo_test
 
 
@@ -20,6 +20,12 @@ class ProjectArtifactBundleFilesEndpointTest(APITestCase):
             project_id=project.id,
             project_id=project.id,
             artifact_bundle=artifact_bundle,
             artifact_bundle=artifact_bundle,
         )
         )
+        ReleaseArtifactBundle.objects.create(
+            organization_id=self.organization.id,
+            release_name="1.0",
+            dist_name="android",
+            artifact_bundle=artifact_bundle,
+        )
 
 
         url = reverse(
         url = reverse(
             "sentry-api-0-project-artifact-bundle-files",
             "sentry-api-0-project-artifact-bundle-files",
@@ -34,74 +40,11 @@ class ProjectArtifactBundleFilesEndpointTest(APITestCase):
         response = self.client.get(url)
         response = self.client.get(url)
 
 
         assert response.status_code == 200, response.content
         assert response.status_code == 200, response.content
-        assert response.data == [
-            {
-                "debugId": None,
-                "filePath": "files/_/_/bundle1.js",
-                "id": "ZmlsZXMvXy9fL2J1bmRsZTEuanM=",
-                "fileSize": 71,
-                "fileType": 0,
-            },
-            {
-                "debugId": None,
-                "filePath": "files/_/_/bundle1.min.js",
-                "id": "ZmlsZXMvXy9fL2J1bmRsZTEubWluLmpz",
-                "fileSize": 63,
-                "fileType": 2,
-            },
-            {
-                "debugId": None,
-                "filePath": "files/_/_/bundle1.min.js.map",
-                "fileSize": 139,
-                "fileType": 0,
-                "id": "ZmlsZXMvXy9fL2J1bmRsZTEubWluLmpzLm1hcA==",
-            },
-            {
-                "debugId": None,
-                "filePath": "files/_/_/index.js",
-                "id": "ZmlsZXMvXy9fL2luZGV4Lmpz",
-                "fileSize": 3706,
-                "fileType": 1,
-            },
-            {
-                "debugId": "eb6e60f1-65ff-4f6f-adff-f1bbeded627b",
-                "filePath": "files/_/_/index.js.map",
-                "id": "ZmlsZXMvXy9fL2luZGV4LmpzLm1hcA==",
-                "fileSize": 1804,
-                "fileType": 3,
-            },
-            {
-                "debugId": "eb6e60f1-65ff-4f6f-adff-f1bbeded627b",
-                "filePath": "files/_/_/index.min.js",
-                "id": "ZmlsZXMvXy9fL2luZGV4Lm1pbi5qcw==",
-                "fileSize": 1676,
-                "fileType": 2,
-            },
-        ]
-
-    def test_get_artifact_bundle_files_pagination_with_multiple_files(self):
-        project = self.create_project(name="foo")
-
-        artifact_bundle = self.create_artifact_bundle(
-            self.organization, artifact_count=6, fixture_path="artifact_bundle_debug_ids"
-        )
-        ProjectArtifactBundle.objects.create(
-            organization_id=self.organization.id,
-            project_id=project.id,
-            artifact_bundle=artifact_bundle,
-        )
-
-        url = reverse(
-            "sentry-api-0-project-artifact-bundle-files",
-            kwargs={
-                "organization_slug": project.organization.slug,
-                "project_slug": project.slug,
-                "bundle_id": artifact_bundle.bundle_id,
-            },
-        )
-
-        expected = [
-            [
+        assert response.data == {
+            "bundleId": str(artifact_bundle.bundle_id),
+            "release": "1.0",
+            "dist": "android",
+            "files": [
                 {
                 {
                     "debugId": None,
                     "debugId": None,
                     "filePath": "files/_/_/bundle1.js",
                     "filePath": "files/_/_/bundle1.js",
@@ -116,8 +59,6 @@ class ProjectArtifactBundleFilesEndpointTest(APITestCase):
                     "fileSize": 63,
                     "fileSize": 63,
                     "fileType": 2,
                     "fileType": 2,
                 },
                 },
-            ],
-            [
                 {
                 {
                     "debugId": None,
                     "debugId": None,
                     "filePath": "files/_/_/bundle1.min.js.map",
                     "filePath": "files/_/_/bundle1.min.js.map",
@@ -132,8 +73,6 @@ class ProjectArtifactBundleFilesEndpointTest(APITestCase):
                     "fileSize": 3706,
                     "fileSize": 3706,
                     "fileType": 1,
                     "fileType": 1,
                 },
                 },
-            ],
-            [
                 {
                 {
                     "debugId": "eb6e60f1-65ff-4f6f-adff-f1bbeded627b",
                     "debugId": "eb6e60f1-65ff-4f6f-adff-f1bbeded627b",
                     "filePath": "files/_/_/index.js.map",
                     "filePath": "files/_/_/index.js.map",
@@ -149,6 +88,98 @@ class ProjectArtifactBundleFilesEndpointTest(APITestCase):
                     "fileType": 2,
                     "fileType": 2,
                 },
                 },
             ],
             ],
+        }
+
+    def test_get_artifact_bundle_files_pagination_with_multiple_files(self):
+        project = self.create_project(name="foo")
+
+        artifact_bundle = self.create_artifact_bundle(
+            self.organization, artifact_count=6, fixture_path="artifact_bundle_debug_ids"
+        )
+        ProjectArtifactBundle.objects.create(
+            organization_id=self.organization.id,
+            project_id=project.id,
+            artifact_bundle=artifact_bundle,
+        )
+        ReleaseArtifactBundle.objects.create(
+            organization_id=self.organization.id,
+            release_name="1.0",
+            artifact_bundle=artifact_bundle,
+        )
+
+        url = reverse(
+            "sentry-api-0-project-artifact-bundle-files",
+            kwargs={
+                "organization_slug": project.organization.slug,
+                "project_slug": project.slug,
+                "bundle_id": artifact_bundle.bundle_id,
+            },
+        )
+
+        expected = [
+            {
+                "bundleId": str(artifact_bundle.bundle_id),
+                "release": "1.0",
+                "dist": None,
+                "files": [
+                    {
+                        "debugId": None,
+                        "filePath": "files/_/_/bundle1.js",
+                        "id": "ZmlsZXMvXy9fL2J1bmRsZTEuanM=",
+                        "fileSize": 71,
+                        "fileType": 0,
+                    },
+                    {
+                        "debugId": None,
+                        "filePath": "files/_/_/bundle1.min.js",
+                        "id": "ZmlsZXMvXy9fL2J1bmRsZTEubWluLmpz",
+                        "fileSize": 63,
+                        "fileType": 2,
+                    },
+                ],
+            },
+            {
+                "bundleId": str(artifact_bundle.bundle_id),
+                "release": "1.0",
+                "dist": None,
+                "files": [
+                    {
+                        "debugId": None,
+                        "filePath": "files/_/_/bundle1.min.js.map",
+                        "fileSize": 139,
+                        "fileType": 0,
+                        "id": "ZmlsZXMvXy9fL2J1bmRsZTEubWluLmpzLm1hcA==",
+                    },
+                    {
+                        "debugId": None,
+                        "filePath": "files/_/_/index.js",
+                        "id": "ZmlsZXMvXy9fL2luZGV4Lmpz",
+                        "fileSize": 3706,
+                        "fileType": 1,
+                    },
+                ],
+            },
+            {
+                "bundleId": str(artifact_bundle.bundle_id),
+                "release": "1.0",
+                "dist": None,
+                "files": [
+                    {
+                        "debugId": "eb6e60f1-65ff-4f6f-adff-f1bbeded627b",
+                        "filePath": "files/_/_/index.js.map",
+                        "id": "ZmlsZXMvXy9fL2luZGV4LmpzLm1hcA==",
+                        "fileSize": 1804,
+                        "fileType": 3,
+                    },
+                    {
+                        "debugId": "eb6e60f1-65ff-4f6f-adff-f1bbeded627b",
+                        "filePath": "files/_/_/index.min.js",
+                        "id": "ZmlsZXMvXy9fL2luZGV4Lm1pbi5qcw==",
+                        "fileSize": 1676,
+                        "fileType": 2,
+                    },
+                ],
+            },
         ]
         ]
 
 
         for index, cursor in enumerate(["2:0:1", "2:1:0", "2:2:0"]):
         for index, cursor in enumerate(["2:0:1", "2:1:0", "2:2:0"]):
@@ -185,61 +216,76 @@ class ProjectArtifactBundleFilesEndpointTest(APITestCase):
         query = "bundle1.js"
         query = "bundle1.js"
         response = self.client.get(url + f"?query={query}")
         response = self.client.get(url + f"?query={query}")
         assert response.status_code == 200, response.content
         assert response.status_code == 200, response.content
-        assert response.data == [
-            {
-                "debugId": None,
-                "filePath": "files/_/_/bundle1.js",
-                "id": "ZmlsZXMvXy9fL2J1bmRsZTEuanM=",
-                "fileSize": 71,
-                "fileType": 0,
-            },
-        ]
+        assert response.data == {
+            "bundleId": str(artifact_bundle.bundle_id),
+            "release": None,
+            "dist": None,
+            "files": [
+                {
+                    "debugId": None,
+                    "filePath": "files/_/_/bundle1.js",
+                    "id": "ZmlsZXMvXy9fL2J1bmRsZTEuanM=",
+                    "fileSize": 71,
+                    "fileType": 0,
+                },
+            ],
+        }
 
 
         # file_path match across multiple files.
         # file_path match across multiple files.
         query = "bundle"
         query = "bundle"
         response = self.client.get(url + f"?query={query}")
         response = self.client.get(url + f"?query={query}")
         assert response.status_code == 200, response.content
         assert response.status_code == 200, response.content
-        assert response.data == [
-            {
-                "debugId": None,
-                "filePath": "files/_/_/bundle1.js",
-                "id": "ZmlsZXMvXy9fL2J1bmRsZTEuanM=",
-                "fileSize": 71,
-                "fileType": 0,
-            },
-            {
-                "debugId": None,
-                "filePath": "files/_/_/bundle1.min.js",
-                "id": "ZmlsZXMvXy9fL2J1bmRsZTEubWluLmpz",
-                "fileSize": 63,
-                "fileType": 2,
-            },
-            {
-                "debugId": None,
-                "filePath": "files/_/_/bundle1.min.js.map",
-                "fileSize": 139,
-                "fileType": 0,
-                "id": "ZmlsZXMvXy9fL2J1bmRsZTEubWluLmpzLm1hcA==",
-            },
-        ]
+        assert response.data == {
+            "bundleId": str(artifact_bundle.bundle_id),
+            "release": None,
+            "dist": None,
+            "files": [
+                {
+                    "debugId": None,
+                    "filePath": "files/_/_/bundle1.js",
+                    "id": "ZmlsZXMvXy9fL2J1bmRsZTEuanM=",
+                    "fileSize": 71,
+                    "fileType": 0,
+                },
+                {
+                    "debugId": None,
+                    "filePath": "files/_/_/bundle1.min.js",
+                    "id": "ZmlsZXMvXy9fL2J1bmRsZTEubWluLmpz",
+                    "fileSize": 63,
+                    "fileType": 2,
+                },
+                {
+                    "debugId": None,
+                    "filePath": "files/_/_/bundle1.min.js.map",
+                    "fileSize": 139,
+                    "fileType": 0,
+                    "id": "ZmlsZXMvXy9fL2J1bmRsZTEubWluLmpzLm1hcA==",
+                },
+            ],
+        }
 
 
         # debug_id match.
         # debug_id match.
         query = "eb6e60f1-65ff-"
         query = "eb6e60f1-65ff-"
         response = self.client.get(url + f"?query={query}")
         response = self.client.get(url + f"?query={query}")
         assert response.status_code == 200, response.content
         assert response.status_code == 200, response.content
-        assert response.data == [
-            {
-                "debugId": "eb6e60f1-65ff-4f6f-adff-f1bbeded627b",
-                "filePath": "files/_/_/index.js.map",
-                "id": "ZmlsZXMvXy9fL2luZGV4LmpzLm1hcA==",
-                "fileSize": 1804,
-                "fileType": 3,
-            },
-            {
-                "debugId": "eb6e60f1-65ff-4f6f-adff-f1bbeded627b",
-                "filePath": "files/_/_/index.min.js",
-                "id": "ZmlsZXMvXy9fL2luZGV4Lm1pbi5qcw==",
-                "fileSize": 1676,
-                "fileType": 2,
-            },
-        ]
+        assert response.data == {
+            "bundleId": str(artifact_bundle.bundle_id),
+            "release": None,
+            "dist": None,
+            "files": [
+                {
+                    "debugId": "eb6e60f1-65ff-4f6f-adff-f1bbeded627b",
+                    "filePath": "files/_/_/index.js.map",
+                    "id": "ZmlsZXMvXy9fL2luZGV4LmpzLm1hcA==",
+                    "fileSize": 1804,
+                    "fileType": 3,
+                },
+                {
+                    "debugId": "eb6e60f1-65ff-4f6f-adff-f1bbeded627b",
+                    "filePath": "files/_/_/index.min.js",
+                    "id": "ZmlsZXMvXy9fL2luZGV4Lm1pbi5qcw==",
+                    "fileSize": 1676,
+                    "fileType": 2,
+                },
+            ],
+        }