Skip to content

Commit 0fc54db

Browse files
iamrajjoshipriscilawebdev
authored andcommitted
🐛 fix(github): make inbound/outbound assignment sync case-insensitive (#101984)
1 parent fba2c94 commit 0fc54db

File tree

4 files changed

+63
-1
lines changed

4 files changed

+63
-1
lines changed

src/sentry/integrations/github/integration.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,8 @@ def sync_assignee_outbound(
451451

452452
# Strip the @ from the username
453453
github_username = external_actor.external_name.lstrip("@")
454+
# lowercase the username
455+
github_username = github_username.lower()
454456

455457
# Only update GitHub if we have a username to assign or if we're explicitly deassigning
456458
if github_username or not assign:

src/sentry/integrations/utils/sync.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ def sync_group_assignee_inbound_by_external_actor(
139139

140140
external_actors = ExternalActor.objects.filter(
141141
provider=EXTERNAL_PROVIDERS_REVERSE[ExternalProviderEnum(integration.provider)].value,
142-
external_name=external_user_name,
142+
external_name__iexact=external_user_name,
143143
integration_id=integration.id,
144144
user_id__isnull=False,
145145
).values_list("user_id", flat=True)

tests/sentry/integrations/github/test_integration.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1791,6 +1791,31 @@ def test_sync_assignee_outbound(self) -> None:
17911791
assert request.url == "https://api.github.com/repos/Test-Organization/foo/issues/123"
17921792
assert orjson.loads(request.body) == {"assignees": ["octocat"]}
17931793

1794+
@responses.activate
1795+
def test_sync_assignee_outbound_case_insensitive(self) -> None:
1796+
"""Test assigning a GitHub issue to a user with linked GitHub account"""
1797+
1798+
user, installation, external_issue, _, _ = self._setup_assignee_sync_test(
1799+
external_name="@JohnDoe"
1800+
)
1801+
1802+
responses.add(
1803+
responses.PATCH,
1804+
"https://api.github.com/repos/Test-Organization/foo/issues/123",
1805+
json={"assignees": ["johndoe"]},
1806+
status=200,
1807+
)
1808+
1809+
responses.calls.reset()
1810+
1811+
with assume_test_silo_mode(SiloMode.REGION):
1812+
installation.sync_assignee_outbound(external_issue, user, assign=True)
1813+
1814+
assert len(responses.calls) == 1
1815+
request = responses.calls[0].request
1816+
assert request.url == "https://api.github.com/repos/Test-Organization/foo/issues/123"
1817+
assert orjson.loads(request.body) == {"assignees": ["johndoe"]}
1818+
17941819
@responses.activate
17951820
def test_sync_assignee_outbound_unassign(self) -> None:
17961821
"""Test unassigning a GitHub issue"""

tests/sentry/integrations/utils/test_sync.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,41 @@ def test_assignment_with_external_actor(
345345
assert updated_assignee.email == "[email protected]"
346346
mock_record_event.assert_called_with(EventLifecycleOutcome.SUCCESS, None, False, None)
347347

348+
@mock.patch("sentry.integrations.utils.metrics.EventLifecycle.record_event")
349+
def test_assignment_with_external_actor_case_insensitive(
350+
self,
351+
mock_record_event: mock.MagicMock,
352+
) -> None:
353+
"""Test assigning a group to a user via external actor."""
354+
assert self.group.get_assignee() is None
355+
356+
external_issue = self.create_integration_external_issue(
357+
group=self.group,
358+
key="JIRA-123",
359+
integration=self.example_integration,
360+
)
361+
362+
# Create external user mapping
363+
self.create_external_user(
364+
user=self.test_user,
365+
external_name="@JohnDoe",
366+
provider=ExternalProviders.GITHUB.value,
367+
integration=self.example_integration,
368+
)
369+
370+
sync_group_assignee_inbound_by_external_actor(
371+
integration=self.example_integration,
372+
external_user_name="@johndoe",
373+
external_issue_key=external_issue.key,
374+
assign=True,
375+
)
376+
377+
updated_assignee = self.group.get_assignee()
378+
assert updated_assignee is not None
379+
assert updated_assignee.id == self.test_user.id
380+
assert updated_assignee.email == "[email protected]"
381+
mock_record_event.assert_called_with(EventLifecycleOutcome.SUCCESS, None, False, None)
382+
348383
@mock.patch("sentry.integrations.utils.sync.where_should_sync")
349384
@mock.patch("sentry.integrations.utils.metrics.EventLifecycle.record_event")
350385
def test_assign_with_multiple_groups(

0 commit comments

Comments
 (0)