Skip to content

feat(codegen): increment org contributors and assign seat in PR webhook handler#104419

Merged
srest2021 merged 30 commits intomasterfrom
srest2021/ENG-5942
Dec 16, 2025
Merged

feat(codegen): increment org contributors and assign seat in PR webhook handler#104419
srest2021 merged 30 commits intomasterfrom
srest2021/ENG-5942

Conversation

@srest2021
Copy link
Copy Markdown
Member

@srest2021 srest2021 commented Dec 4, 2025

fixes ENG-5935

depends on #104371

Track an active contributor on a PR event webhook, if the repo has Seer and AI features enabled (and the seat-based-seer-enabled feature flag)

  • Increment the contributor's num actions.
  • Only assign a seat to the contributor if it is not a bot or an external contributor.
  • Assign a seat to a contributor on/after the second PR event (not the first)--ticket to optimize this here.
  • Seat assignment occurs in a task for robustness. We log a warning if it fails. We plan to add a retry once we know more about each non-ACCEPTED billing outcome and its frequency.

Extra notes

Info about the user's type (ie, bot or not) and association (ie, external contributor or not) can be obtained from the webhook payload, per the gh docs and gh enterprise docs.

  • payload["pull_request"]["author_association"] is a required field for all pull_request, pull_request_review, and pull_request_review_comment action types, and also in gh enterprise. ✅ -> Added to all gh and gh enterprise fixtures.
  • payload["pull_request"]["user"]["type"] is required for the pull_request.opened and pull_request.closed action types. ✅
  • payload["pull_request"]["user"]["type"] is not required for pull_request.edited, or any pull_request_review or pull_request_review_comment action types. But I set up a gh app and triggered pull_request.edited and pull_request_review.submitted webhooks and the field was indeed present. It's also already present in the fixtures used in the tests. I'm assuming we can expect it for the majority of webhooks, unless the user somehow hasn't been "classified" already (?). If we can't find the user type we just assume the user isn't a bot (feedback welcome on this behavior).

@linear
Copy link
Copy Markdown

linear bot commented Dec 4, 2025

@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Dec 4, 2025
@codecov
Copy link
Copy Markdown

codecov bot commented Dec 4, 2025

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
29283 1 29282 234
View the top 1 failed test(s) by shortest run time
tests.sentry.integrations.github.test_utils.ShouldCreateOrIncrementContributorSeatTest::test_returns_false_when_seat_based_seer_disabled
Stack Traces | 2.5s run time
#x1B[1m#x1B[.../hostedtoolcache/Python/3.13.1........./x64/lib/python3.13/unittest/case.py#x1B[0m:58: in testPartExecutor
    yield
#x1B[1m#x1B[.../hostedtoolcache/Python/3.13.1........./x64/lib/python3.13/unittest/case.py#x1B[0m:651: in run
    self._callTestMethod(testMethod)
#x1B[1m#x1B[.../hostedtoolcache/Python/3.13.1........./x64/lib/python3.13/unittest/case.py#x1B[0m:606: in _callTestMethod
    if method() is not None:
#x1B[1m#x1B[31mE   TypeError: ShouldCreateOrIncrementContributorSeatTest.test_returns_false_when_seat_based_seer_disabled() missing 1 required positional argument: 'mock_quota'#x1B[0m

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@srest2021 srest2021 changed the title feat(codegen): increment org contributors and assign seat upon PR event webhook feat(codegen): increment org contributors and assign seat in PR webhook handler Dec 4, 2025
@srest2021 srest2021 changed the base branch from master to Ajay/5931-webhook-logic-guard December 4, 2025 23:52
@github-actions github-actions bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Dec 4, 2025
@srest2021 srest2021 changed the base branch from Ajay/5931-webhook-logic-guard to master December 4, 2025 23:54
@srest2021 srest2021 removed the Scope: Frontend Automatically applied to PRs that change frontend components label Dec 4, 2025
@srest2021 srest2021 changed the base branch from master to Ajay/5931-webhook-logic-guard December 5, 2025 17:56
@getsentry getsentry deleted a comment from github-actions bot Dec 5, 2025
"outcome": outcome,
},
)
retry_task()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

is this in addition to the 3 retries we get? I'm thinking that might be enough potentially. Where if we fail those 3 retries we could do a reconciliation thing later on (and since it's all in a transaction anyway, num_actions also wouldn't increment)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

By "all being in a transaction" I mean the original task firing along with the num_actions increment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I believe it does count towards the 3 retries. I can increase to 5 retries no prob. What sort of reconciliation were you thinking of doing?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Update after syncing in person: removing retry_task altogether. We'll use the logs to see what kinds of outcomes are common/flaky/worth retrying, and add it in once we have a better idea of which outcomes it's helpful to retry on.

is_active = (
contributor.num_actions >= ORGANIZATION_CONTRIBUTOR_ACTIVATION_THRESHOLD
)
contributor.save(update_fields=["num_actions"])
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: date_updated not updated when incrementing num_actions

The contributor.save(update_fields=["num_actions"]) call won't update the date_updated field even though it has auto_now=True. Django's auto_now behavior doesn't apply when update_fields is specified and the field isn't included in the list. This means the date_updated timestamp will remain stale after num_actions is incremented. There's an index on ["organization_id", "date_updated"] suggesting this field is used for queries, and the reset_num_actions_for_organization_contributors task correctly handles this by explicitly setting date_updated=timezone.now().

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I removed it but just put it back @ajay-sentry, it looks like it's a common pattern to include date_updated in update_fields (removed the manual contributor.date_updated = django_timezone.now() though as it looks like that's not needed)

Examples 1, 2, 3, 4

Copy link
Copy Markdown
Contributor

@ajay-sentry ajay-sentry left a comment

Choose a reason for hiding this comment

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

lgtm, @brendanhsentry that's the right flag, right?

@srest2021 srest2021 merged commit 96bee23 into master Dec 16, 2025
67 checks passed
@srest2021 srest2021 deleted the srest2021/ENG-5942 branch December 16, 2025 17:49
@github-actions github-actions bot locked and limited conversation to collaborators Jan 1, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants