Просмотр исходного кода

feat(api-docs): Add external issue endpoints (#23784)

* feat(api-docs): Add external issue endpoints
Colleen O'Rourke 4 лет назад
Родитель
Сommit
67b79abbea

+ 18 - 0
api-docs/openapi.json

@@ -59,6 +59,15 @@
         "description": "Found an error? Let us know.",
         "url": "https://github.com/getsentry/sentry-docs/issues/new/?title=API%20Documentation%20Error:%20/api/releases/&template=api_error_template.md"
       }
+    },
+    {
+      "name": "Integration",
+      "x-sidebar-name": "Integration Platform",
+      "description": "Endpoints for the integration platform",
+      "externalDocs": {
+        "description": "Found an error? Let us know.",
+        "url": "https://github.com/getsentry/sentry-docs/issues/new/?title=API%20Documentation%20Error:%20/api/integration-platform/&template=api_error_template.md"
+      }
     }
   ],
   "paths": {
@@ -199,6 +208,15 @@
     },
     "/api/0/organizations/{organization_slug}/releases/{version}/deploys/": {
       "$ref": "paths/releases/deploys.json"
+    },
+    "/api/0/organizations/{organization_slug}/sentry-app-installations/": {
+      "$ref": "paths/integration-platform/sentry-app-installations.json"
+    },
+    "/api/0/sentry-app-installations/{uuid}/external-issues/": {
+      "$ref": "paths/integration-platform/sentry-app-external-issues.json"
+    },
+    "/api/0/sentry-app-installations/{uuid}/external-issues/{external_issue_id}/": {
+      "$ref": "paths/integration-platform/sentry-app-external-issue-details.json"
     }
   },
   "components": {

+ 43 - 0
api-docs/paths/integration-platform/sentry-app-external-issue-details.json

@@ -0,0 +1,43 @@
+{
+  "delete": {
+    "tags": ["Integration"],
+    "description": "Delete an external issue.",
+    "operationId": "Delete an External Issue",
+    "parameters": [
+      {
+        "name": "uuid",
+        "in": "path",
+        "description": "The uuid of the integration platform integration.",
+        "required": true,
+        "schema": {
+          "type": "string"
+        }
+      },
+      {
+        "name": "external_issue_id",
+        "in": "path",
+        "description": "The id of the external issue.",
+        "required": true,
+        "schema": {
+          "type": "string"
+        }
+      }
+    ],
+    "responses": {
+      "204": {
+        "description": "Success"
+      },
+      "403": {
+        "description": "Forbidden"
+      },
+      "404": {
+        "description": "External issue not found"
+      }
+    },
+    "security": [
+      {
+        "auth_token": ["event:admin"]
+      }
+    ]
+  }
+}

+ 101 - 0
api-docs/paths/integration-platform/sentry-app-external-issues.json

@@ -0,0 +1,101 @@
+{
+  "post": {
+    "tags": ["Integration"],
+    "description": "Create an external issue from an integration platform integration.",
+    "operationId": "Create an External Issue",
+    "parameters": [
+      {
+        "name": "uuid",
+        "in": "path",
+        "description": "The uuid of the integration platform integration.",
+        "required": true,
+        "schema": {
+          "type": "string"
+        }
+      }
+    ],
+    "requestBody": {
+      "content": {
+        "application/json": {
+          "schema": {
+            "required": ["issueId", "webUrl", "project", "identifier"],
+            "type": "object",
+            "properties": {
+              "issueId": {
+                "type": "integer",
+                "description": "The ID of the Sentry issue to link the external issue to."
+              },
+              "webUrl": {
+                "type": "string",
+                "description": "The URL of the external service to link the issue to."
+              },
+              "project": {
+                "type": "string",
+                "description": "The external service's project."
+              },
+              "identifier": {
+                "type": "string",
+                "description": "A unique identifier of the external issue."
+              },
+            }
+          },
+          "example": {
+            "issueId": 1,
+            "webUrl": "https://somerandom.io/project/issue-id",
+            "project": "ExternalProj",
+            "identifier": "issue-1",
+          },
+        }
+      },
+      "required": true
+    },
+    "responses": {
+      "200": {
+        "description": "Success",
+        "content": {
+          "application/json": {
+            "schema": {
+              "type": "object",
+              "required": ["id", "issueId", "serviceType", "displayName", "webUrl"],
+              "properties": {
+                "id": {
+                  "type": "string"
+                },
+                "issueId": {
+                  "type": "string"
+                },
+                "serviceType": {
+                  "type": "string"
+                },
+                "displayName": {
+                  "type": "string"
+                },
+                "webUrl": {
+                  "type": "string"
+                }
+              }
+            },
+            "example": {
+              "id": "1",
+              "issueId": "1",
+              "serviceType": "testing",
+              "displayName": "ExternalProj#issue-1",
+              "webUrl": "https://somerandom.io/project/issue-id"
+            }
+          }
+        }
+      },
+      "403": {
+        "description": "Forbidden"
+      },
+      "404": {
+        "description": "Not Found"
+      }
+    },
+    "security": [
+      {
+        "auth_token": ["event:write"]
+      }
+    ]
+  }
+}

+ 89 - 0
api-docs/paths/integration-platform/sentry-app-installations.json

@@ -0,0 +1,89 @@
+{
+  "get": {
+    "tags": ["Integration"],
+    "description": "Return a list of integration platform installations for a given organization.",
+    "operationId": "List an Organization's Integration Platform Installations",
+    "parameters": [
+      {
+        "name": "organization_slug",
+        "in": "path",
+        "description": "The organization short name.",
+        "required": true,
+        "schema": {
+          "type": "string"
+        }
+      }
+    ],
+    "responses": {
+      "200": {
+        "description": "Success",
+        "content": {
+          "application/json": {
+            "schema": {
+              "type": "array",
+              "items": {
+                "type": "object",
+                "required": ["app", "organization", "uuid", "status"],
+                "properties": {
+                  "app": {
+                    "type": "object",
+                    "required": ["uuid", "slug"],
+                    "properties":
+                      {
+                        "uuid": {
+                          "type": "string"
+                        },
+                        "slug": {
+                          "type": "string"
+                        }
+                      }
+                  },
+                  "organization": {
+                    "type": "object",
+                    "required": ["slug"],
+                    "properties":
+                      {
+                        "slug": {
+                          "type": "string"
+                        }
+                      }
+                  },
+                  "uuid": {
+                    "type": "string"
+                  },
+                  "status": {
+                    "type": "string"
+                  }
+                }
+              }
+            },
+            "example": [
+              {
+                  "app": {
+                      "uuid": "a9988ad6-meow-4905-bb93-f7cbf4c96bbb",
+                      "slug": "cat-75c19a"
+                  },
+                  "organization": {
+                      "slug": "sentry"
+                  },
+                  "uuid": "01635075-m30w-4f96-8fc8-ff9680780a13",
+                  "status": "installed"
+              }
+            ]
+          }
+        }
+      },
+      "403": {
+        "description": "Forbidden"
+      },
+      "404": {
+        "description": "Not Found"
+      }
+    },
+    "security": [
+      {
+        "auth_token": ["org:read", "org:integrations"]
+      }
+    ]
+  }
+}

+ 1 - 1
src/sentry/api/endpoints/sentry_app_installation_external_issues.py

@@ -22,7 +22,7 @@ class SentryAppInstallationExternalIssuesEndpoint(ExternalIssueBaseEndpoint):
 
         try:
             group = Group.objects.get(
-                id=data.get("groupId"),
+                id=data.get("issueId"),
                 project_id__in=Project.objects.filter(organization_id=installation.organization_id),
             )
         except Group.DoesNotExist:

+ 1 - 1
src/sentry/api/serializers/models/platformexternalissue.py

@@ -7,7 +7,7 @@ class PlatformExternalIssueSerializer(Serializer):
     def serialize(self, obj, attrs, user):
         return {
             "id": str(obj.id),
-            "groupId": str(obj.group_id),
+            "issueId": str(obj.group_id),
             "serviceType": obj.service_type,
             "displayName": obj.display_name,
             "webUrl": obj.web_url,

+ 1 - 1
src/sentry/static/sentry/app/types/index.tsx

@@ -1257,7 +1257,7 @@ export type GroupIntegration = Integration & {
 
 export type PlatformExternalIssue = {
   id: string;
-  groupId: string;
+  issueId: string;
   serviceType: string;
   displayName: string;
   webUrl: string;

+ 36 - 0
tests/apidocs/endpoints/integration-platform/test-sentry-app-external-issue-details.py

@@ -0,0 +1,36 @@
+from django.core.urlresolvers import reverse
+from django.test.client import RequestFactory
+
+from tests.apidocs.util import APIDocsTestCase
+
+from sentry.models import SentryAppInstallation
+
+
+class SentryAppDetailsDocs(APIDocsTestCase):
+    def setUp(self):
+        self.org = self.create_organization(owner=self.user, name="Rowdy Tiger")
+        self.project = self.create_project(organization=self.org)
+        self.group = self.create_group(project=self.project)
+        self.sentry_app = self.create_sentry_app(
+            name="Hellboy App", published=True, organization=self.org
+        )
+        self.install = SentryAppInstallation(sentry_app=self.sentry_app, organization=self.org)
+        self.install.save()
+        self.external_issue = self.create_platform_external_issue(
+            group=self.group,
+            service_type=self.sentry_app.slug,
+            display_name="App#issue-1",
+            web_url=self.sentry_app.webhook_url,
+        )
+        self.url = reverse(
+            "sentry-api-0-sentry-app-installation-external-issue-details",
+            kwargs={"uuid": self.install.uuid, "external_issue_id": self.external_issue.id},
+        )
+
+        self.login_as(user=self.user)
+
+    def test_delete(self):
+        response = self.client.delete(self.url)
+        request = RequestFactory().delete(self.url)
+
+        self.validate_schema(request, response)

+ 36 - 0
tests/apidocs/endpoints/integration-platform/test-sentry-app-external-issues.py

@@ -0,0 +1,36 @@
+from django.core.urlresolvers import reverse
+from django.test.client import RequestFactory
+
+from tests.apidocs.util import APIDocsTestCase
+
+from sentry.models import SentryAppInstallation
+
+
+class SentryAppDocs(APIDocsTestCase):
+    def setUp(self):
+        self.org = self.create_organization(owner=self.user, name="Rowdy Tiger")
+        self.project = self.create_project(organization=self.org)
+        self.group = self.create_group(project=self.project)
+        self.sentry_app = self.create_sentry_app(
+            name="Hellboy App", published=True, organization=self.org
+        )
+        self.install = SentryAppInstallation(sentry_app=self.sentry_app, organization=self.org)
+        self.install.save()
+        self.url = reverse(
+            "sentry-api-0-sentry-app-installation-external-issues",
+            kwargs={"uuid": self.install.uuid},
+        )
+
+        self.login_as(user=self.user)
+
+    def test_post(self):
+        data = {
+            "issueId": self.group.id,
+            "webUrl": "https://somerandom.io/project/issue-id",
+            "project": "ExternalProj",
+            "identifier": "issue-1",
+        }
+        response = self.client.post(self.url, data)
+        request = RequestFactory().post(self.url, data)
+
+        self.validate_schema(request, response)

+ 31 - 0
tests/apidocs/endpoints/integration-platform/test-sentry-app-installations.py

@@ -0,0 +1,31 @@
+from django.core.urlresolvers import reverse
+from django.test.client import RequestFactory
+
+from tests.apidocs.util import APIDocsTestCase
+
+from sentry.models import SentryAppInstallation
+
+
+class SentryAppInstallationDocs(APIDocsTestCase):
+    def setUp(self):
+        self.user = self.create_user("foo@example.com")
+        self.org = self.create_organization(name="Jessla", owner=None)
+        self.create_member(user=self.user, organization=self.org, role="owner")
+
+        self.sentry_app = self.create_sentry_app(
+            name="Tesla App", published=True, organization=self.org
+        )
+        self.install = SentryAppInstallation(sentry_app=self.sentry_app, organization=self.org)
+        self.install.save()
+
+        self.login_as(user=self.user)
+        self.url = reverse(
+            "sentry-api-0-sentry-app-installations",
+            kwargs={"organization_slug": self.org.slug},
+        )
+
+    def test_get(self):
+        response = self.client.get(self.url)
+        request = RequestFactory().get(self.url)
+
+        self.validate_schema(request, response)

Некоторые файлы не были показаны из-за большого количества измененных файлов