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: 7 additions & 0 deletions src/sentry/integrations/jira/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
IntegrationConfigurationError,
IntegrationError,
IntegrationFormError,
IntegrationProviderError,
)
from sentry.silo.base import all_silo_function
from sentry.users.models.identity import Identity
Expand Down Expand Up @@ -1013,6 +1014,12 @@ def raise_error(self, exc: Exception, identity: Identity | None = None) -> NoRet
},
)
raise IntegrationConfigurationError(exc.text) from exc
elif isinstance(exc, ApiError):
if "Product Unavailable" in exc.text or "Page Unavailable" in exc.text:
raise IntegrationProviderError(
"Something went wrong while communicating with Jira"
) from exc

super().raise_error(exc, identity=identity)

def sync_assignee_outbound(
Expand Down
9 changes: 9 additions & 0 deletions src/sentry/issues/endpoints/group_integration_details.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
IntegrationConfigurationError,
IntegrationError,
IntegrationFormError,
IntegrationProviderError,
)
from sentry.signals import integration_issue_created, integration_issue_linked
from sentry.types.activity import ActivityType
Expand Down Expand Up @@ -319,6 +320,14 @@ def post(self, request: Request, group, integration_id) -> Response:
except IntegrationError as e:
lifecycle.record_failure(e)
return Response({"non_field_errors": [str(e)]}, status=400)
except IntegrationProviderError as exc:
lifecycle.record_halt(exc)
return Response(
{
"detail": f"Something went wrong while communicating with {integration.provider}"
},
status=503,
)

external_issue_key = installation.make_external_key(data)
external_issue, created = ExternalIssue.objects.get_or_create(
Expand Down
2 changes: 2 additions & 0 deletions src/sentry/rules/actions/integrations/create_ticket/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
ApiUnauthorized,
IntegrationConfigurationError,
IntegrationFormError,
IntegrationProviderError,
IntegrationResourceNotFoundError,
)
from sentry.silo.base import region_silo_function
Expand Down Expand Up @@ -185,6 +186,7 @@ def create_issue(event: GroupEvent, futures: Sequence[RuleFuture]) -> None:
InvalidIdentity,
ApiUnauthorized,
IntegrationResourceNotFoundError,
IntegrationProviderError,
) as e:
# Most of the time, these aren't explicit failures, they're
# some misconfiguration of an issue field - typically Jira.
Expand Down
59 changes: 59 additions & 0 deletions tests/sentry/integrations/jira/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
IntegrationConfigurationError,
IntegrationError,
IntegrationFormError,
IntegrationProviderError,
)
from sentry.silo.base import SiloMode
from sentry.testutils.cases import APITestCase, IntegrationTestCase
Expand Down Expand Up @@ -768,6 +769,64 @@ def test_create_issue_with_configuration_error(self) -> None:
}
)

@responses.activate
def test_create_issue_product_unavailable_error(self) -> None:
responses.add(
responses.GET,
"https://example.atlassian.net/rest/api/2/issue/createmeta",
body=StubService.get_stub_json("jira", "createmeta_response.json"),
content_type="json",
)
# Simulate Jira returning an HTML "Product Unavailable" error page
responses.add(
responses.POST,
"https://example.atlassian.net/rest/api/2/issue",
status=503,
body='<!DOCTYPE html>\n<html lang="en">\n <head>\n <title>Atlassian Cloud Notifications - Product Unavailable</title>\n </head>\n <body>\n <h1>Jira has been deactivated</h1>\n </body>\n</html>',
content_type="text/html",
)
installation = self.integration.get_installation(self.organization.id)
with pytest.raises(
IntegrationProviderError, match="Something went wrong while communicating with Jira"
):
installation.create_issue(
{
"title": "example summary",
"description": "example bug report",
"issuetype": "1",
"project": "10000",
}
)

@responses.activate
def test_create_issue_page_unavailable_error(self) -> None:
responses.add(
responses.GET,
"https://example.atlassian.net/rest/api/2/issue/createmeta",
body=StubService.get_stub_json("jira", "createmeta_response.json"),
content_type="json",
)
# Simulate Jira returning an HTML "Page Unavailable" error
responses.add(
responses.POST,
"https://example.atlassian.net/rest/api/2/issue",
status=503,
body='<!DOCTYPE html>\n<html lang="en">\n <head>\n <title>Page Unavailable</title>\n </head>\n <body>\n <h1>Page Unavailable</h1>\n </body>\n</html>',
content_type="text/html",
)
installation = self.integration.get_installation(self.organization.id)
with pytest.raises(
IntegrationProviderError, match="Something went wrong while communicating with Jira"
):
installation.create_issue(
{
"title": "example summary",
"description": "example bug report",
"issuetype": "1",
"project": "10000",
}
)

@responses.activate
def test_create_issue_labels_and_option(self) -> None:
installation = self.integration.get_installation(self.organization.id)
Expand Down
Loading