diff --git a/src/sentry/seer/assisted_query/issues_tools.py b/src/sentry/seer/assisted_query/issues_tools.py index 08781eaaad74ea..0cc9282afd0d47 100644 --- a/src/sentry/seer/assisted_query/issues_tools.py +++ b/src/sentry/seer/assisted_query/issues_tools.py @@ -251,13 +251,14 @@ def get_issue_filter_keys( stats_period: str | None = None, start: str | None = None, end: str | None = None, + include_feature_flags: bool = True, ) -> dict[str, Any] | None: """ Get available issue filter keys (tags, feature flags, and built-in fields). Calls the Sentry tags API endpoint with different datasets to get: - Tags (dataset=events and dataset=search_issues merged) - - Feature flags (dataset=events with useFlagsBackend=1) + - Feature flags (dataset=events with useFlagsBackend=1) - optional - Built-in fields (e.g., is, assigned_or_suggested, issue.priority, etc.) Args: @@ -266,11 +267,12 @@ def get_issue_filter_keys( stats_period: Time period for the query (e.g., "24h", "7d", "14d"). Cannot be provided with start and end. start: Start date for the query (ISO string). Must be provided with end. end: End date for the query (ISO string). Must be provided with start. + include_feature_flags: Whether to include feature flags in the response (default True). Returns: - Dictionary containing three arrays: + Dictionary containing: - tags: Merged tags from events and search_issues datasets - - feature_flags: Feature flags from events dataset + - feature_flags: Feature flags from events dataset (only if include_feature_flags is True) - built_in_fields: Built-in issue search fields (e.g., is, assigned_or_suggested, issue.priority) Returns None if organization doesn't exist. """ @@ -328,31 +330,37 @@ def get_issue_filter_keys( tags_dict[tag.get("key")] = tag tags = list(tags_dict.values()) - # Get feature flags - flags_params = { - **base_params, - "dataset": Dataset.Events.value, - "useFlagsBackend": "1", - "useCache": "1", - } - flags_resp = client.get( - auth=api_key, - user=None, - path=f"/organizations/{organization.slug}/tags/", - params=flags_params, - ) - feature_flags = flags_resp.data if flags_resp.status_code == 200 else [] + # Get feature flags (optional) + feature_flags: list[Any] = [] + if include_feature_flags: + flags_params = { + **base_params, + "dataset": Dataset.Events.value, + "useFlagsBackend": "1", + "useCache": "1", + } + flags_resp = client.get( + auth=api_key, + user=None, + path=f"/organizations/{organization.slug}/tags/", + params=flags_params, + ) + feature_flags = flags_resp.data if flags_resp.status_code == 200 else [] # Get built-in issue fields tag_keys = [tag.get("key") for tag in tags if tag.get("key")] built_in_fields = _get_built_in_issue_fields(organization, tag_keys) - return { + result: dict[str, Any] = { "tags": tags, - "feature_flags": feature_flags, "built_in_fields": built_in_fields, } + if include_feature_flags: + result["feature_flags"] = feature_flags + + return result + def get_filter_key_values( *, diff --git a/tests/sentry/seer/assisted_query/test_issues_tools.py b/tests/sentry/seer/assisted_query/test_issues_tools.py index 1bc8051d882d79..538ffe5cd8b440 100644 --- a/tests/sentry/seer/assisted_query/test_issues_tools.py +++ b/tests/sentry/seer/assisted_query/test_issues_tools.py @@ -157,6 +157,79 @@ def test_get_issue_filter_keys_multiple_projects(self): assert "project1_tag" in tag_keys assert "project2_tag" in tag_keys + def test_get_issue_filter_keys_without_feature_flags(self): + """Test that feature flags are excluded when include_feature_flags=False""" + # Create an error event with custom tags + self.store_event( + data={ + "event_id": "a" * 32, + "tags": {"fruit": "apple"}, + "timestamp": self.min_ago.isoformat(), + }, + project_id=self.project.id, + ) + + # Create an event with feature flags + self.store_event( + data={ + "contexts": { + "flags": { + "values": [ + {"flag": "feature_a", "result": True}, + ] + } + }, + "timestamp": self.min_ago.isoformat(), + }, + project_id=self.project.id, + ) + + result = get_issue_filter_keys( + org_id=self.organization.id, + project_ids=[self.project.id], + include_feature_flags=False, + ) + + assert result is not None + # Tags and built_in_fields should still be present + assert "tags" in result + assert "built_in_fields" in result + # feature_flags key should NOT be in the result + assert "feature_flags" not in result + + # Verify tags still work + tags = result["tags"] + tag_keys = {tag["key"] for tag in tags} + assert "fruit" in tag_keys + + def test_get_issue_filter_keys_with_feature_flags_default(self): + """Test that feature flags are included by default""" + # Create an event with feature flags + self.store_event( + data={ + "contexts": { + "flags": { + "values": [ + {"flag": "feature_a", "result": True}, + ] + } + }, + "timestamp": self.min_ago.isoformat(), + }, + project_id=self.project.id, + ) + + # Call without specifying include_feature_flags (should default to True) + result = get_issue_filter_keys( + org_id=self.organization.id, + project_ids=[self.project.id], + ) + + assert result is not None + # feature_flags key should be present by default + assert "feature_flags" in result + assert isinstance(result["feature_flags"], list) + @pytest.mark.django_db(databases=["default", "control"]) class TestGetFilterKeyValues(APITestCase, SnubaTestCase, OccurrenceTestMixin):