Browse Source

ref(integrations): Normalize integration module structure (#34887)

Marcos Gaeta 2 years ago
parent
commit
c8a6c37a9c

+ 5 - 3
src/sentry/apidocs/public_exclusion_list.py

@@ -521,9 +521,11 @@ from sentry.integrations.jira_server.webhooks import (
     JiraIssueUpdatedWebhook as JiraServerIssueUpdatedWebhook,
 )
 from sentry.integrations.msteams.webhook import MsTeamsWebhookEndpoint
-from sentry.integrations.slack.endpoints.action import SlackActionEndpoint
-from sentry.integrations.slack.endpoints.command import SlackCommandsEndpoint
-from sentry.integrations.slack.endpoints.event import SlackEventEndpoint
+from sentry.integrations.slack.webhooks import (
+    SlackActionEndpoint,
+    SlackCommandsEndpoint,
+    SlackEventEndpoint,
+)
 from sentry.integrations.vercel.generic_webhook import VercelGenericWebhookEndpoint
 from sentry.integrations.vercel.webhook import VercelWebhookEndpoint
 from sentry.integrations.vsts.search import VstsSearchEndpoint

+ 12 - 5
src/sentry/integrations/__init__.py

@@ -4,11 +4,18 @@ receive webhook requests from third-party services. It contains the business
 logic to implement several of Sentry's features including Ticket Rules,
 Notifications, and Stacktrace Linking. No models are defined in this module.
 
-See also:
-    src/sentry/models/integrations/
-    src/sentry/notifications/
-    src/sentry/shared_integrations/
-    src/sentry_plugins/
+You should expect each provider to have its own module with the following files:
+    - actions/          Alert Rule Action definitions.
+    - client.py         Custom APIClient for the provider.
+    - integration.py    All of the business logic. Implements the IntegrationInstallation interface.
+    - urls.py           Map externally facing URLs to the webhooks defined below.
+    - webhooks/         Endpoints that the providers can hook into to perform actions.
+
+For more Integrations code, see also:
+    - src/sentry/models/integrations/
+    - src/sentry/notifications/
+    - src/sentry/shared_integrations/
+    - src/sentry_plugins/
 """
 
 __all__ = (

+ 1 - 1
src/sentry/integrations/jira/__init__.py

@@ -1,8 +1,8 @@
 from sentry.rules import rules
 
+from .actions import JiraCreateTicketAction
 from .client import JIRA_KEY, JiraApiClient
 from .integration import JiraIntegration, JiraIntegrationProvider
-from .notify_action import JiraCreateTicketAction
 
 __all__ = (
     "JIRA_KEY",

+ 7 - 0
src/sentry/integrations/jira/actions/__init__.py

@@ -0,0 +1,7 @@
+from .create_ticket import JiraCreateTicketAction
+from .form import JiraNotifyServiceForm
+
+__all__ = (
+    "JiraCreateTicketAction",
+    "JiraNotifyServiceForm",
+)

+ 2 - 19
src/sentry/integrations/jira/notify_action.py → src/sentry/integrations/jira/actions/create_ticket.py

@@ -1,29 +1,12 @@
 from __future__ import annotations
 
-import logging
 from typing import Any
 
-from django import forms
-from django.utils.translation import ugettext_lazy as _
-
+from sentry.integrations.jira.actions.form import JiraNotifyServiceForm
 from sentry.models import Integration
-from sentry.rules.actions import IntegrationNotifyServiceForm, TicketEventAction
+from sentry.rules.actions import TicketEventAction
 from sentry.utils.http import absolute_uri
 
-logger = logging.getLogger("sentry.rules")
-
-
-class JiraNotifyServiceForm(IntegrationNotifyServiceForm):
-    def clean(self) -> dict[str, Any] | None:
-        cleaned_data = super().clean()
-
-        integration = cleaned_data.get("integration")
-        try:
-            Integration.objects.get(id=integration)
-        except Integration.DoesNotExist:
-            raise forms.ValidationError(_("Jira integration is a required field."), code="invalid")
-        return cleaned_data
-
 
 class JiraCreateTicketAction(TicketEventAction):
     id = "sentry.integrations.jira.notify_action.JiraCreateTicketAction"

+ 21 - 0
src/sentry/integrations/jira/actions/form.py

@@ -0,0 +1,21 @@
+from __future__ import annotations
+
+from typing import Any
+
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+
+from sentry.models import Integration
+from sentry.rules.actions import IntegrationNotifyServiceForm
+
+
+class JiraNotifyServiceForm(IntegrationNotifyServiceForm):
+    def clean(self) -> dict[str, Any] | None:
+        cleaned_data = super().clean()
+
+        integration = cleaned_data.get("integration")
+        try:
+            Integration.objects.get(id=integration)
+        except Integration.DoesNotExist:
+            raise forms.ValidationError(_("Jira integration is a required field."), code="invalid")
+        return cleaned_data

+ 1 - 1
src/sentry/integrations/msteams/__init__.py

@@ -1,7 +1,7 @@
 from sentry.rules import rules
 from sentry.utils.imports import import_submodules
 
-from .notify_action import MsTeamsNotifyServiceAction
+from .actions import MsTeamsNotifyServiceAction
 
 import_submodules(globals(), __name__, __path__)
 

+ 7 - 0
src/sentry/integrations/msteams/actions/__init__.py

@@ -0,0 +1,7 @@
+from .form import MsTeamsNotifyServiceForm
+from .notification import MsTeamsNotifyServiceAction
+
+__all__ = (
+    "MsTeamsNotifyServiceForm",
+    "MsTeamsNotifyServiceAction",
+)

+ 47 - 0
src/sentry/integrations/msteams/actions/form.py

@@ -0,0 +1,47 @@
+from __future__ import annotations
+
+from typing import Any
+
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+
+
+class MsTeamsNotifyServiceForm(forms.Form):
+    team = forms.ChoiceField(choices=(), widget=forms.Select())
+    channel = forms.CharField(widget=forms.TextInput())
+    channel_id = forms.HiddenInput()
+
+    def __init__(self, *args, **kwargs):
+        team_list = [(i.id, i.name) for i in kwargs.pop("integrations")]
+        self.channel_transformer = kwargs.pop("channel_transformer")
+
+        super().__init__(*args, **kwargs)
+
+        if team_list:
+            self.fields["team"].initial = team_list[0][0]
+
+        self.fields["team"].choices = team_list
+        self.fields["team"].widget.choices = self.fields["team"].choices
+
+    def clean(self) -> dict[str, Any] | None:
+        cleaned_data = super().clean()
+
+        integration_id = cleaned_data.get("team")
+        channel = cleaned_data.get("channel", "")
+        channel_id = self.channel_transformer(integration_id, channel)
+
+        if channel_id is None and integration_id is not None:
+            params = {
+                "channel": channel,
+                "team": dict(self.fields["team"].choices).get(int(integration_id)),
+            }
+
+            raise forms.ValidationError(
+                _('The channel or user "%(channel)s" could not be found in the %(team)s Team.'),
+                code="invalid",
+                params=params,
+            )
+
+        cleaned_data["channel_id"] = channel_id
+
+        return cleaned_data

+ 4 - 50
src/sentry/integrations/msteams/notify_action.py → src/sentry/integrations/msteams/actions/notification.py

@@ -1,59 +1,13 @@
 from __future__ import annotations
 
-from typing import Any
-
-from django import forms
-from django.utils.translation import ugettext_lazy as _
-
+from sentry.integrations.msteams.actions.form import MsTeamsNotifyServiceForm
+from sentry.integrations.msteams.card_builder import build_group_card
+from sentry.integrations.msteams.client import MsTeamsClient
+from sentry.integrations.msteams.utils import get_channel_id
 from sentry.models import Integration
 from sentry.rules.actions import IntegrationEventAction
 from sentry.utils import metrics
 
-from .card_builder import build_group_card
-from .client import MsTeamsClient
-from .utils import get_channel_id
-
-
-class MsTeamsNotifyServiceForm(forms.Form):
-    team = forms.ChoiceField(choices=(), widget=forms.Select())
-    channel = forms.CharField(widget=forms.TextInput())
-    channel_id = forms.HiddenInput()
-
-    def __init__(self, *args, **kwargs):
-        team_list = [(i.id, i.name) for i in kwargs.pop("integrations")]
-        self.channel_transformer = kwargs.pop("channel_transformer")
-
-        super().__init__(*args, **kwargs)
-
-        if team_list:
-            self.fields["team"].initial = team_list[0][0]
-
-        self.fields["team"].choices = team_list
-        self.fields["team"].widget.choices = self.fields["team"].choices
-
-    def clean(self) -> dict[str, Any] | None:
-        cleaned_data = super().clean()
-
-        integration_id = cleaned_data.get("team")
-        channel = cleaned_data.get("channel", "")
-        channel_id = self.channel_transformer(integration_id, channel)
-
-        if channel_id is None and integration_id is not None:
-            params = {
-                "channel": channel,
-                "team": dict(self.fields["team"].choices).get(int(integration_id)),
-            }
-
-            raise forms.ValidationError(
-                _('The channel or user "%(channel)s" could not be found in the %(team)s Team.'),
-                code="invalid",
-                params=params,
-            )
-
-        cleaned_data["channel_id"] = channel_id
-
-        return cleaned_data
-
 
 class MsTeamsNotifyServiceAction(IntegrationEventAction):
     id = "sentry.integrations.msteams.notify_action.MsTeamsNotifyServiceAction"

Some files were not shown because too many files changed in this diff