Skip to content

Conversation

@armenzg
Copy link
Member

@armenzg armenzg commented Dec 5, 2025

For code reviews, we create a GitHub check. In some cases, the customer may request the check to be re-run (e.g. the task failed or timed out).

This handles the GitHub re-run event by scheduling a task which calls Seer with the original run check ID to re-schedule it (it requires https://github.com/getsentry/seer/pull/4173).

Fixes CW-18.

@armenzg armenzg self-assigned this Dec 5, 2025
@linear
Copy link

linear bot commented Dec 5, 2025

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

codecov bot commented Dec 5, 2025

❌ 13 Tests Failed:

Tests completed Failed Passed Skipped
30826 13 30813 247
View the top 3 failed test(s) by shortest run time
tests.sentry.seer.code_review.test_webhook_task.ProcessGitHubWebhookEventTest::test_timeout_error_raises_for_retry
Stack Traces | 1.08s run time
#x1B[1m#x1B[.../seer/code_review/test_webhook_task.py#x1B[0m:234: in test_timeout_error_raises_for_retry
    mock_logger.exception.assert_called_once()
#x1B[1m#x1B[.../hostedtoolcache/Python/3.13.1.../x64/lib/python3.13/unittest/mock.py#x1B[0m:956: in assert_called_once
    raise AssertionError(msg)
#x1B[1m#x1B[31mE   AssertionError: Expected 'exception' to have been called once. Called 0 times.#x1B[0m
tests.sentry.seer.code_review.test_webhook_task.ProcessGitHubWebhookEventTest::test_unexpected_error_logged_and_tracked
Stack Traces | 1.14s run time
#x1B[1m#x1B[.../seer/code_review/test_webhook_task.py#x1B[0m:343: in test_unexpected_error_logged_and_tracked
    mock_logger.exception.assert_called_once()
#x1B[1m#x1B[.../hostedtoolcache/Python/3.13.1.../x64/lib/python3.13/unittest/mock.py#x1B[0m:956: in assert_called_once
    raise AssertionError(msg)
#x1B[1m#x1B[31mE   AssertionError: Expected 'exception' to have been called once. Called 0 times.#x1B[0m
tests.sentry.seer.code_review.test_webhook_task.ProcessGitHubWebhookEventTest::test_server_error_response_raises_for_retry
Stack Traces | 1.17s run time
#x1B[1m#x1B[.../seer/code_review/test_webhook_task.py#x1B[0m:95: in test_server_error_response_raises_for_retry
    mock_logger.exception.assert_called_once()
#x1B[1m#x1B[.../hostedtoolcache/Python/3.13.1.../x64/lib/python3.13/unittest/mock.py#x1B[0m:956: in assert_called_once
    raise AssertionError(msg)
#x1B[1m#x1B[31mE   AssertionError: Expected 'exception' to have been called once. Called 0 times.#x1B[0m
tests.sentry.seer.code_review.test_webhook_task.ProcessGitHubWebhookEventTest::test_ssl_error_raises_for_retry
Stack Traces | 1.19s run time
#x1B[1m#x1B[.../seer/code_review/test_webhook_task.py#x1B[0m:261: in test_ssl_error_raises_for_retry
    mock_logger.exception.assert_called_once()
#x1B[1m#x1B[.../hostedtoolcache/Python/3.13.1.../x64/lib/python3.13/unittest/mock.py#x1B[0m:956: in assert_called_once
    raise AssertionError(msg)
#x1B[1m#x1B[31mE   AssertionError: Expected 'exception' to have been called once. Called 0 times.#x1B[0m
tests.sentry.seer.code_review.test_webhook_task.ProcessGitHubWebhookEventTest::test_new_connection_error_raises_for_retry
Stack Traces | 1.21s run time
#x1B[1m#x1B[.../seer/code_review/test_webhook_task.py#x1B[0m:289: in test_new_connection_error_raises_for_retry
    mock_logger.exception.assert_called_once()
#x1B[1m#x1B[.../hostedtoolcache/Python/3.13.1.../x64/lib/python3.13/unittest/mock.py#x1B[0m:956: in assert_called_once
    raise AssertionError(msg)
#x1B[1m#x1B[31mE   AssertionError: Expected 'exception' to have been called once. Called 0 times.#x1B[0m
tests.sentry.seer.code_review.test_webhook_task.ProcessGitHubWebhookEventTest::test_rate_limit_response_raises_for_retry
Stack Traces | 1.24s run time
#x1B[1m#x1B[.../seer/code_review/test_webhook_task.py#x1B[0m:148: in test_rate_limit_response_raises_for_retry
    mock_logger.exception.assert_called_once()
#x1B[1m#x1B[.../hostedtoolcache/Python/3.13.1.../x64/lib/python3.13/unittest/mock.py#x1B[0m:956: in assert_called_once
    raise AssertionError(msg)
#x1B[1m#x1B[31mE   AssertionError: Expected 'exception' to have been called once. Called 0 times.#x1B[0m
tests.sentry.seer.code_review.test_webhook_task.ProcessGitHubWebhookEventTest::test_service_unavailable_response_raises_for_retry
Stack Traces | 1.26s run time
#x1B[1m#x1B[.../seer/code_review/test_webhook_task.py#x1B[0m:122: in test_service_unavailable_response_raises_for_retry
    mock_logger.exception.assert_called_once()
#x1B[1m#x1B[.../hostedtoolcache/Python/3.13.1.../x64/lib/python3.13/unittest/mock.py#x1B[0m:956: in assert_called_once
    raise AssertionError(msg)
#x1B[1m#x1B[31mE   AssertionError: Expected 'exception' to have been called once. Called 0 times.#x1B[0m
tests.sentry.seer.code_review.test_webhook_task.ProcessGitHubWebhookEventTest::test_network_error_raises_for_retry
Stack Traces | 1.29s run time
#x1B[1m#x1B[.../seer/code_review/test_webhook_task.py#x1B[0m:206: in test_network_error_raises_for_retry
    mock_logger.exception.assert_called_once()
#x1B[1m#x1B[.../hostedtoolcache/Python/3.13.1.../x64/lib/python3.13/unittest/mock.py#x1B[0m:956: in assert_called_once
    raise AssertionError(msg)
#x1B[1m#x1B[31mE   AssertionError: Expected 'exception' to have been called once. Called 0 times.#x1B[0m
tests.sentry.seer.code_review.test_webhooks.CheckRunEventWebhookTest::test_base_case
Stack Traces | 2.25s run time
#x1B[1m#x1B[.../seer/code_review/test_webhooks.py#x1B[0m:42: in test_base_case
    self._send_check_run_event(CHECK_RUN_REREQUESTED_ACTION_EVENT_EXAMPLE)
#x1B[1m#x1B[.../seer/code_review/test_webhooks.py#x1B[0m:34: in _send_check_run_event
    assert response.status_code == 204
#x1B[1m#x1B[31mE   assert 500 == 204#x1B[0m
#x1B[1m#x1B[31mE    +  where 500 = <Response status_code=500, "application/json">.status_code#x1B[0m
tests.sentry.seer.code_review.test_webhooks.CheckRunEventWebhookTest::test_check_run_fails_when_external_id_missing
Stack Traces | 2.26s run time
#x1B[1m#x1B[.../seer/code_review/test_webhooks.py#x1B[0m:89: in test_check_run_fails_when_external_id_missing
    assert "Invalid GitHub check_run event payload" in mock_logger.exception.call_args[0][0]
#x1B[1m#x1B[31mE   AssertionError: assert 'Invalid GitHub check_run event payload' in 'github.webhook.check_run.invalid-payload'#x1B[0m
tests.sentry.seer.code_review.test_webhooks.CheckRunEventWebhookTest::test_check_run_fails_when_external_id_not_numeric
Stack Traces | 2.41s run time
#x1B[1m#x1B[.../seer/code_review/test_webhooks.py#x1B[0m:106: in test_check_run_fails_when_external_id_not_numeric
    assert "external_id must be numeric" in mock_logger.exception.call_args[0][0]
#x1B[1m#x1B[31mE   AssertionError: assert 'external_id must be numeric' in 'github.webhook.check_run.invalid-payload'#x1B[0m
tests.sentry.seer.code_review.test_webhooks.CheckRunEventWebhookTest::test_check_run_fails_when_action_missing
Stack Traces | 2.45s run time
#x1B[1m#x1B[.../seer/code_review/test_webhooks.py#x1B[0m:72: in test_check_run_fails_when_action_missing
    mock_logger.warning.assert_called_once_with("github.webhook.check_run.missing-action")
#x1B[1m#x1B[.../hostedtoolcache/Python/3.13.1.../x64/lib/python3.13/unittest/mock.py#x1B[0m:988: in assert_called_once_with
    raise AssertionError(msg)
#x1B[1m#x1B[31mE   AssertionError: Expected 'warning' to be called once. Called 0 times.#x1B[0m
tests.sentry.seer.code_review.test_webhooks.CheckRunEventWebhookTest::test_check_run_enqueues_task_for_processing
Stack Traces | 2.61s run time
#x1B[1m#x1B[.../seer/code_review/test_webhooks.py#x1B[0m:113: in test_check_run_enqueues_task_for_processing
    self._send_check_run_event(CHECK_RUN_REREQUESTED_ACTION_EVENT_EXAMPLE)
#x1B[1m#x1B[.../seer/code_review/test_webhooks.py#x1B[0m:34: in _send_check_run_event
    assert response.status_code == 204
#x1B[1m#x1B[31mE   assert 500 == 204#x1B[0m
#x1B[1m#x1B[31mE    +  where 500 = <Response status_code=500, "application/json">.status_code#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.

@@ -0,0 +1 @@
# Error prediction module for Seer integration
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe we should call it code_review that is closer to the external name of the feature?

armenzg and others added 5 commits December 12, 2025 13:05
Change the logic to actually handle the webhook payload, extract the info that
is relevant to send to Seer and then send it (to an updated endpoint)
See getsentry/seer#4173 for more details.
@giovanni-guidini giovanni-guidini force-pushed the 12_04/forward_webhook/armenzg branch from 96ef5a7 to 0a1bd89 Compare December 12, 2025 12:43
@giovanni-guidini giovanni-guidini changed the title feat(webhooks): Forward check run events to Seer feat(webhooks): handle check run events for Seer Code Review Dec 12, 2025
@armenzg
Copy link
Member Author

armenzg commented Dec 15, 2025

bugbot review
@sentry review

@armenzg armenzg changed the title feat(webhooks): handle check run events for Seer Code Review feat(webhooks): Forward GitHub re-run check run events for Seer Code Review Dec 15, 2025
status = e.__class__.__name__
metrics.incr(f"{PREFIX}.outcome", tags={"status": f"error_{status}"})
if self.request.retries >= MAX_RETRIES - 1:
logger.exception("%s.error", PREFIX, extra=context)
Copy link
Member

@JoshFerge JoshFerge Dec 17, 2025

Choose a reason for hiding this comment

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

additionally here -- since we use sentry, we'll have the full stacktrace in the issue -- do we really have to log the status?

Copy link
Member Author

Choose a reason for hiding this comment

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

Could you please rephrase this?
status is reported in the finally: metrics.incr(f"{PREFIX}.outcome", tags={"status": status})

Copy link
Member Author

Choose a reason for hiding this comment

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

Does it still apply? I've addressed some of your feedback.

Copy link
Member

@GabeVillalobos GabeVillalobos left a comment

Choose a reason for hiding this comment

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

Changes on the integration side seem reasonable to me. Thanks for running this by us!

Copy link
Member

@JoshFerge JoshFerge left a comment

Choose a reason for hiding this comment

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

seems okay. i feel that the error handling is very over-defensive and will result in a lot of noisy telemetry / makes the code more complicated that it needs to be. And more of a stylistic thing but I also feel that a lot of the comments in this PR feel unnecessary as they just restate what the code is doing.

@armenzg
Copy link
Member Author

armenzg commented Dec 17, 2025

seems okay. i feel that the error handling is very over-defensive and will result in a lot of noisy telemetry / makes the code more complicated that it needs to be. And more of a stylistic thing but I also feel that a lot of the comments in this PR feel unnecessary as they just restate what the code is doing.

I will be addressing both. I changed AGENTS.md to reduce the unnecessary comments.

@JoshFerge
Copy link
Member

seems okay. i feel that the error handling is very over-defensive and will result in a lot of noisy telemetry / makes the code more complicated that it needs to be. And more of a stylistic thing but I also feel that a lot of the comments in this PR feel unnecessary as they just restate what the code is doing.

I will be addressing both. I changed AGENTS.md to reduce the unnecessary comments.

We previously had something about comments in our AGENTS.md and it didn't seem to help -- i think the models are tuned to be extremely verbose


# This needs to match the value defined in the Seer API:
# https://github.com/getsentry/seer/blob/main/src/seer/routes/codegen.py
SEER_PR_REVIEW_RERUN_PATH = "/v1/automation/codegen/pr-review/rerun"
Copy link
Member Author

Choose a reason for hiding this comment

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

@armenzg
Copy link
Member Author

armenzg commented Dec 17, 2025

@seer review

Copy link
Member

@JoshFerge JoshFerge left a comment

Choose a reason for hiding this comment

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

changes lgtm! thank you @armenzg!

@armenzg
Copy link
Member Author

armenzg commented Dec 17, 2025

changes lgtm! thank you @armenzg!

Thank you @JoshFerge for always pressing back and finding bugs!

Copy link
Member

@suejung-sentry suejung-sentry left a comment

Choose a reason for hiding this comment

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

This is great! Added a comment on options to update the "code review eligibility" check logic to match the current state of things as we get ready for GA

"""
Determine if the GitHub check_run event should be handled.
"""
if not features.has("organizations:code-review-beta", organization=organization):
Copy link
Member

@suejung-sentry suejung-sentry Dec 18, 2025

Choose a reason for hiding this comment

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

Since we plan to ship this PR this week, let's use the logic in this check can_use_prevent_ai_features

PLUS

If the org has seat-based-seer-enabled flag on (representing that they've bought the new seat-based seer plan), we should ALSO CHECK whether their repo is enabled using something like below:

        repo_settings = (
            RepositorySettings.objects.select_related("repository")
            .filter(
                repository__external_id=external_repo_id,
                repository__organization_id=sentry_org_id,
                repository__provider=provider, // "integrations:github"
                repository__status=ObjectStatus.ACTIVE,
                enabled_code_review=True,
            )
            .first()
        )

This is the logic I hope to get pulled into an all-in-one helper with the overwatch migration project.

If we prefer instead to tackle this complexity separately and just expose the check-run functionality for the code review beta cohort to start, we can update to check the value of these 4 flags code-review-beta, gen-ai-features, hide_ai_features, enable_pr_review_test_generation (basically what is in can_use_prevent_ai_features but with the additional check that the org is in the code-review-beta cohort).

Copy link
Member Author

Choose a reason for hiding this comment

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

@armenzg armenzg merged commit 276ae9e into master Dec 18, 2025
69 checks passed
@armenzg armenzg deleted the 12_04/forward_webhook/armenzg branch December 18, 2025 12:52
@github-actions github-actions bot locked and limited conversation to collaborators Jan 3, 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.

6 participants