Skip to content

🐛 fix[gitlab]: add assignee sync diagnostics#115356

Open
iamrajjoshi wants to merge 1 commit into
masterfrom
raj--gitlab--assignee-sync-lifecycle
Open

🐛 fix[gitlab]: add assignee sync diagnostics#115356
iamrajjoshi wants to merge 1 commit into
masterfrom
raj--gitlab--assignee-sync-lifecycle

Conversation

@iamrajjoshi
Copy link
Copy Markdown
Collaborator

@iamrajjoshi iamrajjoshi commented May 12, 2026

Description of the change

I am not fully certain we have the root cause of the GitLab assignment sync failures yet. Based on review and hand testing, this no longer changes assignee matching to prefer mapped external IDs or stricter username matching; it keeps the existing GitLab username search behavior.

This adds lifecycle context around inbound and outbound assignment sync so the next failure has enough detail to diagnose the mapping/search path. It preserves the existing no-op return behavior for GitLab outbound cases that previously returned early, including missing mapped external actors, invalid issue keys, GitLab user search failures, and empty GitLab user search results.

Test plan

  • Python compile check for touched files
  • Ruff check and format hooks for touched files
  • Targeted mypy hook for touched source files
  • Targeted pytest attempted locally, but Postgres/Redis devservices were not running in this worktree

Considerations

This is intentionally diagnostic: it preserves the current GitLab username resolution path while adding enough context to confirm or disprove the current assignment-sync hypothesis.

@github-actions github-actions Bot added the Scope: Backend Automatically applied to PRs that change backend components label May 12, 2026
@iamrajjoshi iamrajjoshi force-pushed the raj--gitlab--assignee-sync-lifecycle branch from dd53ec7 to d3b924f Compare May 12, 2026 04:04
@iamrajjoshi iamrajjoshi self-assigned this May 12, 2026
Comment on lines +126 to +130
if external_actor.external_id:
try:
gitlab_user_id = int(external_actor.external_id)
except ValueError:
logger.warning("assignee-outbound.invalid-external-id", extra=log_context)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case will never execute. We don't set external ID for any of our GitLab mappings, so I'm not sure if this changes anything.


# Search for the GitLab user by username to get their user ID
try:
users = client.search_users(gitlab_username) or []
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hand tested this API with my GitLab user, and this request should have returned a single user, so I can vouch that this is correct at least. Also, this API only returns a single username when a username is passed as query param, so the previous logic was slightly more correct: https://docs.gitlab.com/api/users/#as-a-regular-user

@iamrajjoshi iamrajjoshi force-pushed the raj--gitlab--assignee-sync-lifecycle branch from d3b924f to 82a466e Compare May 18, 2026 15:03
@iamrajjoshi iamrajjoshi changed the title 🐛 fix[gitlab]: sync assignees by external id 🐛 fix[gitlab]: add assignee sync diagnostics May 18, 2026
@iamrajjoshi iamrajjoshi force-pushed the raj--gitlab--assignee-sync-lifecycle branch from 82a466e to 0e3ed16 Compare May 18, 2026 15:07
@iamrajjoshi iamrajjoshi force-pushed the raj--gitlab--assignee-sync-lifecycle branch from 0e3ed16 to ef898a1 Compare May 18, 2026 15:09
@iamrajjoshi iamrajjoshi marked this pull request as ready for review May 30, 2026 21:41
@iamrajjoshi iamrajjoshi requested a review from a team as a code owner May 30, 2026 21:41
@iamrajjoshi iamrajjoshi force-pushed the raj--gitlab--assignee-sync-lifecycle branch from ef898a1 to 8b0e4f7 Compare May 30, 2026 21:41
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 30, 2026

Backend Test Failures

Failures on f844feb in this run:

tests/sentry/models/test_groupassignee.py::GroupAssigneeTestCase::test_assignee_sync_outbound_assignlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/models/test_groupassignee.py:167: in test_assignee_sync_outbound_assign
    mock_sync_assignee_outbound.assert_called_with(
/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/unittest/mock.py:977: in assert_called_with
    raise AssertionError(_error_message()) from cause
E   AssertionError: expected call not found.
E   Expected: sync_assignee_outbound(<ExternalIssue at 0x7f5ef8b887d0: id=14, organization_id=4558229068513312, integration_id=38, key='APP-123'>, RpcUser(id=92, pk=92, name='', email='admin@localhost', username='admin@localhost', actor_id=None, display_name='admin@localhost', label='admin@localhost', is_superuser=True, is_authenticated=True, is_anonymous=False, is_active=True, is_staff=True, is_unclaimed=False, last_active=datetime.datetime(2026, 5, 30, 21, 45, 19, 878251, tzinfo=datetime.timezone.utc), is_sentry_app=False, password_usable=True, is_password_expired=False, is_suspended=False, roles=frozenset(), permissions=frozenset(), avatar=None, emails=frozenset({'admin@localhost'}), useremails=[RpcUserEmail(id=91, email='admin@localhost', is_verified=True)], authenticators=[]), assign=True, assignment_source=None)
E     Actual: sync_assignee_outbound(<ExternalIssue at 0x7f5ef92a8870: id=14, organization_id=4558229068513312, integration_id=38, key='APP-123'>, RpcUser(id=92, pk=92, name='', email='admin@localhost', username='admin@localhost', actor_id=None, display_name='admin@localhost', label='admin@localhost', is_superuser=True, is_authenticated=True, is_anonymous=False, is_active=True, is_staff=True, is_unclaimed=False, last_active=datetime.datetime(2026, 5, 30, 21, 45, 19, 878251, tzinfo=datetime.timezone.utc), is_sentry_app=False, password_usable=True, is_password_expired=False, is_suspended=False, roles=frozenset(), permissions=frozenset(), avatar=None, emails=frozenset({'admin@localhost'}), useremails=[RpcUserEmail(id=91, email='admin@localhost', is_verified=True)], authenticators=[]), assign=True, assignment_source=None, lifecycle=<sentry.integrations.utils.metrics.IntegrationEventLifecycle object at 0x7f5efbbf4520>)
tests/sentry/models/test_groupassignee.py::GroupAssigneeTestCase::test_assignee_sync_outbound_unassignlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/models/test_groupassignee.py:288: in test_assignee_sync_outbound_unassign
    mock_sync_assignee_outbound.assert_called_with(
/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/unittest/mock.py:977: in assert_called_with
    raise AssertionError(_error_message()) from cause
E   AssertionError: expected call not found.
E   Expected: sync_assignee_outbound(<ExternalIssue at 0x7f99df528590: id=9, organization_id=4558229069692944, integration_id=45, key='APP-123'>, None, assign=False, assignment_source=None)
E     Actual: sync_assignee_outbound(<ExternalIssue at 0x7f99dcbf7e10: id=9, organization_id=4558229069692944, integration_id=45, key='APP-123'>, None, assign=False, assignment_source=None, lifecycle=<sentry.integrations.utils.metrics.IntegrationEventLifecycle object at 0x7f99df242900>)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants