ocean icon indicating copy to clipboard operation
ocean copied to clipboard

Test create cloud GitHub integration implementation

Open vheckthor opened this issue 7 months ago • 3 comments

User description

Description

What - An integration to sync GitHub Cloud resources to the Port Platform, including repositories, pull requests, teams, members, and workflow runs.

Why - To allow users to import and track their GitHub Cloud resources on the Port Platform, enabling better visibility and management of their GitHub ecosystem.

How - By implementing a robust integration that:

  • Maps GitHub Cloud resources to Port concepts

  • Handles webhook events for real-time updates

  • Provides resync capabilities for all resource types

  • Supports both organization and repository-level webhooks

  • Implements proper error handling and rate limiting

  • Uses async operations for better performance

  • Includes comprehensive logging and monitoring

Type of change

  • [x] New Integration (non-breaking change which adds a new integration)

All tests should be run against the port production environment(using a testing org).

Core testing checklist

  • [x] Integration able to create all default resources from scratch
  • [x] Resync finishes successfully
  • [x] Resync able to create entities
  • [x] Resync able to update entities
  • [x] Resync able to detect and delete entities
  • [ ] Scheduled resync able to abort existing resync and start a new one
  • [x] Tested with at least 2 integrations from scratch
  • [ ] Tested with Kafka and Polling event listeners
  • [ ] Tested deletion of entities that don't pass the selector

Integration testing checklist

  • [x] Integration able to create all default resources from scratch
  • [x] Resync able to create entities
  • [x] Resync able to update entities
  • [x] Resync able to detect and delete entities
  • [x] Resync finishes successfully
  • [x] If new resource kind is added or updated in the integration, add example raw data, mapping and expected result to the examples folder in the integration directory.
  • [x] If resource kind is updated, run the integration with the example data and check if the expected result is achieved
  • [x] If new resource kind is added or updated, validate that live-events for that resource are working as expected
  • [ ] Docs PR link here

Preflight checklist

  • [x] Handled rate limiting
  • [x] Handled pagination
  • [x] Implemented the code in async
  • [ ] Support Multi account

Screenshots

Screenshot 2025-05-23 at 2 51 31 AM (2) Screenshot 2025-05-23 at 2 51 37 AM (2) Screenshot 2025-05-23 at 2 51 43 AM (2) Screenshot 2025-05-23 at 2 51 48 AM (2)

API Documentation

  • GitHub REST API v3: https://docs.github.com/en/rest
  • GitHub Webhooks: https://docs.github.com/en/developers/webhooks-and-events/webhooks
  • GitHub GraphQL API: https://docs.github.com/en/graphql The integration supports the following resource types: Repositories Pull Requests Teams with Members Members Workflow Runs Workflow Jobs

PR Type

Enhancement, Tests, Documentation, Other, Configuration changes


Description

  • Implements a comprehensive GitHub Cloud integration for the Port Platform, enabling synchronization and management of repositories, pull requests, teams, members, and workflow runs.

  • Adds robust async clients for interacting with the GitHub Cloud REST API, including authentication, rate limiting, pagination, and resource enrichment.

  • Introduces entity processors for handling file and search references, as well as utilities for file content parsing (JSON, YAML).

  • Implements full resync logic with batch processing, enrichment options, and error handling.

  • Provides webhook event configuration, factories, and processors for real-time updates on repositories and pull requests.

  • Registers integration handlers and startup logic in the main entrypoint.

  • Adds extensive test coverage for clients, entity processors, webhook logic, and utilities using pytest fixtures and isolated mocks.

  • Includes detailed documentation: README, contributing guidelines, and changelog.

  • Adds configuration files for environment variables, Docker, Poetry, Port integration specs, blueprints, and resource mapping.

  • Provides a Makefile for development, CI workflows, and project automation.


Changes walkthrough 📝

Relevant files
Enhancement
20 files
github_client.py
New async GitHub Cloud client with high-level resource methods

integrations/github-cloud/github_cloud/clients/github_client.py

  • Implements the main async client for interacting with the GitHub Cloud
    REST API.
  • Provides high-level methods for fetching repositories, organizations,
    pull requests, issues, workflow runs/jobs, teams, and file content.
  • Supports enrichment of repository data (e.g., with languages), batch
    processing, and file content parsing.
  • Handles concurrency, error logging, and file reference resolution.
  • +574/-0 
    rest_client.py
    REST client for paginated GitHub Cloud API resources         

    integrations/github-cloud/github_cloud/clients/rest_client.py

  • Implements a REST client for paginated GitHub Cloud API resources.
  • Provides methods for fetching organization/repository resources, file
    content, and repo languages.
  • Handles pagination, response parsing, and content decoding (including
    base64).
  • Includes utility for parsing pagination links from response headers.
  • +244/-0 
    base_client.py
    Base HTTP client for GitHub Cloud API with rate limiting 

    integrations/github-cloud/github_cloud/clients/base_client.py

  • Introduces a base HTTP client for GitHub Cloud API with async request
    handling.
  • Handles authentication, rate limiting, and error management.
  • Provides a method for parsing pagination links from response headers.
  • +112/-0 
    client_factory.py
    Singleton factory for GitHubCloudClient creation                 

    integrations/github-cloud/github_cloud/clients/client_factory.py

  • Implements a singleton factory for creating and caching a
    GitHubCloudClient instance.
  • Retrieves configuration from the Port Ocean context.
  • +24/-0   
    utils.py
    Utilities for object kinds and file content parsing           

    integrations/github-cloud/github_cloud/helpers/utils.py

  • Defines the ObjectKind enum for supported GitHub resource types.
  • Adds robust file content parsing utility for JSON and YAML, with
    logging and fallback.
  • Provides helper functions for parsing file content in various formats.
  • +119/-0 
    entity_processor.py
    Entity processors for file and search references in entities

    integrations/github-cloud/github_cloud/entity_processors/entity_processor.py

  • Implements entity processors for handling file:// and search://
    references in entities.
  • Supports fetching file content and checking file existence in
    repositories.
  • Includes error handling and repository info extraction logic.
  • +165/-0 
    resync_data.py
    Async resync logic for GitHub resources with enrichment   

    integrations/github-cloud/github_cloud/resync_data.py

  • Implements async resync logic for repositories, pull requests, teams
    with members, and members.
  • Supports batch processing, enrichment, and configuration-driven
    options (e.g., include_languages, include_bot_members).
  • Handles error logging and selector configuration extraction.
  • +215/-0 
    events.py
    Event configuration classes for webhook event selection   

    integrations/github-cloud/github_cloud/webhook/events.py

  • Defines abstract and concrete event configuration classes for
    repository and organization webhooks.
  • Uses dataclasses for event configuration and provides dictionary
    conversion for API payloads.
  • +126/-0 
    _base_webhook_factory.py
    Abstract base class for GitHub webhook factories                 

    integrations/github-cloud/github_cloud/webhook/webhook_factory/_base_webhook_factory.py

  • Implements an abstract base class for webhook factories.
  • Provides logic for webhook creation, existence checks, payload
    building, and response validation.
  • Supports generic event configuration types.
  • +145/-0 
    repository_webhook_factory.py
    Repository webhook factory for GitHub Cloud integration   

    integrations/github-cloud/github_cloud/webhook/webhook_factory/repository_webhook_factory.py

  • Implements a factory for creating repository webhooks.
  • Handles webhook creation for multiple repositories and event
    configuration.
  • Includes error handling and logging for batch operations.
  • +123/-0 
    organization_webhook_factory.py
    Organization webhook factory for GitHub Cloud integration

    integrations/github-cloud/github_cloud/webhook/webhook_factory/organization_webhook_factory.py

  • Implements a factory for creating organization webhooks.
  • Handles batch creation for all accessible organizations with error
    handling.
  • Supports event configuration and logging.
  • +122/-0 
    _github_abstract_webhook_processor.py
    Abstract webhook processor for GitHub Cloud events             

    integrations/github-cloud/github_cloud/webhook/webhook_processors/_github_abstract_webhook_processor.py

  • Implements an abstract webhook processor for GitHub Cloud events.
  • Provides common logic for event type extraction, authentication, and
    payload validation.
  • Supports event filtering and logging.
  • +115/-0 
    repository_webhook_processor.py
    Repository webhook processor for GitHub Cloud events         

    integrations/github-cloud/github_cloud/webhook/webhook_processors/repository_webhook_processor.py

  • Implements a webhook processor for repository events.
  • Handles creation, update, and deletion events for repositories.
  • Extracts repository data and manages result formatting.
  • +101/-0 
    pull_request_webhook_processor.py
    Pull request webhook processor for GitHub Cloud events     

    integrations/github-cloud/github_cloud/webhook/webhook_processors/pull_request_webhook_processor.py

  • Implements a webhook processor for pull request events.
  • Handles creation, update, and closure events for pull requests.
  • Extracts pull request data and manages result formatting.
  • +136/-0 
    main.py
    Main integration entrypoint and handler registration         

    integrations/github-cloud/main.py

  • Implements the main integration entrypoint for Port Ocean.
  • Registers resync handlers for repositories, pull requests, teams, and
    members.
  • Handles webhook processor registration and startup logic for webhook
    creation.
  • Includes error handling and logging throughout.
  • +191/-0 
    Makefile
    Add Makefile for development and CI workflows                       

    integrations/github-cloud/Makefile

  • Added a Makefile with commands for install, test, lint, format, clean,
    Docker, and more.
  • Included targets for development, release, documentation, and security
    checks.
  • Provided a help target listing available commands.
  • +101/-0 
    auth_client.py
    Add AuthClient for GitHub API authentication                         

    integrations/github-cloud/github_cloud/clients/auth_client.py

  • Implemented AuthClient class for GitHub Cloud authentication.
  • Provided method to generate authentication headers for API requests.
  • Included docstrings for clarity.
  • +23/-0   
    __init__.py
    Add clients package initialization and exports                     

    integrations/github-cloud/github_cloud/clients/init.py

  • Added __init__.py to expose AuthClient, HTTPBaseClient,
    GitHubCloudClient, and RestClient.
  • Defined __all__ for explicit module exports.
  • +6/-0     
    __init__.py
    Add entity_processors package initialization and exports 

    integrations/github-cloud/github_cloud/entity_processors/init.py

  • Added __init__.py to expose FileEntityProcessor and
    SearchEntityProcessor.
  • Defined __all__ for explicit module exports.
  • +6/-0     
    __init__.py
    Add webhook_factory package initialization and exports     

    integrations/github-cloud/github_cloud/webhook/webhook_factory/init.py

  • Added __init__.py to expose BaseWebhookFactory,
    RepositoryWebhookFactory, and OrganizationWebhookFactory.
  • Defined __all__ for explicit module exports.
  • +9/-0     
    Miscellaneous
    1 files
    __init__.py
    Init file for webhook processor module exports                     

    integrations/github-cloud/github_cloud/webhook/webhook_processors/init.py

  • Adds an __init__ file to expose webhook processor classes.
  • Imports and lists abstract, repository, and pull request processors.
  • +9/-0     
    Tests
    9 files
    conftest.py
    Pytest fixtures for Port Ocean and HTTP client mocking     

    integrations/github-cloud/tests/conftest.py

  • Provides pytest fixtures for mocking Port Ocean context and HTTP
    client.
  • Ensures isolation and mocking for all test modules.
  • +24/-0   
    test_clients.py
    Tests for AuthClient, HTTPBaseClient, and client factory 

    integrations/github-cloud/tests/test_clients.py

  • Adds tests for AuthClient, HTTPBaseClient, and client factory logic.
  • Covers authentication headers, API request handling, rate limiting,
    and singleton behavior.
  • +109/-0 
    test_entity_processors.py
    Tests for file and search entity processors                           

    integrations/github-cloud/tests/test_entity_processors.py

  • Adds tests for FileEntityProcessor and SearchEntityProcessor.
  • Covers file content fetching, search pattern parsing, and error
    handling.
  • +127/-0 
    test_github_client.py
    Tests for GitHubCloudClient high-level methods                     

    integrations/github-cloud/tests/test_github_client.py

  • Adds tests for the main GitHubCloudClient methods.
  • Covers repository, organization, pull request, issue, workflow, and
    team member fetching.
  • Tests enrichment, file content, and search logic.
  • +157/-0 
    test_rest_client.py
    Tests for RestClient pagination and file/language methods

    integrations/github-cloud/tests/test_rest_client.py

  • Adds tests for the RestClient's paginated resource fetching and
    file/language methods.
  • Covers pagination, file content decoding, and search API handling.
  • +175/-0 
    test_utils.py
    Tests for ObjectKind enum and file content parsing             

    integrations/github-cloud/tests/test_utils.py

  • Adds tests for ObjectKind enum and file content parsing utility.
  • Covers JSON, YAML, multi-document YAML, and fallback scenarios.
  • +105/-0 
    test_webhook_factory.py
    Tests for repository and organization webhook factories   

    integrations/github-cloud/tests/test_webhook_factory.py

  • Adds tests for repository and organization webhook factories.
  • Covers webhook creation, existence checks, event configuration, and
    error handling.
  • +169/-0 
    test_webhook_processors.py
    Tests for repository and pull request webhook processors 

    integrations/github-cloud/tests/test_webhook_processors.py

  • Adds tests for repository and pull request webhook processors.
  • Covers authentication, event filtering, payload validation, and event
    handling logic.
  • Tests edge cases and error handling for webhook event processing.
  • +263/-0 
    test_webhook_events.py
    Add tests for webhook event configuration classes               

    integrations/github-cloud/tests/test_webhook_events.py

  • Added tests for RepositoryEvents and OrganizationEvents classes.
  • Tested default and custom values, to_dict methods, and immutability.
  • Used pytest and dataclasses for assertions and error checks.
  • +91/-0   
    Documentation
    3 files
    README.md
    Initial project README with installation and usage instructions

    integrations/github-cloud/README.md

  • Added a comprehensive README file describing the GitHub Cloud
    integration.
  • Included installation, development, and contribution instructions.
  • Provided an overview of features and project structure.
  • Linked to documentation and license information.
  • +89/-0   
    CONTRIBUTING.md
    Add contributing guidelines reference file                             

    integrations/github-cloud/CONTRIBUTING.md

  • Added a CONTRIBUTING.md file with a link to the integration
    contributing guide.
  • +3/-0     
    CHANGELOG.md
    Add changelog file for project version tracking                   

    integrations/github-cloud/CHANGELOG.md

  • Added a CHANGELOG.md file to document notable project changes.
  • Adopted Keep a Changelog and Semantic Versioning standards.
  • +6/-0     
    Configuration changes
    8 files
    .env.example
    Provide example environment configuration file                     

    integrations/github-cloud/.env.example

  • Added an example environment file with required environment variables
    for configuration.
  • Included placeholders for GitHub token and Port integration settings.
  • +7/-0     
    poetry.toml
    Add Poetry configuration for in-project virtualenvs           

    integrations/github-cloud/poetry.toml

  • Added poetry.toml to configure Poetry to use in-project virtual
    environments.
  • +2/-0     
    pyproject.toml
    Add project and dependency configuration with pyproject.toml

    integrations/github-cloud/pyproject.toml

  • Added pyproject.toml for project metadata and dependency management.
  • Defined dependencies, development tools, and configuration for mypy,
    ruff, black, and pytest.
  • Configured towncrier for changelog management.
  • +112/-0 
    Dockerfile
    Add Dockerfile for containerized deployment                           

    integrations/github-cloud/Dockerfile

  • Added a Dockerfile for building and running the integration in a
    container.
  • Configured Poetry installation and dependency management.
  • Set up the entrypoint to run the application.
  • +32/-0   
    .dockerignore
    Add .dockerignore to optimize Docker builds                           

    integrations/github-cloud/.dockerignore

  • Added a .dockerignore file to exclude unnecessary files and
    directories from Docker build context.
  • Excluded VCS, virtual environments, test, documentation, and cache
    files.
  • +78/-0   
    spec.yaml
    Add Port integration specification file                                   

    integrations/github-cloud/.port/spec.yaml

  • Added Port integration specification YAML describing supported
    features and configuration options.
  • Defined exporter resources and required configuration fields.
  • +22/-0   
    blueprints.json
    Add Port blueprints for GitHub resource mapping                   

    integrations/github-cloud/.port/resources/blueprints.json

  • Added blueprints.json defining Port blueprints for GitHub resources
    (Repository, Member, Team, Pull Request).
  • Specified schemas, properties, and relations for each blueprint.
  • +157/-0 
    port-app-config.yml
    Add Port app configuration for resource mapping                   

    integrations/github-cloud/.port/resources/port-app-config.yml

  • Added Port app configuration YAML mapping GitHub resources to Port
    entities.
  • Defined selectors, entity mappings, properties, and relations for
    repository, member, team, and pull request.
  • +69/-0   
    Additional files
    3 files
    __init__.py [link]   
    __init__.py [link]   
    __init__.py [link]   

    Need help?
  • Type /help how to ... in the comments thread for any questions about Qodo Merge usage.
  • Check out the documentation for more information.
  • vheckthor avatar May 23 '25 02:05 vheckthor

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
    🧪 PR contains tests
    🔒 Security concerns

    Sensitive information exposure:
    The code in github_cloud/clients/base_client.py logs API request URLs with debug level, which might include sensitive information in query parameters. Consider masking sensitive parts of URLs in logs, especially when they might contain tokens or other credentials.

    ⚡ Recommended focus areas for review

    Error Handling

    The get_paginated_resource method has a potential issue with error handling. If the API request fails, it raises an exception but doesn't properly handle pagination state, which could lead to incomplete data retrieval or infinite loops.

    params_dict = params or {}
    # GitHub Cloud recommends using per_page parameter
    params_dict["per_page"] = params_dict.get("per_page", self.DEFAULT_PAGE_SIZE)
    
    url = resource_type
    
    while url:
        logger.debug(f"Fetching from {url}")
        try:
            response = await self._client.request(
                method="GET",
                url=url if url.startswith("http") else f"{self.base_url}/{url}",
                headers=self._headers,
                params=params_dict if not url.startswith("http") else None,
            )
            response.raise_for_status()
        except Exception as e:
            logger.error(f"Failed to fetch {url}: {str(e)}")
            raise
    
        batch = response.json()
    
        # Handle different response types using match-case
        match batch:
            case list() if batch:
                yield batch
                links = await self.get_page_links(response)
                url = links.get("next", "")
                params_dict = None
            case dict() if "items" in batch and batch["items"]:
                yield batch["items"]
                # Handle GitHub Cloud search API pagination
                if "next_page" in batch:
                    params_dict = params_dict or {}
                    params_dict["page"] = batch["next_page"]
                else:
                    links = await self.get_page_links(response)
                    url = links.get("next", "")
                    params_dict = None
            case _:
                break
    
    Indentation Issue

    There's an indentation inconsistency in the get_repositories method that could affect the logic flow. The code block after the async for loop has an extra level of indentation.

    logger.info(f"Received batch with {len(repos_batch)} repositories")
    if include_languages:
        enriched_batch = await self._enrich_batch(
            repos_batch, self._enrich_repo_with_languages, max_concurrent
        )
        yield enriched_batch
    else:
        yield repos_batch
    
    Rate Limiting Logic

    The rate limiting logic is duplicated in both the try block and the exception handler, which could lead to maintenance issues. Consider refactoring to a single rate limit handling function.

        match response.status_code:
            case HTTPStatus.FORBIDDEN if response.headers.get("X-RateLimit-Remaining") == "0":
                reset_time = int(response.headers.get("X-RateLimit-Reset", time.time() + 60))
                wait_time = reset_time - int(time.time()) + 1
                logger.warning(f"Rate limited. Waiting {wait_time}s...")
                await asyncio.sleep(wait_time)
                continue
            case HTTPStatus.NOT_FOUND:
                return {}
            case _:
                response.raise_for_status()
                return response.json() if response.content else {}
    
    except httpx.HTTPStatusError as e:
        # Handle rate limiting in exception case
        if e.response.status_code == HTTPStatus.FORBIDDEN and e.response.headers.get("X-RateLimit-Remaining") == "0":
            reset_time = int(e.response.headers.get("X-RateLimit-Reset", time.time() + 60))
            wait_time = reset_time - int(time.time()) + 1
            logger.warning(f"Rate limited. Waiting {wait_time}s...")
            await asyncio.sleep(wait_time)
            continue
    

    qodo-code-review[bot] avatar May 23 '25 02:05 qodo-code-review[bot]

    PR Code Suggestions ✨

    Explore these optional code suggestions:

    CategorySuggestion                                                                                                                                    Impact
    Possible issue
    Fix indentation error

    Fix the indentation error in the code block. The logger statement is incorrectly
    indented, which will cause a syntax error when the code is executed. Proper
    indentation is critical in Python as it defines code blocks.

    integrations/github-cloud/github_cloud/clients/github_client.py [177-180]

     async for repos_batch in self.rest.get_paginated_resource(
         "user/repos", params=request_params
     ):
    -        logger.info(f"Received batch with {len(repos_batch)} repositories")
    +    logger.info(f"Received batch with {len(repos_batch)} repositories")
    
    • [ ] Apply / Chat
    Suggestion importance[1-10]: 9

    __

    Why: The suggestion correctly identifies and fixes a critical indentation error that would cause a syntax error and prevent the code from running. Proper indentation is essential in Python, making this a high-impact correction.

    High
    Improve error handling

    The dictionary comprehension has a potential bug with the walrus operator (:=)
    assignment for 'parts' and 'rel'. If 'rel="' is not in parts[1], the 'rel'
    variable will still be assigned but not used, which could lead to unexpected
    behavior. Add proper error handling for this case.

    integrations/github-cloud/github_cloud/clients/rest_client.py [239-244]

    -return {
    -    rel.split('rel="')[1].rstrip('"'): parts[0].strip("<>")
    -    for link in response.headers["Link"].split(",")
    -    if len(parts := link.strip().split(";")) >= 2
    -    and 'rel="' in (rel := parts[1].strip())
    -}
    +result = {}
    +for link in response.headers["Link"].split(","):
    +    parts = link.strip().split(";")
    +    if len(parts) >= 2:
    +        rel_part = parts[1].strip()
    +        if 'rel="' in rel_part:
    +            url = parts[0].strip("<>")
    +            rel = rel_part.split('rel="')[1].rstrip('"')
    +            result[rel] = url
    +return result
    
    • [ ] Apply / Chat
    Suggestion importance[1-10]: 7

    __

    Why: The suggestion improves the robustness and clarity of the dictionary comprehension by making the parsing logic explicit and easier to follow, reducing the risk of subtle bugs with the walrus operator. While not a critical bug fix, it enhances maintainability and correctness.

    Medium
    Fix redundant string replacement

    The current code is replacing "/hooks" with "/hooks", which is a no-op operation
    that doesn't change the endpoint. This could lead to incorrect API calls if the
    endpoint doesn't already end with "/hooks". Review the intended replacement
    logic.

    integrations/github-cloud/github_cloud/webhook/webhook_factory/_base_webhook_factory.py [76-77]

     # Get the current webhooks
    -webhooks_endpoint = github_webhook_endpoint.replace("/hooks", "/hooks")
    +webhooks_endpoint = github_webhook_endpoint
    
    • [ ] Apply / Chat
    Suggestion importance[1-10]: 6

    __

    Why: The suggestion removes a redundant and confusing string replacement operation that has no effect, clarifying the code and preventing potential future confusion or errors. This is a minor but worthwhile improvement.

    Low
    General
    Improve PR state handling

    Handle the "closed" action more specifically by checking if the pull request was
    merged, and update the status accordingly. This ensures accurate state
    representation in Port.

    integrations/github-cloud/github_cloud/webhook/webhook_processors/pull_request_webhook_processor.py [64-113]

     async def handle_event(
         self, payload: EventPayload, resource_config: ResourceConfig
     ) -> WebhookEventRawResults:
         """
         Handle a pull request event.
     
         Args:
             payload: Event payload
             resource_config: Resource configuration
     
         Returns:
             Processing results
     
         Raises:
             ValueError: If required data is missing or invalid
         """
         try:
             action, pull_request, repo, pr_number = self._extract_pull_request_data(payload)
             repo_name = repo.get("full_name", "")
     
             logger.info(f"Handling pull request {action} event for {repo_name}#{pr_number}")
     
             # Use match-case for action handling
             match action:
    -            case "closed" | "merged":
    -                # For closed/merged PRs, we still want to update the status
    +            case "closed":
    +                # For closed PRs, check if it was merged
    +                updated_pr = await self._github_cloud_webhook_client.get_pull_request(
    +                    repo_name, pr_number
    +                )
    +                if updated_pr and updated_pr.get("merged"):
    +                    logger.info(f"Pull request {repo_name}#{pr_number} was merged")
    +                    # Ensure the action reflects the merged state
    +                    updated_pr["state"] = "merged"
    +            case "merged":
    +                # For merged PRs, we still want to update the status
                     updated_pr = await self._github_cloud_webhook_client.get_pull_request(
                         repo_name, pr_number
                     )
                 case _:
                     # For other actions, try to get fresh data, fallback to payload
                     updated_pr = (
                         await self._github_cloud_webhook_client.get_pull_request(repo_name, pr_number)
                         or pull_request
                     )
     
             if not updated_pr:
                 logger.warning(f"Could not fetch pull request {repo_name}#{pr_number}")
                 return WebhookEventRawResults(
                     updated_raw_results=[],
                     deleted_raw_results=[],
                 )
     
             # Add repository information to the pull request
             updated_pr["repository"] = repo
     
             return WebhookEventRawResults(
                 updated_raw_results=[updated_pr],
                 deleted_raw_results=[],
             )
    
    • [ ] Apply / Chat
    Suggestion importance[1-10]: 8

    __

    Why: This suggestion ensures accurate state representation for merged pull requests, which is important for downstream systems relying on correct PR status, making it a high-impact correctness improvement.

    Medium
    Add request timeout

    Add a timeout parameter to the HTTP request to prevent indefinite waiting for
    responses. This helps avoid blocking the application when GitHub API is slow to
    respond.

    integrations/github-cloud/github_cloud/clients/base_client.py [30-64]

     async def send_api_request(
         self,
         method: str,
         path: str,
         params: Optional[dict[str, Any]] = None,
         data: Optional[dict[str, Any]] = None,
     ) -> dict[str, Any]:
         """
         Send an API request to GitHub Cloud.
     
         Args:
             method: HTTP method (GET, POST, PUT, DELETE)
             path: API path to append to base URL
             params: Query parameters
             data: Request body data
     
         Returns:
             JSON response as dictionary
     
         Raises:
             httpx.HTTPError: If the request fails (except 404)
             httpx.HTTPStatusError: If the request fails with a non-404 status code
         """
         url = f"{self.base_url}/{path.lstrip('/')}"
         logger.debug(f"Sending {method} request to {url}")
     
         for attempt in range(3):
             try:
                 response = await self._client.request(
                     method=method,
                     url=url,
                     headers=self._headers,
                     params=params,
                     json=data,
    +                timeout=60.0,
                 )
    
    • [ ] Apply / Chat
    Suggestion importance[1-10]: 7

    __

    Why: Introducing a timeout to HTTP requests is a good practice to prevent indefinite hangs, improving reliability, but is not a critical bug fix.

    Medium
    Track failed operations

    Add error count tracking to provide a complete summary of webhook creation
    results. This helps with monitoring and troubleshooting by showing both
    successful and failed operations.

    integrations/github-cloud/github_cloud/webhook/webhook_factory/repository_webhook_factory.py [86-110]

     async def create_webhooks_for_repositories(self, repositories: list[Dict[str, Any]]) -> None:
         """
         Create webhooks for multiple repositories.
     
         Args:
             repositories: List of repositories
     
         Raises:
             ValueError: If repository data is invalid
         """
         if not repositories:
             logger.warning("No repositories provided for webhook creation")
             return
     
         logger.info(f"Initiating webhooks creation for {len(repositories)} repositories")
     
         success_count = 0
    +    error_count = 0
         for repo in repositories:
             try:
                 owner, name = self._get_repo_info(repo)
                 if await self.create_repository_webhook(owner, name):
                     success_count += 1
    +            else:
    +                error_count += 1
             except ValueError as e:
                 logger.error(f"Skipping invalid repository: {str(e)}")
    +            error_count += 1
                 continue
     
    +    logger.info(
    +        f"Completed webhooks creation process: {success_count}/{len(repositories)} successful, {error_count} failed"
    +    )
    +
    
    • [ ] Apply / Chat
    Suggestion importance[1-10]: 6

    __

    Why: Adding error count tracking and reporting in create_webhooks_for_repositories improves observability and troubleshooting, but is a moderate enhancement rather than a critical fix.

    Low
    • [ ] Update

    qodo-code-review[bot] avatar May 23 '25 02:05 qodo-code-review[bot]

    This pull request is automatically being deployed by Amplify Hosting (learn more).

    Access this pull request here: https://pr-1681.d1ftd8v2gowp8w.amplifyapp.com