Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions src/sentry/seer/endpoints/group_ai_autofix.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
from sentry.seer.autofix.utils import (
AutofixStoppingPoint,
CodingAgentProviderType,
has_project_connected_repos,
)
from sentry.seer.models import SeerPermissionError
from sentry.types.ratelimit import RateLimit, RateLimitCategory
Expand Down Expand Up @@ -182,12 +181,6 @@ def post(self, request: Request, group: Group) -> Response:

The process runs asynchronously, and you can get the state using the GET endpoint.
"""
if not has_project_connected_repos(group.organization, group.project):
return Response(
{"detail": "SCM integration is not configured for this project."},
status=status.HTTP_409_CONFLICT,
)

serializer = ExplorerAutofixRequestSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Expand Down
58 changes: 14 additions & 44 deletions tests/sentry/seer/endpoints/test_group_ai_autofix.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,8 @@ def test_get_returns_state(self, mock_get_explorer_state):
assert response.status_code == 200, response.data
mock_get_explorer_state.assert_called_once_with(group.organization, group.id)

@patch("sentry.seer.endpoints.group_ai_autofix.has_project_connected_repos", return_value=True)
@patch("sentry.seer.endpoints.group_ai_autofix.trigger_autofix_agent")
def test_post_triggers_autofix_agent(self, mock_trigger_explorer, _):
def test_post_triggers_autofix_agent(self, mock_trigger_explorer):
group = self.create_group()
mock_trigger_explorer.return_value = 123

Expand All @@ -55,23 +54,8 @@ def test_post_triggers_autofix_agent(self, mock_trigger_explorer, _):
assert response.data["run_id"] == 123
mock_trigger_explorer.assert_called_once()

@patch("sentry.seer.endpoints.group_ai_autofix.has_project_connected_repos", return_value=False)
def test_post_returns_409_without_connected_repos(self, _):
group = self.create_group()

self.login_as(user=self.user)
response = self.client.post(
self._get_url(group.id),
data={"step": "root_cause"},
format="json",
)

assert response.status_code == 409, response.data
assert response.data["detail"] == "SCM integration is not configured for this project."

@patch("sentry.seer.endpoints.group_ai_autofix.has_project_connected_repos", return_value=True)
@patch("sentry.seer.endpoints.group_ai_autofix.trigger_autofix_agent")
def test_stopping_point(self, mock_trigger_explorer, _):
def test_stopping_point(self, mock_trigger_explorer):
"""Stopping point forces the step to be root_cause"""
group = self.create_group()
mock_trigger_explorer.return_value = 123
Expand All @@ -96,9 +80,8 @@ def test_stopping_point(self, mock_trigger_explorer, _):
insert_index=None,
)

@patch("sentry.seer.endpoints.group_ai_autofix.has_project_connected_repos", return_value=True)
@patch("sentry.seer.endpoints.group_ai_autofix.trigger_autofix_agent")
def test_insert_index_passed_through(self, mock_trigger_explorer, _):
def test_insert_index_passed_through(self, mock_trigger_explorer):
"""POST passes insert_index to trigger_autofix_agent for retry-from-step."""
group = self.create_group()
mock_trigger_explorer.return_value = 123
Expand All @@ -122,9 +105,8 @@ def test_insert_index_passed_through(self, mock_trigger_explorer, _):
insert_index=3,
)

@patch("sentry.seer.endpoints.group_ai_autofix.has_project_connected_repos", return_value=True)
@patch("sentry.seer.endpoints.group_ai_autofix.trigger_autofix_agent")
def test_post_continue_unknown_run_returns_404(self, mock_trigger_explorer, _):
def test_post_continue_unknown_run_returns_404(self, mock_trigger_explorer):
mock_trigger_explorer.side_effect = SeerPermissionError("Unknown run id for group")
group = self.create_group()

Expand All @@ -138,9 +120,8 @@ def test_post_continue_unknown_run_returns_404(self, mock_trigger_explorer, _):
assert response.status_code == 404, response.data
mock_trigger_explorer.assert_called_once()

@patch("sentry.seer.endpoints.group_ai_autofix.has_project_connected_repos", return_value=True)
@patch("sentry.seer.endpoints.group_ai_autofix.trigger_autofix_agent")
def test_post_returns_402_when_no_seer_quota(self, mock_trigger_explorer, _):
def test_post_returns_402_when_no_seer_quota(self, mock_trigger_explorer):
"""POST returns 402 Payment Required when quota check fails."""
mock_trigger_explorer.side_effect = NoSeerQuotaException()
group = self.create_group()
Expand All @@ -155,10 +136,7 @@ def test_post_returns_402_when_no_seer_quota(self, mock_trigger_explorer, _):
assert response.status_code == 402, response.data
assert response.data == "No budget for Seer Autofix."

@patch("sentry.seer.endpoints.group_ai_autofix.has_project_connected_repos", return_value=True)
def test_post_coding_agent_handoff_errors_with_both_provider_and_integration_id(
self, _
) -> None:
def test_post_coding_agent_handoff_errors_with_both_provider_and_integration_id(self) -> None:
"""POST returns 400 when both provider and integration_id are specified for coding_agent_handoff."""
group = self.create_group()

Expand All @@ -177,9 +155,8 @@ def test_post_coding_agent_handoff_errors_with_both_provider_and_integration_id(
assert response.status_code == 400, response.data
assert response.data["detail"] == "Cannot specify both integration_id and provider"

@patch("sentry.seer.endpoints.group_ai_autofix.has_project_connected_repos", return_value=True)
@patch("sentry.seer.endpoints.group_ai_autofix.trigger_coding_agent_handoff")
def test_post_coding_agent_handoff_unknown_run_returns_404(self, mock_handoff, _):
def test_post_coding_agent_handoff_unknown_run_returns_404(self, mock_handoff):
mock_handoff.side_effect = SeerPermissionError("Unknown run id for group")
group = self.create_group()

Expand All @@ -198,9 +175,8 @@ def test_post_coding_agent_handoff_unknown_run_returns_404(self, mock_handoff, _
mock_handoff.assert_called_once()
assert mock_handoff.call_args.kwargs["referrer"] == AutofixReferrer.GROUP_AUTOFIX_ENDPOINT

@patch("sentry.seer.endpoints.group_ai_autofix.has_project_connected_repos", return_value=True)
@patch("sentry.seer.endpoints.group_ai_autofix.trigger_coding_agent_handoff")
def test_post_coding_agent_handoff_auto_creates_pr_by_default(self, mock_handoff, _):
def test_post_coding_agent_handoff_auto_creates_pr_by_default(self, mock_handoff):
mock_handoff.return_value = {"successes": [{"repo_name": "owner/repo"}], "failures": []}
group = self.create_group()

Expand All @@ -226,10 +202,9 @@ def test_post_coding_agent_handoff_auto_creates_pr_by_default(self, mock_handoff
auto_create_pr=True,
)

@patch("sentry.seer.endpoints.group_ai_autofix.has_project_connected_repos", return_value=True)
@patch("sentry.seer.agent.client_utils.make_agent_state_request")
@patch("sentry.seer.agent.client.make_agent_update_request")
def test_open_pr(self, mock_explorer_update_request, mock_explorer_state_request, _):
def test_open_pr(self, mock_explorer_update_request, mock_explorer_state_request):
self.login_as(user=self.user)
group = self.create_group()

Expand Down Expand Up @@ -266,11 +241,10 @@ def test_open_pr(self, mock_explorer_update_request, mock_explorer_state_request
assert response.status_code == 202, response.data
assert response.data == {"run_id": 123}

@patch("sentry.seer.endpoints.group_ai_autofix.has_project_connected_repos", return_value=True)
@patch("sentry.seer.agent.client_utils.make_agent_state_request")
@patch("sentry.seer.agent.client.make_agent_update_request")
def test_open_pr_with_repo_name(
self, mock_explorer_update_request, mock_explorer_state_request, _
self, mock_explorer_update_request, mock_explorer_state_request
):
self.login_as(user=self.user)
group = self.create_group()
Expand Down Expand Up @@ -311,11 +285,10 @@ def test_open_pr_with_repo_name(
assert call_body["payload"]["type"] == "create_pr"
assert call_body["payload"]["repo_name"] == "my-org/my-repo"

@patch("sentry.seer.endpoints.group_ai_autofix.has_project_connected_repos", return_value=True)
@patch("sentry.seer.agent.client_utils.make_agent_state_request")
@patch("sentry.seer.agent.client.make_agent_update_request")
def test_open_pr_without_repo_name(
self, mock_explorer_update_request, mock_explorer_state_request, _
self, mock_explorer_update_request, mock_explorer_state_request
):
self.login_as(user=self.user)
group = self.create_group()
Expand Down Expand Up @@ -355,8 +328,7 @@ def test_open_pr_without_repo_name(
assert call_body["payload"]["type"] == "create_pr"
assert "repo_name" not in call_body["payload"]

@patch("sentry.seer.endpoints.group_ai_autofix.has_project_connected_repos", return_value=True)
def test_open_pr_no_run_id(self, _) -> None:
def test_open_pr_no_run_id(self) -> None:
self.login_as(user=self.user)
group = self.create_group()

Expand All @@ -369,9 +341,8 @@ def test_open_pr_no_run_id(self, _) -> None:
assert response.status_code == 400, response.data
assert response.data["detail"] == "run_id is required for open_pr"

@patch("sentry.seer.endpoints.group_ai_autofix.has_project_connected_repos", return_value=True)
@patch("sentry.seer.agent.client_utils.make_agent_state_request")
def test_open_pr_permission_error(self, mock_explorer_state_request, _):
def test_open_pr_permission_error(self, mock_explorer_state_request):
self.login_as(user=self.user)
group = self.create_group()

Expand Down Expand Up @@ -400,8 +371,7 @@ def test_open_pr_permission_error(self, mock_explorer_state_request, _):

assert response.status_code == 404, response.data

@patch("sentry.seer.endpoints.group_ai_autofix.has_project_connected_repos", return_value=True)
def test_open_pr_coding_disabled(self, _):
def test_open_pr_coding_disabled(self):
self.login_as(user=self.user)
group = self.create_group()
self.organization.update_option("sentry:enable_seer_coding", False)
Expand Down
Loading