Browse Source

feat(webhooks):Add a webhook for issue.escalating (#69997)

issue_escalating is already an existing analytics event that gets thrown
but we don't have a webhook for it. So this PR maps a webhook to
issue_escalating signal.
Athena Moghaddam 10 months ago
parent
commit
ed239ed523

+ 1 - 0
src/sentry/issues/escalating.py

@@ -522,6 +522,7 @@ def manage_issue_states(
                 event=event,
                 event=event,
                 sender=manage_issue_states,
                 sender=manage_issue_states,
                 was_until_escalating=True if has_forecast else False,
                 was_until_escalating=True if has_forecast else False,
+                new_substatus=GroupSubStatus.ESCALATING,
             )
             )
             if data and activity_data and has_forecast:  # Redundant checks needed for typing
             if data and activity_data and has_forecast:  # Redundant checks needed for typing
                 data.update(activity_data)
                 data.update(activity_data)

+ 27 - 1
src/sentry/receivers/sentry_apps.py

@@ -20,6 +20,7 @@ from sentry.signals import (
     comment_deleted,
     comment_deleted,
     comment_updated,
     comment_updated,
     issue_assigned,
     issue_assigned,
+    issue_escalating,
     issue_ignored,
     issue_ignored,
     issue_resolved,
     issue_resolved,
     issue_unresolved,
     issue_unresolved,
@@ -72,7 +73,32 @@ def send_issue_unresolved_webhook(
     user: User | RpcUser | None = None,
     user: User | RpcUser | None = None,
     new_substatus: GroupSubStatus | None = None,
     new_substatus: GroupSubStatus | None = None,
     **kwargs,
     **kwargs,
-):
+) -> None:
+    send_issue_unresolved_webhook_helper(
+        group=group, project=project, user=user, new_substatus=new_substatus, **kwargs
+    )
+
+
+@issue_escalating.connect(weak=False)
+def send_issue_escalating_webhook(
+    group: Group,
+    project: Project,
+    new_substatus: GroupSubStatus | None = None,
+    **kwargs,
+) -> None:
+    # Escalating is a form of unresolved so we send the same webhook
+    send_issue_unresolved_webhook_helper(
+        group=group, project=project, new_substatus=new_substatus, **kwargs
+    )
+
+
+def send_issue_unresolved_webhook_helper(
+    group: Group,
+    project: Project,
+    user: User | RpcUser | None = None,
+    new_substatus: GroupSubStatus | None = None,
+    **kwargs,
+) -> None:
     organization = project.organization
     organization = project.organization
     if features.has("organizations:webhooks-unresolved", organization):
     if features.has("organizations:webhooks-unresolved", organization):
         send_workflow_webhooks(
         send_workflow_webhooks(

+ 22 - 0
tests/sentry/receivers/test_sentry_apps.py

@@ -6,11 +6,13 @@ from unittest.mock import patch
 from sentry.api.serializers import serialize
 from sentry.api.serializers import serialize
 from sentry.api.serializers.models.user import UserSerializer
 from sentry.api.serializers.models.user import UserSerializer
 from sentry.constants import SentryAppInstallationStatus
 from sentry.constants import SentryAppInstallationStatus
+from sentry.issues.escalating import manage_issue_states
 from sentry.issues.ongoing import bulk_transition_group_to_ongoing
 from sentry.issues.ongoing import bulk_transition_group_to_ongoing
 from sentry.models.activity import Activity
 from sentry.models.activity import Activity
 from sentry.models.commit import Commit
 from sentry.models.commit import Commit
 from sentry.models.group import GroupStatus
 from sentry.models.group import GroupStatus
 from sentry.models.groupassignee import GroupAssignee
 from sentry.models.groupassignee import GroupAssignee
+from sentry.models.groupinbox import GroupInboxReason
 from sentry.models.grouplink import GroupLink
 from sentry.models.grouplink import GroupLink
 from sentry.models.release import Release
 from sentry.models.release import Release
 from sentry.models.repository import Repository
 from sentry.models.repository import Repository
@@ -98,6 +100,26 @@ class TestIssueWorkflowNotifications(APITestCase):
         )
         )
         assert delay.call_count == 2
         assert delay.call_count == 2
 
 
+    @with_feature("organizations:webhooks-unresolved")
+    def test_notify_after_escalating(self, delay):
+        # First we need to have an ignored issue
+        self.update_issue({"status": "ignored", "substatus": "until_escalating"})
+        event = self.issue.get_latest_event()
+        manage_issue_states(
+            group=self.issue,
+            group_inbox_reason=GroupInboxReason.ESCALATING,
+            event=event,
+            activity_data={},
+        )
+        delay.assert_any_call(
+            installation_id=self.install.id,
+            issue_id=self.issue.id,
+            type="unresolved",
+            user_id=None,
+            data={"substatus": "escalating"},
+        )
+        assert delay.call_count == 2
+
     def test_notify_after_basic_resolved(self, delay):
     def test_notify_after_basic_resolved(self, delay):
         self.update_issue()
         self.update_issue()