diff --git a/repo_policy_compliance/check.py b/repo_policy_compliance/check.py
index 6f8c8413..4893775d 100644
--- a/repo_policy_compliance/check.py
+++ b/repo_policy_compliance/check.py
@@ -4,7 +4,7 @@
"""Individual checks used to compose job checks."""
from enum import Enum
-from typing import NamedTuple
+from typing import Callable, NamedTuple, ParamSpec, TypeVar
from github import Github
from github.Branch import Branch
@@ -12,6 +12,7 @@
from repo_policy_compliance import log
from repo_policy_compliance.comment import remove_quote_lines
+from repo_policy_compliance.exceptions import GithubClientError
from repo_policy_compliance.github_client import (
get_branch,
get_collaborator_permission,
@@ -65,6 +66,38 @@ class Report(NamedTuple):
log.setup()
+P = ParamSpec("P")
+R = TypeVar("R")
+
+
+def github_exceptions_to_fail_report(func: Callable[P, R]) -> Callable[P, R | Report]:
+ """Catch exceptions and convert to failed report with reason.
+
+ Args:
+ func: The function to catch the GithubClient exceptions for.
+
+ Returns:
+ The function where any exceptions raised would be converted to a failed result.
+ """
+
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R | Report:
+ """Replace function.
+
+ Args:
+ args: The positional arguments passed to the original method.
+ kwargs: The keywords arguments passed to the original method.
+
+ Returns:
+ Failed result report if any exceptions were raised. The return value after calling the
+ wrapped function otherwise.
+ """
+ try:
+ return func(*args, **kwargs)
+ except GithubClientError as exc:
+ return Report(result=Result.FAIL, reason=str(exc))
+
+ return wrapper
+
@log.call
def branch_protected(branch: Branch) -> Report:
@@ -84,6 +117,7 @@ def branch_protected(branch: Branch) -> Report:
return Report(result=Result.PASS, reason=None)
+@github_exceptions_to_fail_report
@inject_github_client
@log.call
def target_branch_protection(
@@ -133,6 +167,7 @@ def target_branch_protection(
return Report(result=Result.PASS, reason=None)
+@github_exceptions_to_fail_report
@inject_github_client
@log.call
def collaborators(github_client: Github, repository_name: str) -> Report:
@@ -195,6 +230,7 @@ def _branch_external_fork(repository: Repository, source_repository_name: str) -
return True
+@github_exceptions_to_fail_report
@inject_github_client
@log.call
def execute_job(
diff --git a/src-docs/check.py.md b/src-docs/check.py.md
index ad9e110c..b1d2d89c 100644
--- a/src-docs/check.py.md
+++ b/src-docs/check.py.md
@@ -14,12 +14,14 @@ Individual checks used to compose job checks.
---
-
+
-## function `exceptions_to_fail_report`
+## function `github_exceptions_to_fail_report`
```python
-exceptions_to_fail_report(func: Callable[~P, ~R]) → Callable[~P, ~R]
+github_exceptions_to_fail_report(
+ func: Callable[~P, ~R]
+) → Callable[~P, Union[~R, Report]]
```
Catch exceptions and convert to failed report with reason.
@@ -28,7 +30,7 @@ Catch exceptions and convert to failed report with reason.
**Args:**
- - `func`: The function to catch the exceptions for.
+ - `func`: The function to catch the GithubClient exceptions for.
@@ -36,6 +38,81 @@ Catch exceptions and convert to failed report with reason.
The function where any exceptions raised would be converted to a failed result.
+---
+
+
+
+## function `wrapper`
+
+```python
+wrapper(*args: args, **kwargs: kwargs) → Union[~R, Report]
+```
+
+Replace function.
+
+
+
+**Args:**
+
+ - `args`: The positional arguments passed to the original method.
+ - `kwargs`: The keywords arguments passed to the original method.
+
+
+
+**Returns:**
+ Failed result report if any exceptions were raised. The return value after calling the wrapped function otherwise.
+
+
+---
+
+
+
+## function `wrapper`
+
+```python
+wrapper(*args: args, **kwargs: kwargs) → Union[~R, Report]
+```
+
+Replace function.
+
+
+
+**Args:**
+
+ - `args`: The positional arguments passed to the original method.
+ - `kwargs`: The keywords arguments passed to the original method.
+
+
+
+**Returns:**
+ Failed result report if any exceptions were raised. The return value after calling the wrapped function otherwise.
+
+
+---
+
+
+
+## function `wrapper`
+
+```python
+wrapper(*args: args, **kwargs: kwargs) → Union[~R, Report]
+```
+
+Replace function.
+
+
+
+**Args:**
+
+ - `args`: The positional arguments passed to the original method.
+ - `kwargs`: The keywords arguments passed to the original method.
+
+
+
+**Returns:**
+ Failed result report if any exceptions were raised. The return value after calling the wrapped function otherwise.
+
+
---
## class `Report`
diff --git a/tests/unit/test_check.py b/tests/unit/test_check.py
index e5f3976e..54d377cd 100644
--- a/tests/unit/test_check.py
+++ b/tests/unit/test_check.py
@@ -12,6 +12,29 @@
from github.Repository import Repository
import repo_policy_compliance
+from repo_policy_compliance.check import Result
+from repo_policy_compliance.exceptions import GithubClientError
+
+
+def test_github_exceptions_to_fail_report():
+ """
+ arrange: given a function that raises a GithubClient error.
+ act: when the function is called with github_exceptions_to_fail_report decorator.
+ assert: a failed report with exception as reason is returned.
+ """
+
+ @repo_policy_compliance.check.github_exceptions_to_fail_report
+ def github_client_error_raiser():
+ """A mock function to raise github client error.
+
+ Raises:
+ GithubClientError: always.
+ """
+ raise GithubClientError("Exception message.")
+
+ report = github_client_error_raiser()
+ assert report.result == Result.FAIL
+ assert report.reason == "Exception message."
@pytest.mark.parametrize(
diff --git a/tests/unit/test_github_client.py b/tests/unit/test_github_client.py
index f590126b..b9a91ad3 100644
--- a/tests/unit/test_github_client.py
+++ b/tests/unit/test_github_client.py
@@ -10,7 +10,7 @@
from github.Repository import Repository
import repo_policy_compliance.github_client
-from repo_policy_compliance.check import target_branch_protection
+from repo_policy_compliance.check import Result, target_branch_protection
from repo_policy_compliance.exceptions import GithubClientError
GITHUB_REPOSITORY_NAME = "test/repository"
@@ -48,12 +48,12 @@ def test_github_error(
repo_policy_compliance.github_client, "get", lambda *_args, **_kwargs: github_client
)
- with pytest.raises(GithubClientError) as error:
- # The github_client is injected
- target_branch_protection( # pylint: disable=no-value-for-parameter
- GITHUB_REPOSITORY_NAME, GITHUB_BRANCH_NAME, GITHUB_REPOSITORY_NAME
- )
- assert expected_message in str(error.value)
+ # The github_client is injected
+ report = target_branch_protection( # pylint: disable=no-value-for-parameter
+ GITHUB_REPOSITORY_NAME, GITHUB_BRANCH_NAME, GITHUB_REPOSITORY_NAME
+ )
+ assert report.result == Result.FAIL
+ assert expected_message in str(report.reason)
def test_get_collaborator_permission_error():
@@ -67,7 +67,7 @@ def test_get_collaborator_permission_error():
with pytest.raises(GithubClientError) as error:
# The github_client is injected
- repo_policy_compliance.github_client.get_collaborator_permission( # pylint: disable=no-value-for-parameter
+ repo_policy_compliance.github_client.get_collaborator_permission(
mock_repository, "test_user"
)
assert "Invalid collaborator permission" in str(error.value)