tawada / grass-grower

0 stars 0 forks source link

Enhance exception handling in `services/github/__init__.py` to distinguish between different subprocess errors more accurately. #101

Open tawada opened 1 month ago

tawada commented 1 month ago

The existing program has various modules and functions spread across multiple files. Here is one specific issue identified within the code:

Issue: Lack of Exception Handling Granularity

File: services/github/exceptions.py and services/github/__init__.py

Description: In the services/github/__init__.py, there are several external command executions using subprocess.run and other git operations. These operations can fail due to a variety of reasons like network issues, incorrect repository paths, and unauthorized access. Currently, the exception handling around these commands is not granular enough to distinguish between various failure modes.

For instance, in services/github/setup_repository, all subprocess errors are caught and raised again as a high-level GitHubRepoNotFoundException. This is misleading because the actual error could be different (e.g., network failure or permission issue).

Example of the Issue:

except exceptions.GitHubRepoNotFoundException as err:
    raise exceptions.GitHubRepoNotFoundException(
        f"Invalid repository: {repo}") from err

Suggested Fix: Enhance the exception handling mechanism by distinguishing between various exceptions. Additionally, use the existing custom exceptions like GitHubConnectionException, GitHubNoRefFetchedException, etc., for more informative error messages.

Proposed Change:

try:
    complete_process = subprocess.run(
        command,
        stdout=subprocess.PIPE if capture_output else None,
        stderr=subprocess.PIPE if capture_output else None,
        cwd=repo_path,
        check=True,
    )
    return complete_process
except subprocess.CalledProcessError as err:
    shorted_commands = " ".join(command)[:50]
    log(
        f"Command {shorted_commands} failed with error ({err.returncode}): {err}",
        level="exception",
    )
    if "Could not resolve hostname" in err.stderr.decode():
        raise exceptions.GitHubConnectionException("Could not resolve hostname github.com") from err
    elif "No such ref was fetched" in err.stderr.decode():
        raise exceptions.GitNoRefFetchedException("No such ref was fetched") from err
    else:
        exception, error_message = exceptions.parse_exception(err)
        raise exception(error_message) from err

This way, the error messages will be more informative, and different failure cases can be handled accordingly.