Skip to content

Conversation

@rnetser
Copy link
Collaborator

@rnetser rnetser commented Dec 29, 2025

Summary by CodeRabbit

  • New Features

    • Global and per-repository option to optionally re-run CI checks for PRs when the base branch is pushed.
    • PR processing now waits ~30s to improve merge-state accuracy before labeling and optional retriggering.
  • Behavior

    • Labeling now can also trigger configured retests when appropriate; retest execution consolidated through a central runner.
  • Tests

    • Expanded tests covering labeling, conditional retriggering, merge-state scenarios, and error cases.

✏️ Tip: You can customize this high-level summary in your review settings.

…dated

Implements automatic re-triggering of GitHub check suites when a PR's base
branch receives new commits, helping keep CI results current and preventing
merges of stale PRs with outdated test results.

Key changes:
- Add 'retrigger-checks-on-base-push' config option (default: true) in schema.yaml
- Implement clean separation of concerns in pull_request_handler.py:
  * label_pull_request_by_merge_state() - ONLY handles PR labeling
  * _retrigger_check_suites_for_pr() - handles check suite re-requesting
  * retrigger_checks_for_out_of_date_prs_on_push() - coordinates labeling and check triggering
- Update push_handler.py to delegate PR processing to PullRequestHandler
- Add retrigger_checks_on_base_push attribute to GithubWebhook in github_api.py
- Add comprehensive tests verifying the separated design and behavior

The implementation checks each open PR targeting the updated branch and
re-triggers check suites only for PRs with merge_state="behind", ensuring
CI validation against the latest base branch commits.
@coderabbitai
Copy link

coderabbitai bot commented Dec 29, 2025

Walkthrough

Adds a config-driven opt-in to re-trigger configured CI checks for open pull requests when their base branch is pushed. New config keys, a GithubWebhook attribute, a RunnerHandler entrypoint, and pull-request labeling flow changes implement conditional retriggering.

Changes

Cohort / File(s) Summary
Configuration
webhook_server/config/schema.yaml
Added top-level and per-repository boolean retrigger-checks-on-base-push (default: false).
GitHub API
webhook_server/libs/github_api.py
Added retrigger_checks_on_base_push attribute on GithubWebhook, populated from repo config (default False).
Issue comment handling
webhook_server/libs/handlers/issue_comment_handler.py
Removed local per-test mapping and manual asyncio.gather; now delegates retest orchestration to RunnerHandler.run_retests() and removed unused imports.
Pull request handling
webhook_server/libs/handlers/pull_request_handler.py
Replaced labeling-only flow with label_and_rerun_checks_all_opened_pull_requests_merge_state_after_merged() (adds 30s wait). label_pull_request_by_merge_state() now returns merge state string; added _retrigger_check_suites_for_pr() to conditionally call RunnerHandler when repo config permits and PR is behind/blocked.
Retest orchestration
webhook_server/libs/handlers/runner_handler.py
Added run_retests(supported_retests: list[str], pull_request: PullRequest) to map retest names to runner methods, spawn concurrent tasks, gather results, and log errors; added typing imports.
Tests & constants
webhook_server/tests/test_pull_request_handler.py, webhook_server/utils/constants
Renamed/updated tests to exercise renamed labeling method and retrigger behavior; added PRE_COMMIT_STR constant and test shim for asyncio.to_thread; added coverage for retrigger error branches.

Sequence Diagram

sequenceDiagram
    participant Webhook as Webhook Receiver
    participant PRH as PullRequestHandler
    participant GHA as GitHub API
    participant RH as RunnerHandler
    participant CI as CI/Check Suites

    rect rgb(200,220,255)
    note over Webhook,PRH: Base-branch push event
    Webhook->>PRH: push event
    end

    PRH->>GHA: list open PRs
    GHA-->>PRH: open PRs

    rect rgb(255,240,200)
    loop for each open PR
        PRH->>GHA: fetch PR details (mergeable_state)
        GHA-->>PRH: mergeable_state
        PRH->>PRH: label PR by merge state
    end
    end

    rect rgb(220,255,220)
    alt retrigger enabled && PR behind/blocked
        PRH->>RH: run_retests(configured_tests, pull_request)
        RH->>RH: map test names -> runner methods
        par Concurrent retests
            RH->>CI: spawn retest task 1
            RH->>CI: spawn retest task 2
            RH->>CI: spawn retest task N
        end
        CI-->>RH: results / errors
        RH-->>PRH: completion / logs
    else retrigger disabled or not applicable
        PRH->>PRH: skip retrigger
    end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.50% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main feature: auto re-running GitHub check runs on open PRs after a merge to the base branch, with the opt-in aspect clearly stated.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch re-trigger-pr-not-rebased

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1746abf and 084e88c.

📒 Files selected for processing (1)
  • webhook_server/tests/test_pull_request_handler.py
🧰 Additional context used
📓 Path-based instructions (3)
webhook_server/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

webhook_server/**/*.py: Never use defensive checks (hasattr, if object:, if value is not None) on required parameters passed to __init__() - required parameters are always provided in this self-contained server application
Defensive checks ARE acceptable in destructors (__del__) because they may be called during failed initialization
Defensive checks ARE acceptable for lazy initialization where attributes explicitly start as None - check is legitimate for uninitialized attributes
Never use defensive checks on known library versions controlled in pyproject.toml - e.g., PyGithub >=2.4.0 methods are guaranteed to exist
Never use defensive checks on webhook payload fields guaranteed by GitHub webhook specification - e.g., user.node_id, user.type, sender always exist in webhook payloads
Never use hasattr() for type discrimination - use isinstance() instead for type checking
Never return fake default values ('', 0, False, None objects, []) to hide missing data - raise exceptions with clear error messages instead to enable fail-fast debugging
ALL PyGithub method calls MUST be wrapped with asyncio.to_thread() to avoid blocking the FastAPI event loop - including .get_*(), .create_*(), .edit(), .add_to_*(), .remove_from_*()
ALL PyGithub property accesses that may trigger API calls MUST be wrapped with asyncio.to_thread() - properties like .draft, .mergeable, .state, .committer, .permissions, .labels, .assignees are NOT safe to access directly
PyGithub PaginatedList iteration MUST be wrapped in asyncio.to_thread() with list conversion - never iterate directly to avoid blocking the event loop
ALL imports must be at the top of files - no imports in the middle of functions or try/except blocks except for TYPE_CHECKING conditional imports
ALL functions must have complete type hints compatible with mypy strict mode - parameter types, return types, and complex object types must be explicitly annotated
Code coverage of 90% or higher is ...

Files:

  • webhook_server/tests/test_pull_request_handler.py
webhook_server/**/*.{py,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Defensive checks ARE acceptable for optional parameters explicitly typed as Type | None - check is legitimate for parameters allowing None

Files:

  • webhook_server/tests/test_pull_request_handler.py
webhook_server/tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Test files MUST use TEST_GITHUB_TOKEN = 'ghp_test1234...' with # pragma: allowlist secret comment to avoid security warnings in test tokens

Files:

  • webhook_server/tests/test_pull_request_handler.py
🧠 Learnings (11)
📚 Learning: 2024-10-29T10:42:50.163Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 612
File: webhook_server_container/libs/github_api.py:925-926
Timestamp: 2024-10-29T10:42:50.163Z
Learning: In `webhook_server_container/libs/github_api.py`, the method `self._keep_approved_by_approvers_after_rebase()` must be called after removing labels when synchronizing a pull request. Therefore, it should be placed outside the `ThreadPoolExecutor` to ensure it runs sequentially after label removal.

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2024-10-29T08:09:57.157Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 612
File: webhook_server_container/libs/github_api.py:2089-2100
Timestamp: 2024-10-29T08:09:57.157Z
Learning: In `webhook_server_container/libs/github_api.py`, when the function `_keep_approved_by_approvers_after_rebase` is called, existing approval labels have already been cleared after pushing new changes, so there's no need to check for existing approvals within this function.

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/**/*.py : ALL PyGithub property accesses that may trigger API calls MUST be wrapped with `asyncio.to_thread()` - properties like `.draft`, `.mergeable`, `.state`, `.committer`, `.permissions`, `.labels`, `.assignees` are NOT safe to access directly

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2024-10-08T09:19:56.185Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 586
File: webhook_server_container/libs/github_api.py:1947-1956
Timestamp: 2024-10-08T09:19:56.185Z
Learning: In `webhook_server_container/libs/github_api.py`, the indentation style used in the `set_pull_request_automerge` method is acceptable as per the project's coding standards.

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/libs/**/*.py : Eliminate unnecessary defensive checks for return type changes and method signature modifications in internal APIs - fail-fast principle is preferred over compatibility

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/**/*.py : ALL PyGithub method calls MUST be wrapped with `asyncio.to_thread()` to avoid blocking the FastAPI event loop - including `.get_*()`, `.create_*()`, `.edit()`, `.add_to_*()`, `.remove_from_*()`

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-05-13T12:06:27.297Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 778
File: webhook_server/libs/pull_request_handler.py:327-330
Timestamp: 2025-05-13T12:06:27.297Z
Learning: In the GitHub webhook server, synchronous GitHub API calls (like create_issue_comment, add_to_assignees, etc.) in async methods should be awaited using asyncio.to_thread or loop.run_in_executor to prevent blocking the event loop.

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/**/*.py : PyGithub PaginatedList iteration MUST be wrapped in `asyncio.to_thread()` with list conversion - never iterate directly to avoid blocking the event loop

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/**/*.py : ALL functions must have complete type hints compatible with mypy strict mode - parameter types, return types, and complex object types must be explicitly annotated

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-10-28T13:04:00.466Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 878
File: webhook_server/libs/handlers/runner_handler.py:491-571
Timestamp: 2025-10-28T13:04:00.466Z
Learning: In webhook_server/libs/handlers/runner_handler.py, the run_build_container method is designed with the pattern that push=True is always called with set_check=False in production code, so no check-run status needs to be finalized after push operations.

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-12-29T13:09:56.231Z
Learnt from: rnetser
Repo: myk-org/github-webhook-server PR: 959
File: webhook_server/libs/handlers/pull_request_handler.py:887-887
Timestamp: 2025-12-29T13:09:56.231Z
Learning: In the myk-org/github-webhook-server repository, logging statements in the webhook_server codebase should use f-strings for interpolation. Do not suggest changing to lazy formatting with % (e.g., logger.debug('msg %s', var)) since that is an established style choice. When adding new log statements, prefer f"...{var}..." for readability and performance, and avoid string concatenation or format-style logging unless the project explicitly adopts a different convention.

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
🪛 Ruff (0.14.10)
webhook_server/tests/test_pull_request_handler.py

32-32: Dynamically typed expressions (typing.Any) are disallowed in *args

(ANN401)


32-32: Dynamically typed expressions (typing.Any) are disallowed in **kwargs

(ANN401)


472-472: Wrong type passed to first argument of pytest.mark.parametrize; expected tuple

Use a tuple for the first argument

(PT006)


487-487: Boolean-typed positional argument in function definition

(FBT001)

🔇 Additional comments (1)
webhook_server/tests/test_pull_request_handler.py (1)

30-34: LGTM! Excellent test coverage for the retrigger feature.

The test additions properly cover the new opt-in retrigger functionality:

  • Lines 30-34: The _sync_to_thread helper correctly provides an async shim for test mocking (all past review issues addressed ✓)
  • Lines 415-468: Tests verify both disabled and enabled retrigger scenarios with proper isolation
  • Lines 470-515: Parametrized test comprehensively covers all merge states (behind, blocked, clean, dirty, unstable, unknown) with correct retrigger expectations
  • Lines 1876-1945: New tests verify separation of concerns (labeling-only behavior) and the internal _retrigger_check_suites_for_pr method with success, empty config, and exception cases

All tests consistently use _sync_to_thread for patching asyncio.to_thread, maintaining fast synchronous execution while preserving async semantics. Type hints are complete per mypy strict mode requirements.

Static analysis notes: The Ruff hints at lines 32 (Any in type hints), 472 (parametrize format), and 487 (boolean param) are acceptable for test code patterns and can be safely ignored.

Also applies to: 415-515, 1648-1648, 1694-1694, 1711-1711, 1822-1822, 1836-1836, 1876-1945


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@myakove-bot
Copy link
Collaborator

Report bugs in Issues

Welcome! 🎉

This pull request will be automatically processed with the following features:

🔄 Automatic Actions

  • Reviewer Assignment: Reviewers are automatically assigned based on the OWNERS file in the repository root
  • Size Labeling: PR size labels (XS, S, M, L, XL, XXL) are automatically applied based on changes
  • Issue Creation: A tracking issue is created for this PR and will be closed when the PR is merged or closed
  • Pre-commit Checks: pre-commit runs automatically if .pre-commit-config.yaml exists
  • Branch Labeling: Branch-specific labels are applied to track the target branch
  • Auto-verification: Auto-verified users have their PRs automatically marked as verified

📋 Available Commands

PR Status Management

  • /wip - Mark PR as work in progress (adds WIP: prefix to title)
  • /wip cancel - Remove work in progress status
  • /hold - Block PR merging (approvers only)
  • /hold cancel - Unblock PR merging
  • /verified - Mark PR as verified
  • /verified cancel - Remove verification status
  • /reprocess - Trigger complete PR workflow reprocessing (useful if webhook failed or configuration changed)

Review & Approval

  • /lgtm - Approve changes (looks good to me)
  • /approve - Approve PR (approvers only)
  • /automerge - Enable automatic merging when all requirements are met (maintainers and approvers only)
  • /assign-reviewers - Assign reviewers based on OWNERS file
  • /assign-reviewer @username - Assign specific reviewer
  • /check-can-merge - Check if PR meets merge requirements

Testing & Validation

  • /retest tox - Run Python test suite with tox
  • /retest build-container - Rebuild and test container image
  • /retest python-module-install - Test Python package installation
  • /retest pre-commit - Run pre-commit hooks and checks
  • /retest conventional-title - Validate commit message format
  • /retest all - Run all available tests

Container Operations

  • /build-and-push-container - Build and push container image (tagged with PR number)
    • Supports additional build arguments: /build-and-push-container --build-arg KEY=value

Cherry-pick Operations

  • /cherry-pick <branch> - Schedule cherry-pick to target branch when PR is merged
    • Multiple branches: /cherry-pick branch1 branch2 branch3

Label Management

  • /<label-name> - Add a label to the PR
  • /<label-name> cancel - Remove a label from the PR

✅ Merge Requirements

This PR will be automatically approved when the following conditions are met:

  1. Approval: /approve from at least one approver
  2. LGTM Count: Minimum 1 /lgtm from reviewers
  3. Status Checks: All required status checks must pass
  4. No Blockers: No WIP, hold, or conflict labels
  5. Verified: PR must be marked as verified (if verification is enabled)

📊 Review Process

Approvers and Reviewers

Approvers:

  • myakove
  • rnetser

Reviewers:

  • myakove
  • rnetser
Available Labels
  • hold
  • verified
  • wip
  • lgtm
  • approve
  • automerge

💡 Tips

  • WIP Status: Use /wip when your PR is not ready for review
  • Verification: The verified label is automatically removed on each new commit
  • Cherry-picking: Cherry-pick labels are processed when the PR is merged
  • Container Builds: Container images are automatically tagged with the PR number
  • Permission Levels: Some commands require approver permissions
  • Auto-verified Users: Certain users have automatic verification and merge privileges

For more information, please refer to the project documentation or contact the maintainers.

@rnetser
Copy link
Collaborator Author

rnetser commented Dec 29, 2025

/build-and-push-container

@myakove-bot
Copy link
Collaborator

New container for ghcr.io/myk-org/github-webhook-server:pr-959 published

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 20aabd2 and 3a8072e.

📒 Files selected for processing (6)
  • webhook_server/config/schema.yaml
  • webhook_server/libs/github_api.py
  • webhook_server/libs/handlers/issue_comment_handler.py
  • webhook_server/libs/handlers/pull_request_handler.py
  • webhook_server/libs/handlers/runner_handler.py
  • webhook_server/tests/test_pull_request_handler.py
🧰 Additional context used
📓 Path-based instructions (6)
webhook_server/libs/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

webhook_server/libs/**/*.py: Internal methods in webhook_server/libs/ can change freely without backward compatibility requirements - return types, method signatures, and implementations may be modified without deprecation warnings
Eliminate unnecessary defensive checks for return type changes and method signature modifications in internal APIs - fail-fast principle is preferred over compatibility

Files:

  • webhook_server/libs/handlers/runner_handler.py
  • webhook_server/libs/github_api.py
  • webhook_server/libs/handlers/issue_comment_handler.py
  • webhook_server/libs/handlers/pull_request_handler.py
webhook_server/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

webhook_server/**/*.py: Never use defensive checks (hasattr, if object:, if value is not None) on required parameters passed to __init__() - required parameters are always provided in this self-contained server application
Defensive checks ARE acceptable in destructors (__del__) because they may be called during failed initialization
Defensive checks ARE acceptable for lazy initialization where attributes explicitly start as None - check is legitimate for uninitialized attributes
Never use defensive checks on known library versions controlled in pyproject.toml - e.g., PyGithub >=2.4.0 methods are guaranteed to exist
Never use defensive checks on webhook payload fields guaranteed by GitHub webhook specification - e.g., user.node_id, user.type, sender always exist in webhook payloads
Never use hasattr() for type discrimination - use isinstance() instead for type checking
Never return fake default values ('', 0, False, None objects, []) to hide missing data - raise exceptions with clear error messages instead to enable fail-fast debugging
ALL PyGithub method calls MUST be wrapped with asyncio.to_thread() to avoid blocking the FastAPI event loop - including .get_*(), .create_*(), .edit(), .add_to_*(), .remove_from_*()
ALL PyGithub property accesses that may trigger API calls MUST be wrapped with asyncio.to_thread() - properties like .draft, .mergeable, .state, .committer, .permissions, .labels, .assignees are NOT safe to access directly
PyGithub PaginatedList iteration MUST be wrapped in asyncio.to_thread() with list conversion - never iterate directly to avoid blocking the event loop
ALL imports must be at the top of files - no imports in the middle of functions or try/except blocks except for TYPE_CHECKING conditional imports
ALL functions must have complete type hints compatible with mypy strict mode - parameter types, return types, and complex object types must be explicitly annotated
Code coverage of 90% or higher is ...

Files:

  • webhook_server/libs/handlers/runner_handler.py
  • webhook_server/libs/github_api.py
  • webhook_server/libs/handlers/issue_comment_handler.py
  • webhook_server/tests/test_pull_request_handler.py
  • webhook_server/libs/handlers/pull_request_handler.py
webhook_server/**/*.{py,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Defensive checks ARE acceptable for optional parameters explicitly typed as Type | None - check is legitimate for parameters allowing None

Files:

  • webhook_server/libs/handlers/runner_handler.py
  • webhook_server/libs/github_api.py
  • webhook_server/libs/handlers/issue_comment_handler.py
  • webhook_server/tests/test_pull_request_handler.py
  • webhook_server/libs/handlers/pull_request_handler.py
webhook_server/libs/handlers/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

webhook_server/libs/handlers/**/*.py: Architecture guarantee: repository_data is ALWAYS set before handlers instantiate in GithubWebhook.process() with fail-fast exceptions - no defensive checks needed
Use await asyncio.gather(*tasks, return_exceptions=True) for concurrent non-blocking PyGithub operations to enable parallel processing of multiple GitHub API calls
Use structured logging with contextual parameters via get_logger_with_params() including repository, hook_id, and component-specific identifiers for webhook correlation
Configuration access via Config(repository='org/repo-name') - repository parameter is required for per-repository overrides via .github-webhook-server.yaml
Handler pattern: implement __init__(self, github_webhook: GithubWebhook, ...) and process_event(event_data: dict) -> None for all GitHub event handlers
Use self.github_webhook.unified_api for all GitHub API operations in handlers - never access GitHub API directly

Files:

  • webhook_server/libs/handlers/runner_handler.py
  • webhook_server/libs/handlers/issue_comment_handler.py
  • webhook_server/libs/handlers/pull_request_handler.py
webhook_server/config/schema.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

Configuration schema must be defined in webhook_server/config/schema.yaml with validation logic in webhook_server/libs/config.py

Files:

  • webhook_server/config/schema.yaml
webhook_server/tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Test files MUST use TEST_GITHUB_TOKEN = 'ghp_test1234...' with # pragma: allowlist secret comment to avoid security warnings in test tokens

Files:

  • webhook_server/tests/test_pull_request_handler.py
🧠 Learnings (16)
📓 Common learnings
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/libs/handlers/*check_run*.py : Repository cloning for check_run webhook events MUST be optimized by skipping clone when action != 'completed' or when check name is 'can-be-merged' with non-success conclusion
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to {config.yaml,.github-webhook-server.yaml} : Maintain backward compatibility ONLY for user-facing configuration files (`config.yaml`, `.github-webhook-server.yaml`) - configuration schema changes must support old formats or provide migration paths

Applied to files:

  • webhook_server/config/schema.yaml
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/libs/handlers/**/*.py : Configuration access via `Config(repository='org/repo-name')` - repository parameter is required for per-repository overrides via `.github-webhook-server.yaml`

Applied to files:

  • webhook_server/config/schema.yaml
  • webhook_server/libs/github_api.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/config/schema.yaml : Configuration schema must be defined in `webhook_server/config/schema.yaml` with validation logic in `webhook_server/libs/config.py`

Applied to files:

  • webhook_server/config/schema.yaml
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Maintain backward compatibility for webhook payload handling - must follow GitHub webhook specification to ensure compatibility with GitHub API changes

Applied to files:

  • webhook_server/config/schema.yaml
📚 Learning: 2025-02-25T12:01:42.999Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 666
File: webhook_server_container/libs/github_api.py:2254-2255
Timestamp: 2025-02-25T12:01:42.999Z
Learning: In the ProcessGithubWehook class, the `self.conventional_title` attribute is set during initialization by the `_repo_data_from_config()` method, and doesn't need additional existence checks.

Applied to files:

  • webhook_server/libs/github_api.py
📚 Learning: 2024-10-29T08:09:57.157Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 612
File: webhook_server_container/libs/github_api.py:2089-2100
Timestamp: 2024-10-29T08:09:57.157Z
Learning: In `webhook_server_container/libs/github_api.py`, when the function `_keep_approved_by_approvers_after_rebase` is called, existing approval labels have already been cleared after pushing new changes, so there's no need to check for existing approvals within this function.

Applied to files:

  • webhook_server/libs/github_api.py
  • webhook_server/tests/test_pull_request_handler.py
  • webhook_server/libs/handlers/pull_request_handler.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/libs/handlers/**/*.py : Architecture guarantee: `repository_data` is ALWAYS set before handlers instantiate in `GithubWebhook.process()` with fail-fast exceptions - no defensive checks needed

Applied to files:

  • webhook_server/libs/github_api.py
📚 Learning: 2024-10-09T09:16:45.452Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 579
File: webhook_server_container/libs/github_api.py:1098-1101
Timestamp: 2024-10-09T09:16:45.452Z
Learning: In the Python method `_run_tox` within `webhook_server_container/libs/github_api.py`, the variable `_tox_tests` is already comma-separated, so removing spaces with `_tox_tests.replace(" ", "")` is appropriate to handle any accidental spaces when specifying Tox environments.

Applied to files:

  • webhook_server/libs/handlers/issue_comment_handler.py
📚 Learning: 2024-10-15T10:37:45.791Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 598
File: webhook_server_container/libs/github_api.py:1860-1874
Timestamp: 2024-10-15T10:37:45.791Z
Learning: In the `process_retest_command` method in `webhook_server_container/libs/github_api.py`, `_target_tests` is defined before use.

Applied to files:

  • webhook_server/libs/handlers/issue_comment_handler.py
📚 Learning: 2024-10-29T10:42:50.163Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 612
File: webhook_server_container/libs/github_api.py:925-926
Timestamp: 2024-10-29T10:42:50.163Z
Learning: In `webhook_server_container/libs/github_api.py`, the method `self._keep_approved_by_approvers_after_rebase()` must be called after removing labels when synchronizing a pull request. Therefore, it should be placed outside the `ThreadPoolExecutor` to ensure it runs sequentially after label removal.

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
  • webhook_server/libs/handlers/pull_request_handler.py
📚 Learning: 2024-10-08T09:19:56.185Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 586
File: webhook_server_container/libs/github_api.py:1947-1956
Timestamp: 2024-10-08T09:19:56.185Z
Learning: In `webhook_server_container/libs/github_api.py`, the indentation style used in the `set_pull_request_automerge` method is acceptable as per the project's coding standards.

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
  • webhook_server/libs/handlers/pull_request_handler.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/libs/**/*.py : Eliminate unnecessary defensive checks for return type changes and method signature modifications in internal APIs - fail-fast principle is preferred over compatibility

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-10-28T13:04:00.466Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 878
File: webhook_server/libs/handlers/runner_handler.py:491-571
Timestamp: 2025-10-28T13:04:00.466Z
Learning: In webhook_server/libs/handlers/runner_handler.py, the run_build_container method is designed with the pattern that push=True is always called with set_check=False in production code, so no check-run status needs to be finalized after push operations.

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/**/*.py : ALL PyGithub property accesses that may trigger API calls MUST be wrapped with `asyncio.to_thread()` - properties like `.draft`, `.mergeable`, `.state`, `.committer`, `.permissions`, `.labels`, `.assignees` are NOT safe to access directly

Applied to files:

  • webhook_server/libs/handlers/pull_request_handler.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/libs/handlers/*check_run*.py : Repository cloning for check_run webhook events MUST be optimized by skipping clone when action != 'completed' or when check name is 'can-be-merged' with non-success conclusion

Applied to files:

  • webhook_server/libs/handlers/pull_request_handler.py
🧬 Code graph analysis (4)
webhook_server/libs/github_api.py (1)
webhook_server/libs/config.py (1)
  • get_value (99-120)
webhook_server/libs/handlers/issue_comment_handler.py (2)
webhook_server/libs/handlers/runner_handler.py (1)
  • run_retests (747-776)
webhook_server/tests/conftest.py (1)
  • pull_request (106-107)
webhook_server/tests/test_pull_request_handler.py (2)
webhook_server/libs/handlers/pull_request_handler.py (3)
  • label_and_rerun_checks_all_opened_pull_requests_merge_state_after_merged (410-437)
  • label_pull_request_by_merge_state (880-901)
  • _retrigger_check_suites_for_pr (903-925)
webhook_server/libs/handlers/runner_handler.py (1)
  • run_retests (747-776)
webhook_server/libs/handlers/pull_request_handler.py (4)
webhook_server/tests/conftest.py (3)
  • pull_request (106-107)
  • github_webhook (111-131)
  • PullRequest (90-102)
webhook_server/utils/helpers.py (1)
  • format_task_fields (135-154)
webhook_server/tests/test_runner_handler.py (1)
  • runner_handler (48-50)
webhook_server/libs/handlers/runner_handler.py (1)
  • run_retests (747-776)
🪛 Ruff (0.14.10)
webhook_server/libs/handlers/runner_handler.py

755-755: Logging statement uses f-string

(G004)


769-769: Logging statement uses f-string

(G004)


776-776: Logging statement uses f-string

(G004)

webhook_server/tests/test_pull_request_handler.py

441-441: Missing return type annotation for private function mock_label_side_effect

(ANN202)


463-463: Wrong type passed to first argument of pytest.mark.parametrize; expected tuple

Use a tuple for the first argument

(PT006)


478-478: Boolean-typed positional argument in function definition

(FBT001)

webhook_server/libs/handlers/pull_request_handler.py

887-887: Logging statement uses f-string

(G004)


919-919: Logging statement uses f-string

(G004)


922-922: Logging statement uses f-string

(G004)

🔇 Additional comments (3)
webhook_server/libs/github_api.py (1)

711-714: LOW: New retrigger_checks_on_base_push attribute is correctly sourced and typed

Using Config.get_value("retrigger-checks-on-base-push", return_on_none=False, extra_dict=repository_config) respects the expected precedence: local .github-webhook-server.yaml → repo-specific config → root config → default False. The explicit bool annotation and wiring into GithubWebhook match how other feature flags are handled, and it lines up with the schema addition.

No changes needed here.

As per coding guidelines, this follows the config/schema pattern without extra defensive checks.

webhook_server/libs/handlers/issue_comment_handler.py (1)

5-6: LOW: Retest handling nicely centralized via RunnerHandler.run_retests

Typing tasks as list[Coroutine[Any, Any, Any] | Task[Any]] and delegating /retest execution to runner_handler.run_retests(...) removes duplicate mapping/gather logic from this handler and keeps all CI execution paths in RunnerHandler. This also aligns issue_comment-initiated retests with the new “retrigger on base push” flow.

No functional issues spotted here.

Also applies to: 106-137, 449-451

webhook_server/libs/handlers/pull_request_handler.py (1)

167-173: LOW: Merge‑state labeling and retrigger flow are well factored and align with the new config flag

The new flow:

  • On closed+merged, process_pull_request_webhook_data calls
    label_and_rerun_checks_all_opened_pull_requests_merge_state_after_merged().
  • That method:
    • Waits 30s (non‑blocking asyncio.sleep) to let GitHub compute mergeable_state.
    • Fetches open PRs via await asyncio.to_thread(self.repository.get_pulls, state="open").
    • Calls label_pull_request_by_merge_state for each PR and uses its returned merge_state.
    • If github_webhook.retrigger_checks_on_base_push is True and the state is "behind" or "blocked", delegates to _retrigger_check_suites_for_pr.

label_pull_request_by_merge_state is now a pure “labeling + state” helper: it wraps the mergeable_state property in asyncio.to_thread, updates only the NEEDS_REBASE / HAS_CONFLICTS labels, and returns the state string (early‑returning on "unknown"). Tests also assert that this method does not itself trigger checks, keeping separation of concerns clear.

_retrigger_check_suites_for_pr correctly:

  • Logs via logger.step with structured task fields.
  • Uses github_webhook.current_pull_request_supported_retest as the single source of truth for which checks can run.
  • No‑ops (with a debug log) when no checks are configured.
  • Delegates execution to runner_handler.run_retests, reusing the shared mapping and error handling there.

Overall, this matches the intended “opt‑in retrigger after merge” behavior and respects the async + PyGithub access guidelines.

Also applies to: 410-438, 880-902, 903-925

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3a8072e and 42968da.

📒 Files selected for processing (1)
  • webhook_server/libs/handlers/pull_request_handler.py
🧰 Additional context used
📓 Path-based instructions (4)
webhook_server/libs/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

webhook_server/libs/**/*.py: Internal methods in webhook_server/libs/ can change freely without backward compatibility requirements - return types, method signatures, and implementations may be modified without deprecation warnings
Eliminate unnecessary defensive checks for return type changes and method signature modifications in internal APIs - fail-fast principle is preferred over compatibility

Files:

  • webhook_server/libs/handlers/pull_request_handler.py
webhook_server/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

webhook_server/**/*.py: Never use defensive checks (hasattr, if object:, if value is not None) on required parameters passed to __init__() - required parameters are always provided in this self-contained server application
Defensive checks ARE acceptable in destructors (__del__) because they may be called during failed initialization
Defensive checks ARE acceptable for lazy initialization where attributes explicitly start as None - check is legitimate for uninitialized attributes
Never use defensive checks on known library versions controlled in pyproject.toml - e.g., PyGithub >=2.4.0 methods are guaranteed to exist
Never use defensive checks on webhook payload fields guaranteed by GitHub webhook specification - e.g., user.node_id, user.type, sender always exist in webhook payloads
Never use hasattr() for type discrimination - use isinstance() instead for type checking
Never return fake default values ('', 0, False, None objects, []) to hide missing data - raise exceptions with clear error messages instead to enable fail-fast debugging
ALL PyGithub method calls MUST be wrapped with asyncio.to_thread() to avoid blocking the FastAPI event loop - including .get_*(), .create_*(), .edit(), .add_to_*(), .remove_from_*()
ALL PyGithub property accesses that may trigger API calls MUST be wrapped with asyncio.to_thread() - properties like .draft, .mergeable, .state, .committer, .permissions, .labels, .assignees are NOT safe to access directly
PyGithub PaginatedList iteration MUST be wrapped in asyncio.to_thread() with list conversion - never iterate directly to avoid blocking the event loop
ALL imports must be at the top of files - no imports in the middle of functions or try/except blocks except for TYPE_CHECKING conditional imports
ALL functions must have complete type hints compatible with mypy strict mode - parameter types, return types, and complex object types must be explicitly annotated
Code coverage of 90% or higher is ...

Files:

  • webhook_server/libs/handlers/pull_request_handler.py
webhook_server/**/*.{py,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Defensive checks ARE acceptable for optional parameters explicitly typed as Type | None - check is legitimate for parameters allowing None

Files:

  • webhook_server/libs/handlers/pull_request_handler.py
webhook_server/libs/handlers/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

webhook_server/libs/handlers/**/*.py: Architecture guarantee: repository_data is ALWAYS set before handlers instantiate in GithubWebhook.process() with fail-fast exceptions - no defensive checks needed
Use await asyncio.gather(*tasks, return_exceptions=True) for concurrent non-blocking PyGithub operations to enable parallel processing of multiple GitHub API calls
Use structured logging with contextual parameters via get_logger_with_params() including repository, hook_id, and component-specific identifiers for webhook correlation
Configuration access via Config(repository='org/repo-name') - repository parameter is required for per-repository overrides via .github-webhook-server.yaml
Handler pattern: implement __init__(self, github_webhook: GithubWebhook, ...) and process_event(event_data: dict) -> None for all GitHub event handlers
Use self.github_webhook.unified_api for all GitHub API operations in handlers - never access GitHub API directly

Files:

  • webhook_server/libs/handlers/pull_request_handler.py
🧠 Learnings (5)
📚 Learning: 2024-10-29T10:42:50.163Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 612
File: webhook_server_container/libs/github_api.py:925-926
Timestamp: 2024-10-29T10:42:50.163Z
Learning: In `webhook_server_container/libs/github_api.py`, the method `self._keep_approved_by_approvers_after_rebase()` must be called after removing labels when synchronizing a pull request. Therefore, it should be placed outside the `ThreadPoolExecutor` to ensure it runs sequentially after label removal.

Applied to files:

  • webhook_server/libs/handlers/pull_request_handler.py
📚 Learning: 2024-10-29T08:09:57.157Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 612
File: webhook_server_container/libs/github_api.py:2089-2100
Timestamp: 2024-10-29T08:09:57.157Z
Learning: In `webhook_server_container/libs/github_api.py`, when the function `_keep_approved_by_approvers_after_rebase` is called, existing approval labels have already been cleared after pushing new changes, so there's no need to check for existing approvals within this function.

Applied to files:

  • webhook_server/libs/handlers/pull_request_handler.py
📚 Learning: 2024-10-08T09:19:56.185Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 586
File: webhook_server_container/libs/github_api.py:1947-1956
Timestamp: 2024-10-08T09:19:56.185Z
Learning: In `webhook_server_container/libs/github_api.py`, the indentation style used in the `set_pull_request_automerge` method is acceptable as per the project's coding standards.

Applied to files:

  • webhook_server/libs/handlers/pull_request_handler.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/**/*.py : ALL PyGithub property accesses that may trigger API calls MUST be wrapped with `asyncio.to_thread()` - properties like `.draft`, `.mergeable`, `.state`, `.committer`, `.permissions`, `.labels`, `.assignees` are NOT safe to access directly

Applied to files:

  • webhook_server/libs/handlers/pull_request_handler.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/libs/handlers/*check_run*.py : Repository cloning for check_run webhook events MUST be optimized by skipping clone when action != 'completed' or when check name is 'can-be-merged' with non-success conclusion

Applied to files:

  • webhook_server/libs/handlers/pull_request_handler.py
🧬 Code graph analysis (1)
webhook_server/libs/handlers/pull_request_handler.py (2)
webhook_server/utils/helpers.py (1)
  • format_task_fields (135-154)
webhook_server/libs/handlers/runner_handler.py (1)
  • run_retests (747-776)
🪛 Ruff (0.14.10)
webhook_server/libs/handlers/pull_request_handler.py

887-887: Logging statement uses f-string

(G004)


915-915: Logging statement uses f-string

(G004)


918-918: Logging statement uses f-string

(G004)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: can-be-merged
  • GitHub Check: can-be-merged
  • GitHub Check: can-be-merged
  • GitHub Check: can-be-merged
  • GitHub Check: can-be-merged
  • GitHub Check: conventional-title
  • GitHub Check: build-container
  • GitHub Check: python-module-install
  • GitHub Check: pre-commit
  • GitHub Check: tox
🔇 Additional comments (3)
webhook_server/libs/handlers/pull_request_handler.py (3)

880-901: LGTM! Clean return type enhancement.

Changing the return type from None to str is backward compatible—existing callers (like line 743) can ignore the return value. The new return enables the caller at line 432 to act on merge_state without re-querying PyGithub, reducing API calls.


903-922: LGTM! Clean delegation to existing retest infrastructure.

The implementation correctly:

  • Wraps pull_request.number property access in asyncio.to_thread() per guidelines
  • Uses structured logging with format_task_fields() for task correlation
  • Delegates to runner_handler.run_retests() (verified in relevant code snippets)
  • Returns early when no checks are configured (defensive but acceptable)

410-437: LGTM! Config attributes verified and implementation confirmed.

Both config attributes exist and are properly typed in the GithubWebhook class:

  • retrigger_checks_on_base_push: bool — opt-in flag initialized from config
  • current_pull_request_supported_retest: list[str] — populated from repository settings

The _retrigger_check_suites_for_pr() method correctly follows async patterns: wraps PyGithub property access with asyncio.to_thread(), checks for available checks before processing, and delegates to runner_handler.run_retests(). The merge state filtering (only "behind" and "blocked") is tested across multiple scenarios and prevents unnecessary retriggers for clean or conflicted PRs.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42968da and 1746abf.

📒 Files selected for processing (2)
  • webhook_server/config/schema.yaml
  • webhook_server/tests/test_pull_request_handler.py
🧰 Additional context used
📓 Path-based instructions (4)
webhook_server/config/schema.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

Configuration schema must be defined in webhook_server/config/schema.yaml with validation logic in webhook_server/libs/config.py

Files:

  • webhook_server/config/schema.yaml
webhook_server/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

webhook_server/**/*.py: Never use defensive checks (hasattr, if object:, if value is not None) on required parameters passed to __init__() - required parameters are always provided in this self-contained server application
Defensive checks ARE acceptable in destructors (__del__) because they may be called during failed initialization
Defensive checks ARE acceptable for lazy initialization where attributes explicitly start as None - check is legitimate for uninitialized attributes
Never use defensive checks on known library versions controlled in pyproject.toml - e.g., PyGithub >=2.4.0 methods are guaranteed to exist
Never use defensive checks on webhook payload fields guaranteed by GitHub webhook specification - e.g., user.node_id, user.type, sender always exist in webhook payloads
Never use hasattr() for type discrimination - use isinstance() instead for type checking
Never return fake default values ('', 0, False, None objects, []) to hide missing data - raise exceptions with clear error messages instead to enable fail-fast debugging
ALL PyGithub method calls MUST be wrapped with asyncio.to_thread() to avoid blocking the FastAPI event loop - including .get_*(), .create_*(), .edit(), .add_to_*(), .remove_from_*()
ALL PyGithub property accesses that may trigger API calls MUST be wrapped with asyncio.to_thread() - properties like .draft, .mergeable, .state, .committer, .permissions, .labels, .assignees are NOT safe to access directly
PyGithub PaginatedList iteration MUST be wrapped in asyncio.to_thread() with list conversion - never iterate directly to avoid blocking the event loop
ALL imports must be at the top of files - no imports in the middle of functions or try/except blocks except for TYPE_CHECKING conditional imports
ALL functions must have complete type hints compatible with mypy strict mode - parameter types, return types, and complex object types must be explicitly annotated
Code coverage of 90% or higher is ...

Files:

  • webhook_server/tests/test_pull_request_handler.py
webhook_server/**/*.{py,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Defensive checks ARE acceptable for optional parameters explicitly typed as Type | None - check is legitimate for parameters allowing None

Files:

  • webhook_server/tests/test_pull_request_handler.py
webhook_server/tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Test files MUST use TEST_GITHUB_TOKEN = 'ghp_test1234...' with # pragma: allowlist secret comment to avoid security warnings in test tokens

Files:

  • webhook_server/tests/test_pull_request_handler.py
🧠 Learnings (12)
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to {config.yaml,.github-webhook-server.yaml} : Maintain backward compatibility ONLY for user-facing configuration files (`config.yaml`, `.github-webhook-server.yaml`) - configuration schema changes must support old formats or provide migration paths

Applied to files:

  • webhook_server/config/schema.yaml
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/config/schema.yaml : Configuration schema must be defined in `webhook_server/config/schema.yaml` with validation logic in `webhook_server/libs/config.py`

Applied to files:

  • webhook_server/config/schema.yaml
📚 Learning: 2024-10-29T08:09:57.157Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 612
File: webhook_server_container/libs/github_api.py:2089-2100
Timestamp: 2024-10-29T08:09:57.157Z
Learning: In `webhook_server_container/libs/github_api.py`, when the function `_keep_approved_by_approvers_after_rebase` is called, existing approval labels have already been cleared after pushing new changes, so there's no need to check for existing approvals within this function.

Applied to files:

  • webhook_server/config/schema.yaml
  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2024-10-29T10:42:50.163Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 612
File: webhook_server_container/libs/github_api.py:925-926
Timestamp: 2024-10-29T10:42:50.163Z
Learning: In `webhook_server_container/libs/github_api.py`, the method `self._keep_approved_by_approvers_after_rebase()` must be called after removing labels when synchronizing a pull request. Therefore, it should be placed outside the `ThreadPoolExecutor` to ensure it runs sequentially after label removal.

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2024-10-08T09:19:56.185Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 586
File: webhook_server_container/libs/github_api.py:1947-1956
Timestamp: 2024-10-08T09:19:56.185Z
Learning: In `webhook_server_container/libs/github_api.py`, the indentation style used in the `set_pull_request_automerge` method is acceptable as per the project's coding standards.

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/**/*.py : ALL PyGithub property accesses that may trigger API calls MUST be wrapped with `asyncio.to_thread()` - properties like `.draft`, `.mergeable`, `.state`, `.committer`, `.permissions`, `.labels`, `.assignees` are NOT safe to access directly

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/libs/**/*.py : Eliminate unnecessary defensive checks for return type changes and method signature modifications in internal APIs - fail-fast principle is preferred over compatibility

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-05-13T12:06:27.297Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 778
File: webhook_server/libs/pull_request_handler.py:327-330
Timestamp: 2025-05-13T12:06:27.297Z
Learning: In the GitHub webhook server, synchronous GitHub API calls (like create_issue_comment, add_to_assignees, etc.) in async methods should be awaited using asyncio.to_thread or loop.run_in_executor to prevent blocking the event loop.

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/**/*.py : ALL PyGithub method calls MUST be wrapped with `asyncio.to_thread()` to avoid blocking the FastAPI event loop - including `.get_*()`, `.create_*()`, `.edit()`, `.add_to_*()`, `.remove_from_*()`

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-10-28T13:04:00.466Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 878
File: webhook_server/libs/handlers/runner_handler.py:491-571
Timestamp: 2025-10-28T13:04:00.466Z
Learning: In webhook_server/libs/handlers/runner_handler.py, the run_build_container method is designed with the pattern that push=True is always called with set_check=False in production code, so no check-run status needs to be finalized after push operations.

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-11-25T12:39:43.079Z
Learnt from: CR
Repo: myk-org/github-webhook-server PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:39:43.079Z
Learning: Applies to webhook_server/**/*.py : PyGithub PaginatedList iteration MUST be wrapped in `asyncio.to_thread()` with list conversion - never iterate directly to avoid blocking the event loop

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
📚 Learning: 2025-12-29T13:09:56.231Z
Learnt from: rnetser
Repo: myk-org/github-webhook-server PR: 959
File: webhook_server/libs/handlers/pull_request_handler.py:887-887
Timestamp: 2025-12-29T13:09:56.231Z
Learning: In the myk-org/github-webhook-server repository, logging statements in the webhook_server codebase should use f-strings for interpolation. Do not suggest changing to lazy formatting with % (e.g., logger.debug('msg %s', var)) since that is an established style choice. When adding new log statements, prefer f"...{var}..." for readability and performance, and avoid string concatenation or format-style logging unless the project explicitly adopts a different convention.

Applied to files:

  • webhook_server/tests/test_pull_request_handler.py
🧬 Code graph analysis (1)
webhook_server/tests/test_pull_request_handler.py (2)
webhook_server/libs/handlers/pull_request_handler.py (3)
  • label_and_rerun_checks_all_opened_pull_requests_merge_state_after_merged (410-437)
  • label_pull_request_by_merge_state (880-901)
  • _retrigger_check_suites_for_pr (903-921)
webhook_server/libs/handlers/runner_handler.py (1)
  • run_retests (747-776)
🪛 Ruff (0.14.10)
webhook_server/tests/test_pull_request_handler.py

30-30: Missing return type annotation for private function _sync_to_thread

(ANN202)


30-30: Missing type annotation for *args

(ANN002)


30-30: Missing type annotation for **kwargs

(ANN003)


470-470: Wrong type passed to first argument of pytest.mark.parametrize; expected tuple

Use a tuple for the first argument

(PT006)


485-485: Boolean-typed positional argument in function definition

(FBT001)

🔇 Additional comments (7)
webhook_server/config/schema.yaml (2)

86-89: LGTM: Global config property correctly defined.

The new retrigger-checks-on-base-push global property is well-structured:

  • Type and default value follow the established pattern
  • Description accurately reflects that re-triggering occurs when a PR is merged (not on arbitrary pushes)
  • Optional property maintains backward compatibility

Based on learnings, this maintains backward compatibility for user-facing configuration.


306-309: LGTM: Per-repository override correctly defined.

The per-repository retrigger-checks-on-base-push property correctly mirrors the global property, allowing repository-specific configuration. This follows the established pattern for configuration overrides.

webhook_server/tests/test_pull_request_handler.py (5)

291-292: LGTM: Method rename reflects expanded functionality.

The method name change from label_all_opened_pull_requests_merge_state_after_merged to label_and_rerun_checks_all_opened_pull_requests_merge_state_after_merged accurately describes the new behavior (labeling + optional check retriggering). All test references are updated consistently.

Also applies to: 429-431


413-432: LGTM: Test correctly verifies default behavior without retriggering.

The test properly verifies that when retrigger_checks_on_base_push is disabled (line 424), only labeling occurs without check retriggering. The test correctly patches asyncio.sleep to avoid real delays.

Minor note: This test doesn't patch asyncio.to_thread (unlike newer tests below), relying on the real implementation. While this works because the mock object is thread-safe, consider using the _sync_to_thread pattern for consistency with lines 460, 496, etc.


434-466: LGTM: Comprehensive test for retrigger behavior.

The test correctly verifies that:

  • Retriggering is conditional on retrigger_checks_on_base_push being enabled
  • Only PRs with merge_state="behind" trigger checks
  • The _sync_to_thread pattern is properly used to avoid blocking operations

The mock_label_side_effect helper now includes proper type annotations, addressing the previous review feedback.


469-513: LGTM: Excellent parametrized test coverage for merge states.

The parametrized test comprehensively verifies retrigger behavior across all GitHub merge states:

  • Correctly identifies behind and blocked as retriggering states
  • Verifies non-retriggering states (clean, dirty, unstable, unknown)
  • Properly uses the _sync_to_thread pattern throughout

Note: The Ruff PT006 warning about tuple syntax is a false positive—the comma-separated string format is valid pytest parametrize syntax.


1895-1925: LGTM: Comprehensive tests for _retrigger_check_suites_for_pr.

The first two tests provide excellent coverage:

  • test_retrigger_check_suites_for_pr_success verifies that configured checks are passed to run_retests
  • test_retrigger_check_suites_for_pr_no_check_suites verifies early return when no checks are configured

Both properly use the _sync_to_thread pattern and verify the correct integration points.

@rnetser rnetser changed the title Aloow opt-in to auto re-run GH check runs on open PRs after merge to base branch feat: Allow opt-in to auto re-run GH check runs on open PRs after merge to base branch Dec 29, 2025
@rnetser
Copy link
Collaborator Author

rnetser commented Dec 29, 2025

/retest conventional-title

coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 29, 2025
Added type annotations to _sync_to_thread shim function using modern Python type parameter syntax.
Added missing asyncio.to_thread patch in test_retrigger_check_suites_for_pr_behind_merge to ensure consistent test behavior.
Fixed test docstring to accurately reflect exception propagation behavior.
@rnetser
Copy link
Collaborator Author

rnetser commented Dec 29, 2025

/build-and-push-container

@myakove-bot
Copy link
Collaborator

New container for ghcr.io/myk-org/github-webhook-server:pr-959 published

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants