Browse Source

fix(issue-link): Exclude choices that do not conform to our API (#33536)

Objective:
In sentry_rule.data we have saved select field choices that do not conform to our API of Array<string, string>. This causes our frontend to crash when trying to render the form. Instead we will filter out those choices and if the saved value for the field was in the excluded choices set, we will ask the user to reselect for that field.
NisanthanNanthakumar 2 years ago
parent
commit
f4c664aaec

+ 10 - 0
src/sentry/api/endpoints/project_rule_details.py

@@ -63,6 +63,16 @@ class ProjectRuleDetailsEndpoint(RuleEndpoint):
                 del action["_sentry_app_installation"]
                 del action["_sentry_app_component"]
 
+            # TODO(nisanthan): This is a temporary fix. We need to save both the label and value of the selected choice and not save all the choices.
+            if action.get("id") == "sentry.integrations.jira.notify_action.JiraCreateTicketAction":
+                for field in action.get("dynamic_form_fields", []):
+                    if field.get("choices"):
+                        field["choices"] = [
+                            p
+                            for p in field.get("choices", [])
+                            if isinstance(p[0], str) and isinstance(p[1], str)
+                        ]
+
         if len(errors):
             serialized_rule["errors"] = errors
 

+ 75 - 0
tests/sentry/api/endpoints/test_project_rule_details.py

@@ -232,6 +232,81 @@ class ProjectRuleDetailsTest(APITestCase):
         )
         assert resp.data["lastTriggered"] == datetime.now().replace(tzinfo=UTC)
 
+    def test_with_jira_action_error(self):
+        self.login_as(user=self.user)
+        self.integration = Integration.objects.create(
+            provider="jira", name="Jira", external_id="jira:1"
+        )
+        self.integration.add_organization(self.organization, self.user)
+
+        conditions = [
+            {"id": "sentry.rules.conditions.every_event.EveryEventCondition"},
+            {"id": "sentry.rules.filters.issue_occurrences.IssueOccurrencesFilter", "value": 10},
+        ]
+
+        actions = [
+            {
+                "id": "sentry.integrations.jira.notify_action.JiraCreateTicketAction",
+                "integration": self.integration.id,
+                "customfield_epic_link": "EPIC-3",
+                "customfield_severity": "Medium",
+                "dynamic_form_fields": [
+                    {
+                        "choices": [
+                            ["EPIC-1", "Citizen Knope"],
+                            ["EPIC-2", "The Comeback Kid"],
+                            ["EPIC-3", {"key": None, "ref": None, "props": {}, "_owner": None}],
+                        ],
+                        "label": "Epic Link",
+                        "name": "customfield_epic_link",
+                        "required": False,
+                        "type": "select",
+                        "url": f"/extensions/jira/search/{self.organization.slug}/{self.integration.id}/",
+                    },
+                    {
+                        "choices": [
+                            ["Very High", "Very High"],
+                            ["High", "High"],
+                            ["Medium", "Medium"],
+                            ["Low", "Low"],
+                        ],
+                        "label": "Severity",
+                        "name": "customfield_severity",
+                        "required": True,
+                        "type": "select",
+                    },
+                ],
+            }
+        ]
+        data = {
+            "conditions": conditions,
+            "actions": actions,
+            "filter_match": "all",
+            "action_match": "all",
+            "frequency": 30,
+        }
+
+        rule = Rule.objects.create(project=self.project, label="foo", data=data)
+
+        url = reverse(
+            "sentry-api-0-project-rule-details",
+            kwargs={
+                "organization_slug": self.project.organization.slug,
+                "project_slug": self.project.slug,
+                "rule_id": rule.id,
+            },
+        )
+
+        response = self.client.get(url, format="json")
+
+        assert response.status_code == 200
+
+        # Expect that the choices get filtered to match the API: Array<string, string>
+        assert response.data["actions"][0].get("dynamic_form_fields")[0].get("choices") == [
+            ["EPIC-1", "Citizen Knope"],
+            ["EPIC-2", "The Comeback Kid"],
+        ]
+
 
 class UpdateProjectRuleTest(APITestCase):
     @patch("sentry.signals.alert_rule_edited.send_robust")