diff --git a/src/git_portfolio/__main__.py b/src/git_portfolio/__main__.py index 032c02fa..a0e4f91a 100644 --- a/src/git_portfolio/__main__.py +++ b/src/git_portfolio/__main__.py @@ -34,14 +34,14 @@ CONFIG_MANAGER = cm.ConfigManager() -def _echo_outputs(response: res.ResponseFailure | res.ResponseSuccess) -> None: - if bool(response): - success = cast(res.ResponseSuccess, response) - click.secho(success.value) - else: - click.secho( - f"Error(s) found during execution:\n{response.value['message']}", fg="red" - ) +def _echo_outputs(responses: list[res.Response]) -> None: + for response in responses: + if bool(response): + success = cast(res.ResponseSuccess, response) + click.secho(success.value) + else: + failure = cast(res.ResponseFailure, response) + click.secho(f"{failure.value['message']}", fg="red") def gitp_config_check(func: F) -> F: @@ -56,11 +56,12 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: ) sys.exit(3) else: - value = func(*args, **kwargs) - _echo_outputs(value) - if not bool(value): - sys.exit(4) - return value + responses = func(*args, **kwargs) + _echo_outputs(responses) + for response in responses: + if not bool(response): + sys.exit(4) + return responses return cast(F, wrapper) @@ -77,9 +78,7 @@ def _get_connection_settings(config: c.Config) -> cs.GhConnectionSettings: @gitp_config_check -def _call_git_use_case( - command: str, args: tuple[str] -) -> res.ResponseFailure | res.ResponseSuccess: +def _call_git_use_case(command: str, args: tuple[str]) -> list[res.Response]: return git.GitUseCase().execute( CONFIG_MANAGER.config.github_selected_repos, command, args ) @@ -87,34 +86,34 @@ def _call_git_use_case( @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def add(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def add(args: tuple[str]) -> list[res.Response]: """Batch `git add` command.""" return _call_git_use_case("add", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def branch(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def branch(args: tuple[str]) -> list[res.Response]: """Batch `git branch` command.""" return _call_git_use_case("branch", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def checkout(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def checkout(args: tuple[str]) -> list[res.Response]: """Batch `git checkout` command.""" return _call_git_use_case("checkout", args) @main.command() @gitp_config_check -def clone() -> res.ResponseFailure | res.ResponseSuccess: +def clone() -> list[res.Response]: """Batch `git clone` command on current folder. Does not accept aditional args.""" settings = _get_connection_settings(CONFIG_MANAGER.config) try: github_service = ghs.GithubService(settings) except ghs.GithubServiceError as gse: - return res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse) + return [res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse)] return gcuc.GitCloneUseCase(github_service).execute( CONFIG_MANAGER.config.github_selected_repos @@ -123,105 +122,105 @@ def clone() -> res.ResponseFailure | res.ResponseSuccess: @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def commit(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def commit(args: tuple[str]) -> list[res.Response]: """Batch `git commit` command.""" return _call_git_use_case("commit", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def diff(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def diff(args: tuple[str]) -> list[res.Response]: """Batch `git diff` command.""" return _call_git_use_case("diff", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def fetch(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def fetch(args: tuple[str]) -> list[res.Response]: """Batch `git fetch` command.""" return _call_git_use_case("fetch", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def init(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def init(args: tuple[str]) -> list[res.Response]: """Batch `git init` command.""" return _call_git_use_case("init", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def merge(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def merge(args: tuple[str]) -> list[res.Response]: """Batch `git merge` command.""" return _call_git_use_case("merge", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def mv(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def mv(args: tuple[str]) -> list[res.Response]: """Batch `git mv` command.""" return _call_git_use_case("mv", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def pull(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def pull(args: tuple[str]) -> list[res.Response]: """Batch `git pull` command.""" return _call_git_use_case("pull", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def push(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def push(args: tuple[str]) -> list[res.Response]: """Batch `git push` command.""" return _call_git_use_case("push", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def rebase(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def rebase(args: tuple[str]) -> list[res.Response]: """Batch `git rebase` command.""" return _call_git_use_case("rebase", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def reset(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def reset(args: tuple[str]) -> list[res.Response]: """Batch `git reset` command.""" return _call_git_use_case("reset", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def rm(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def rm(args: tuple[str]) -> list[res.Response]: """Batch `git rm` command.""" return _call_git_use_case("rm", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def show(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def show(args: tuple[str]) -> list[res.Response]: """Batch `git show` command.""" return _call_git_use_case("show", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def status(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def status(args: tuple[str]) -> list[res.Response]: """Batch `git status` command.""" return _call_git_use_case("status", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def switch(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def switch(args: tuple[str]) -> list[res.Response]: """Batch `git switch` command.""" return _call_git_use_case("switch", args) @main.command(context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) -def tag(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def tag(args: tuple[str]) -> list[res.Response]: """Batch `git tag` command.""" return _call_git_use_case("tag", args) @@ -263,42 +262,45 @@ def config_init() -> None: click.secho(success.value) break else: - click.secho(f"Error: {response.value['message']}", fg="red") - if response.type == res.ResponseTypes.SYSTEM_ERROR: + failure = cast(res.ResponseFailure, response) + click.secho(f"Error: {failure.value['message']}", fg="red") + if failure.type == res.ResponseTypes.SYSTEM_ERROR: click.ClickException("") @group_config.command("repos") @gitp_config_check -def config_repos() -> res.ResponseFailure | res.ResponseSuccess: +def config_repos() -> list[res.Response]: """Configure current working `gitp` repositories.""" new_repos = p.InquirerPrompter.new_repos( CONFIG_MANAGER.config.github_selected_repos ) if not new_repos: - return res.ResponseSuccess() + return [res.ResponseSuccess()] settings = _get_connection_settings(CONFIG_MANAGER.config) try: github_service = ghs.GithubService(settings) except ghs.GithubServiceError as gse: - return res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse) + return [res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse)] repo_names = github_service.get_repo_names() selected_repos = p.InquirerPrompter.select_repos(repo_names) - return cr.ConfigReposUseCase(CONFIG_MANAGER).execute( - github_service.get_config(), selected_repos - ) + return [ + cr.ConfigReposUseCase(CONFIG_MANAGER).execute( + github_service.get_config(), selected_repos + ) + ] @group_issues.command("create") @gitp_config_check -def create_issues() -> res.ResponseFailure | res.ResponseSuccess: +def create_issues() -> list[res.Response]: """Batch creation of issues on GitHub.""" settings = _get_connection_settings(CONFIG_MANAGER.config) try: github_service = ghs.GithubService(settings) except ghs.GithubServiceError as gse: - return res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse) + return [res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse)] issue = p.InquirerPrompter.create_issues( CONFIG_MANAGER.config.github_selected_repos @@ -308,13 +310,13 @@ def create_issues() -> res.ResponseFailure | res.ResponseSuccess: @group_issues.command("close") @gitp_config_check -def close_issues() -> res.ResponseFailure | res.ResponseSuccess: +def close_issues() -> list[res.Response]: """Batch close issues on GitHub.""" settings = _get_connection_settings(CONFIG_MANAGER.config) try: github_service = ghs.GithubService(settings) except ghs.GithubServiceError as gse: - return res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse) + return [res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse)] list_object = "issue" title_query = p.InquirerPrompter.query_by_title( @@ -334,13 +336,13 @@ def close_issues() -> res.ResponseFailure | res.ResponseSuccess: @group_issues.command("reopen") @gitp_config_check -def reopen_issues() -> res.ResponseFailure | res.ResponseSuccess: +def reopen_issues() -> list[res.Response]: """Batch reopen issues on GitHub.""" settings = _get_connection_settings(CONFIG_MANAGER.config) try: github_service = ghs.GithubService(settings) except ghs.GithubServiceError as gse: - return res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse) + return [res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse)] list_object = "issue" title_query = p.InquirerPrompter.query_by_title( @@ -361,7 +363,7 @@ def reopen_issues() -> res.ResponseFailure | res.ResponseSuccess: @main.command("poetry", context_settings={"ignore_unknown_options": True}) @click.argument("args", nargs=-1) @gitp_config_check -def poetry_cmd(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: +def poetry_cmd(args: tuple[str]) -> list[res.Response]: """Batch `poetry` command.""" return poetry.PoetryUseCase().execute( CONFIG_MANAGER.config.github_selected_repos, "poetry", args @@ -370,13 +372,13 @@ def poetry_cmd(args: tuple[str]) -> res.ResponseFailure | res.ResponseSuccess: @group_prs.command("create") @gitp_config_check -def create_prs() -> res.ResponseFailure | res.ResponseSuccess: +def create_prs() -> list[res.Response]: """Batch creation of pull requests on GitHub.""" settings = _get_connection_settings(CONFIG_MANAGER.config) try: github_service = ghs.GithubService(settings) except ghs.GithubServiceError as gse: - return res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse) + return [res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse)] pr = p.InquirerPrompter.create_pull_requests( CONFIG_MANAGER.config.github_selected_repos @@ -396,13 +398,13 @@ def create_prs() -> res.ResponseFailure | res.ResponseSuccess: @group_prs.command("close") @gitp_config_check -def close_prs() -> res.ResponseFailure | res.ResponseSuccess: +def close_prs() -> list[res.Response]: """Batch close pull requests on GitHub.""" settings = _get_connection_settings(CONFIG_MANAGER.config) try: github_service = ghs.GithubService(settings) except ghs.GithubServiceError as gse: - return res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse) + return [res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse)] list_object = "pull request" title_query = p.InquirerPrompter.query_by_title( @@ -422,13 +424,13 @@ def close_prs() -> res.ResponseFailure | res.ResponseSuccess: @group_prs.command("merge") @gitp_config_check -def merge_prs() -> res.ResponseFailure | res.ResponseSuccess: +def merge_prs() -> list[res.Response]: """Batch merge of pull requests on GitHub.""" settings = _get_connection_settings(CONFIG_MANAGER.config) try: github_service = ghs.GithubService(settings) except ghs.GithubServiceError as gse: - return res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse) + return [res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse)] pr_merge = p.InquirerPrompter.merge_pull_requests( github_service.get_username(), @@ -439,13 +441,13 @@ def merge_prs() -> res.ResponseFailure | res.ResponseSuccess: @group_branches.command("delete") @gitp_config_check -def delete_branches() -> res.ResponseFailure | res.ResponseSuccess: +def delete_branches() -> list[res.Response]: """Batch deletion of branches on GitHub.""" settings = _get_connection_settings(CONFIG_MANAGER.config) try: github_service = ghs.GithubService(settings) except ghs.GithubServiceError as gse: - return res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse) + return [res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, gse)] branch = p.InquirerPrompter.delete_branches( CONFIG_MANAGER.config.github_selected_repos diff --git a/src/git_portfolio/domain/issue.py b/src/git_portfolio/domain/issue.py index f9767370..e90c081a 100644 --- a/src/git_portfolio/domain/issue.py +++ b/src/git_portfolio/domain/issue.py @@ -1,6 +1,7 @@ """Issue model.""" +from __future__ import annotations + from dataclasses import dataclass -from typing import Set @dataclass @@ -10,4 +11,4 @@ class Issue: number: int title: str body: str - labels: Set[str] + labels: set[str] diff --git a/src/git_portfolio/domain/pull_request.py b/src/git_portfolio/domain/pull_request.py index e1626db6..76ffbc69 100644 --- a/src/git_portfolio/domain/pull_request.py +++ b/src/git_portfolio/domain/pull_request.py @@ -1,6 +1,7 @@ """Pull request model.""" +from __future__ import annotations + from dataclasses import dataclass -from typing import Set @dataclass @@ -9,7 +10,7 @@ class PullRequest: title: str body: str - labels: Set[str] + labels: set[str] link_issues: bool issues_title_query: str inherit_labels: bool diff --git a/src/git_portfolio/github_service.py b/src/git_portfolio/github_service.py index 9be90310..08a8995b 100644 --- a/src/git_portfolio/github_service.py +++ b/src/git_portfolio/github_service.py @@ -1,6 +1,7 @@ """Github service module.""" from __future__ import annotations +import abc import copy from typing import Any @@ -19,7 +20,28 @@ class GithubServiceError(Exception): pass -class GithubService: +class AbstractGithubService(abc.ABC): + """Abstract Github service class.""" + + @abc.abstractmethod + def list_issues_from_repo( + self, + github_repo: str, + request: il.IssueListValidRequest | il.IssueListInvalidRequest, + ) -> list[i.Issue]: + """Return list of issues from one repository.""" + raise NotImplementedError # pragma: no cover + + @staticmethod + @abc.abstractmethod + def link_issues( + pr_base: pr.PullRequest, filtered_issues: list[i.Issue] + ) -> pr.PullRequest: + """Return a new PR with body message and labels of linked issues.""" + raise NotImplementedError # pragma: no cover + + +class GithubService(AbstractGithubService): """Github service class.""" def __init__(self, github_config: cs.GhConnectionSettings) -> None: diff --git a/src/git_portfolio/responses.py b/src/git_portfolio/responses.py index c0a320ec..d9c81712 100644 --- a/src/git_portfolio/responses.py +++ b/src/git_portfolio/responses.py @@ -15,7 +15,13 @@ class ResponseTypes: SUCCESS = "Success" -class ResponseFailure: +class Response: + """General response class.""" + + pass + + +class ResponseFailure(Response): """Response failure class.""" def __init__(self, type_: str, message: str | Exception | None) -> None: @@ -50,7 +56,7 @@ def __bool__(self) -> bool: return False -class ResponseSuccess: +class ResponseSuccess(Response): """Response success class.""" def __init__(self, value: Any = None) -> None: diff --git a/src/git_portfolio/use_cases/config_init.py b/src/git_portfolio/use_cases/config_init.py index 6fced182..e278f05b 100644 --- a/src/git_portfolio/use_cases/config_init.py +++ b/src/git_portfolio/use_cases/config_init.py @@ -16,9 +16,7 @@ def __init__(self, config_manager: cm.ConfigManager) -> None: """Initializer.""" self.config_manager = config_manager - def execute( - self, request: gcs.GhConnectionSettings - ) -> res.ResponseFailure | res.ResponseSuccess: + def execute(self, request: gcs.GhConnectionSettings) -> res.Response: """Initialize app configuration.""" try: new_github_service = ghs.GithubService(request) diff --git a/src/git_portfolio/use_cases/config_repos.py b/src/git_portfolio/use_cases/config_repos.py index 20b44427..1cea0e3f 100644 --- a/src/git_portfolio/use_cases/config_repos.py +++ b/src/git_portfolio/use_cases/config_repos.py @@ -15,7 +15,7 @@ def __init__(self, config_manager: cm.ConfigManager) -> None: def execute( self, github_config: cs.GhConnectionSettings, selected_repos: list[str] - ) -> res.ResponseFailure | res.ResponseSuccess: + ) -> res.Response: """Configuration of git repositories.""" self.config_manager.config.github_access_token = github_config.access_token self.config_manager.config.github_hostname = github_config.hostname diff --git a/src/git_portfolio/use_cases/gh.py b/src/git_portfolio/use_cases/gh.py index 70b4c197..f718293c 100644 --- a/src/git_portfolio/use_cases/gh.py +++ b/src/git_portfolio/use_cases/gh.py @@ -5,7 +5,7 @@ from typing import Any import git_portfolio.config_manager as cm -import git_portfolio.github_service as ghs +import git_portfolio.github_service as gs import git_portfolio.responses as res @@ -15,49 +15,45 @@ class GhUseCase: def __init__( self, config_manager: cm.ConfigManager, - github_service: ghs.GithubService, + github_service: gs.AbstractGithubService, github_repo: str = "", ) -> None: """Initializer.""" self.config_manager = config_manager self.github_service = github_service - self.error = False self.github_repo = github_repo - self.output = "" + self.responses: list[res.Response] = [] - def call_github_service(self, method: str, *args: Any, **kwargs: Any) -> None: - """Handle error from github_service.""" + def call_github_service( + self, method: str, *args: Any, **kwargs: Any + ) -> res.Response: + """Handle error from github_service and return response.""" + response: res.Response try: method_to_call = getattr(self.github_service, method) - self.output += method_to_call(*args, **kwargs) - except ghs.GithubServiceError as gse: - self.error = True - self.output += str(gse) + output = method_to_call(*args, **kwargs) + response = res.ResponseSuccess(output) + except gs.GithubServiceError as gse: + response = res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, str(gse)) except Exception: - self.error = True - self.output += ( + error_msg = ( "An unexpected error occured. Please report at " "https://github.com/staticdev/git-portfolio/issues/new " f"with the following info:\n{traceback.format_exc()}" ) - - def generate_response(self) -> res.ResponseFailure | res.ResponseSuccess: - """Create appropriate response object.""" - if self.error: - return res.ResponseFailure(res.ResponseTypes.PARAMETERS_ERROR, self.output) - return res.ResponseSuccess(self.output) + response = res.ResponseFailure(res.ResponseTypes.SYSTEM_ERROR, error_msg) + self.responses.append(response) + return response def action(self, github_repo: str, *args: Any, **kwargs: Any) -> None: """Execute some action in a repo.""" raise NotImplementedError # pragma: no cover - def execute( - self, *args: Any, **kwargs: Any - ) -> res.ResponseFailure | res.ResponseSuccess: + def execute(self, *args: Any, **kwargs: Any) -> list[res.Response]: """Execute GitHubUseCase.""" if self.github_repo: self.action(self.github_repo, *args, **kwargs) else: for github_repo in self.config_manager.config.github_selected_repos: self.action(github_repo, *args, **kwargs) - return self.generate_response() + return self.responses diff --git a/src/git_portfolio/use_cases/gh_close_issue.py b/src/git_portfolio/use_cases/gh_close_issue.py index 036ebef9..a0f4ec31 100644 --- a/src/git_portfolio/use_cases/gh_close_issue.py +++ b/src/git_portfolio/use_cases/gh_close_issue.py @@ -21,4 +21,9 @@ def action( # type: ignore[override] if isinstance(response, res.ResponseSuccess): self.call_github_service(github_service_method, github_repo, response.value) else: - self.output += f"{github_repo}: no issues match search.\n" + self.responses.append( + res.ResponseFailure( + res.ResponseTypes.RESOURCE_ERROR, + f"{github_repo}: no issues match search.\n", + ) + ) diff --git a/src/git_portfolio/use_cases/gh_merge_pr.py b/src/git_portfolio/use_cases/gh_merge_pr.py index 545ab5fe..b65eb28c 100644 --- a/src/git_portfolio/use_cases/gh_merge_pr.py +++ b/src/git_portfolio/use_cases/gh_merge_pr.py @@ -14,8 +14,8 @@ def action( # type: ignore[override] ) -> None: """Merge pull requests.""" github_service_method = "merge_pull_request_from_repo" - self.call_github_service(github_service_method, github_repo, pr_merge) - if pr_merge.delete_branch and not self.error: + resp = self.call_github_service(github_service_method, github_repo, pr_merge) + if pr_merge.delete_branch and bool(resp): delete_branch_use_case = dbr.GhDeleteBranchUseCase( self.config_manager, self.github_service ) diff --git a/src/git_portfolio/use_cases/gh_reopen_issue.py b/src/git_portfolio/use_cases/gh_reopen_issue.py index 1cd3326e..727f126e 100644 --- a/src/git_portfolio/use_cases/gh_reopen_issue.py +++ b/src/git_portfolio/use_cases/gh_reopen_issue.py @@ -21,4 +21,9 @@ def action( # type: ignore[override] if isinstance(response, res.ResponseSuccess): self.call_github_service(github_service_method, github_repo, response.value) else: - self.output += f"{github_repo}: no issues match search.\n" + self.responses.append( + res.ResponseFailure( + res.ResponseTypes.RESOURCE_ERROR, + f"{github_repo}: no issues match search.\n", + ) + ) diff --git a/src/git_portfolio/use_cases/git.py b/src/git_portfolio/use_cases/git.py index b6075c51..868c3084 100644 --- a/src/git_portfolio/use_cases/git.py +++ b/src/git_portfolio/use_cases/git.py @@ -14,7 +14,7 @@ class GitUseCase: def execute( self, git_selected_repos: list[str], command: str, args: tuple[str, ...] - ) -> res.ResponseFailure | res.ResponseSuccess: + ) -> list[res.Response]: """Batch `git` command. Args: @@ -23,17 +23,16 @@ def execute( args: command arguments. Returns: - res.ResponseFailure | res.ResponseSuccess: final result. + list[res.Response]: final results. """ err_output = command_checker.CommandChecker().check("git") if err_output: - return res.ResponseFailure(res.ResponseTypes.SYSTEM_ERROR, err_output) - output = "" - error = False + return [res.ResponseFailure(res.ResponseTypes.SYSTEM_ERROR, err_output)] + responses: list[res.Response] = [] cwd = pathlib.Path().absolute() for repo_name in git_selected_repos: folder_name = repo_name.split("/")[1] - output += f"{folder_name}: " + output = f"{folder_name}: " try: popen = subprocess.Popen( # noqa: S603, S607 ["git", command, *args], @@ -41,24 +40,30 @@ def execute( stderr=subprocess.PIPE, cwd=os.path.join(cwd, folder_name), ) - stdout, err = popen.communicate() + stdout, error = popen.communicate() if popen.returncode == 0: if stdout: stdout_str = stdout.decode("utf-8") output += f"{stdout_str}\n" else: output += f"{command} successful.\n" + responses.append(res.ResponseSuccess(output)) else: - if err: - error = True - error_str = err.decode("utf-8") + if error: + error_str = error.decode("utf-8") output += f"{error_str}" + responses.append( + res.ResponseFailure( + res.ResponseTypes.RESOURCE_ERROR, output + ) + ) else: stdout_str = stdout.decode("utf-8") output += f"{stdout_str}\n" + responses.append(res.ResponseSuccess(output)) except FileNotFoundError as fnf_error: - error = True output += f"{fnf_error.strerror}: {fnf_error.filename}\n" - if error: - return res.ResponseFailure(res.ResponseTypes.PARAMETERS_ERROR, output) - return res.ResponseSuccess(output) + responses.append( + res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, output) + ) + return responses diff --git a/src/git_portfolio/use_cases/git_clone.py b/src/git_portfolio/use_cases/git_clone.py index 6e0ead49..b622a51c 100644 --- a/src/git_portfolio/use_cases/git_clone.py +++ b/src/git_portfolio/use_cases/git_clone.py @@ -17,26 +17,25 @@ def __init__(self, github_service: ghs.GithubService) -> None: self.github_service = github_service self.err_output = command_checker.CommandChecker().check("git") - def execute( - self, git_selected_repos: list[str] - ) -> res.ResponseFailure | res.ResponseSuccess: + def execute(self, git_selected_repos: list[str]) -> list[res.Response]: """Batch `git clone` command. Args: git_selected_repos: list of configured repo names. Returns: - str: output. - str: error output. + list[res.Response]: final results. """ if self.err_output: - return res.ResponseFailure(res.ResponseTypes.SYSTEM_ERROR, self.err_output) - output = "" + return [ + res.ResponseFailure(res.ResponseTypes.SYSTEM_ERROR, self.err_output) + ] + responses: list[res.Response] = [] cwd = pathlib.Path().absolute() for repo_name in git_selected_repos: folder_name = repo_name.split("/")[1] clone_path = self.github_service.get_repo_url(repo_name) - output += f"{folder_name}: " + output = f"{folder_name}: " popen = subprocess.Popen( # noqa: S603, S607 ["git", "clone", clone_path], stdout=subprocess.PIPE, @@ -47,7 +46,11 @@ def execute( # check for errors if popen.returncode == 0: output += "clone successful.\n" + responses.append(res.ResponseSuccess(output)) else: error_str = error.decode("utf-8") output += f"{error_str}" - return res.ResponseSuccess(output) + responses.append( + res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, output) + ) + return responses diff --git a/src/git_portfolio/use_cases/poetry.py b/src/git_portfolio/use_cases/poetry.py index 97181c3d..8ca01507 100644 --- a/src/git_portfolio/use_cases/poetry.py +++ b/src/git_portfolio/use_cases/poetry.py @@ -14,7 +14,7 @@ class PoetryUseCase: def execute( self, git_selected_repos: list[str], command: str, args: tuple[str] - ) -> res.ResponseFailure | res.ResponseSuccess: + ) -> list[res.Response]: """Batch `poetry` command. Args: @@ -23,17 +23,16 @@ def execute( args: command arguments. Returns: - res.ResponseFailure | res.ResponseSuccess: final result. + list[res.Response]: final results. """ err_output = command_checker.CommandChecker().check("poetry") if err_output: - return res.ResponseFailure(res.ResponseTypes.SYSTEM_ERROR, err_output) - output = "" - error = False + return [res.ResponseFailure(res.ResponseTypes.SYSTEM_ERROR, err_output)] + responses: list[res.Response] = [] cwd = pathlib.Path().absolute() for repo_name in git_selected_repos: folder_name = repo_name.split("/")[1] - output += f"{folder_name}: " + output = f"{folder_name}: " try: popen = subprocess.Popen( # noqa: S603, S607 [command, *args], @@ -41,7 +40,7 @@ def execute( stderr=subprocess.PIPE, cwd=os.path.join(cwd, folder_name), ) - stdout, err = popen.communicate() + stdout, error = popen.communicate() if popen.returncode == 0: # case for command with no output on success if not stdout: @@ -49,13 +48,16 @@ def execute( else: stdout_str = stdout.decode("utf-8") output += f"{stdout_str}\n" + responses.append(res.ResponseSuccess(output)) else: - error = True - error_str = err.decode("utf-8") + error_str = error.decode("utf-8") output += f"{error_str}" + responses.append( + res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, output) + ) except FileNotFoundError as fnf_error: - error = True output += f"{fnf_error.strerror}: {fnf_error.filename}\n" - if error: - return res.ResponseFailure(res.ResponseTypes.PARAMETERS_ERROR, output) - return res.ResponseSuccess(output) + responses.append( + res.ResponseFailure(res.ResponseTypes.RESOURCE_ERROR, output) + ) + return responses diff --git a/src/git_portfolio/views.py b/src/git_portfolio/views.py index d02acd9e..cbde0c1f 100644 --- a/src/git_portfolio/views.py +++ b/src/git_portfolio/views.py @@ -1,16 +1,16 @@ """List issue on Github use case.""" from __future__ import annotations -import git_portfolio.github_service as ghs +import git_portfolio.github_service as gs import git_portfolio.request_objects.issue_list as il import git_portfolio.responses as res def issues( github_repo: str, - github_service: ghs.GithubService, + github_service: gs.AbstractGithubService, request: il.IssueListValidRequest | il.IssueListInvalidRequest, -) -> res.ResponseSuccess | res.ResponseFailure: +) -> res.Response: """Return a list of matching issues.""" if isinstance(request, il.IssueListInvalidRequest): return res.build_response_from_invalid_request(request) diff --git a/tests/conftest.py b/tests/conftest.py index 37545401..db9db6c0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,8 +1,54 @@ """Package-wide test fixtures.""" import _pytest.config +import git_portfolio.domain.issue as i +import git_portfolio.domain.pull_request as pr +import git_portfolio.domain.pull_request_merge as mpr + def pytest_configure(config: _pytest.config.Config) -> None: """Pytest configuration hook.""" config.addinivalue_line("markers", "e2e: mark as end-to-end test.") config.addinivalue_line("markers", "integration: mark as integration test.") + + +REPO_NAME = "repo-name" +REPO = f"org/{REPO_NAME}" +REPO2 = f"org/{REPO_NAME}2" +SUCCESS_MSG = f"{REPO}: success output" +ERROR_MSG = "some error" +LABEL_BUG = "bug" +LABEL_ENHANCEMENT = "enhancement" +LABEL_DO_NOT_INHERIT = "do_not_use" +DOMAIN_ISSUES = [ + i.Issue(0, "my issue title", "issue body", {LABEL_BUG}), + i.Issue(1, "doesnt match title", "body4", {LABEL_DO_NOT_INHERIT}), + i.Issue(2, "issue title", "body3", set()), + i.Issue(3, "pr match issue title", "body5", {LABEL_ENHANCEMENT}), +] +DOMAIN_PRS = [ + pr.PullRequest( + "my pr title", + "my pr body", + set(), + False, + "", + False, + "main", + "branch", + False, + ), + pr.PullRequest( + "my pr title 2", + "my pr body 2", + {LABEL_BUG, LABEL_BUG}, + True, + "issue title", + True, + "main", + "branch", + False, + ), +] +DOMAIN_MPR = mpr.PullRequestMerge("branch", "main", "org name", False) +BRANCH_NAME = "my-branch" diff --git a/tests/test_github_service.py b/tests/test_github_service.py index fcb57984..7296bf2e 100644 --- a/tests/test_github_service.py +++ b/tests/test_github_service.py @@ -6,19 +6,56 @@ import github3 import pytest from pytest_mock import MockerFixture +from tests.conftest import BRANCH_NAME +from tests.conftest import DOMAIN_ISSUES +from tests.conftest import DOMAIN_MPR +from tests.conftest import DOMAIN_PRS +from tests.conftest import ERROR_MSG +from tests.conftest import LABEL_BUG +from tests.conftest import LABEL_DO_NOT_INHERIT +from tests.conftest import LABEL_ENHANCEMENT +from tests.conftest import REPO +from tests.conftest import REPO2 +from tests.conftest import SUCCESS_MSG import git_portfolio.domain.gh_connection_settings as cs import git_portfolio.domain.issue as i import git_portfolio.domain.pull_request as pr -import git_portfolio.domain.pull_request_merge as mpr import git_portfolio.github_service as gs import git_portfolio.request_objects.issue_list as il -REPO = "org/repo-name" -REPO2 = "org/repo-name2" -INVALID_REQUEST_ISSUES = il.IssueListInvalidRequest() -NO_FILTER_REQUEST_ISSUES = il.IssueListValidRequest() +class FakeGithubService(gs.AbstractGithubService): + """Fake Github Service.""" + + def fake_success(self, _: str) -> str: + """Fake success method.""" + return SUCCESS_MSG + + def fake_error(self, _: str) -> str: + """Fake expected error method.""" + raise gs.GithubServiceError(ERROR_MSG) + + def fake_unexpected_error(self, _: str) -> str: + """Fake expected error method.""" + raise Exception(ERROR_MSG) + + def create_pull_request_from_repo(self, _: str, __: pr.PullRequest) -> str: + """Fake create pull request from one repository.""" + return SUCCESS_MSG + + def list_issues_from_repo( + self, _: str, __: il.IssueListValidRequest | il.IssueListInvalidRequest + ) -> list[i.Issue]: + """Fake issues list method.""" + return DOMAIN_ISSUES + + @staticmethod + def link_issues(_: pr.PullRequest, __: list[i.Issue]) -> pr.PullRequest: + """Fake link issues method.""" + return pr.PullRequest( + "Title", "", set(), False, "query", False, "main", "origin", False + ) @pytest.fixture @@ -37,66 +74,6 @@ def domain_gh_conn_settings() -> list[cs.GhConnectionSettings]: return gh_conn_settings -@pytest.fixture -def domain_issues() -> list[i.Issue]: - """Issues fixture.""" - issues = [ - i.Issue( - 0, - "my issue title", - "my issue body", - {"testing", "refactor"}, - ), - i.Issue(2, "also doesnt match title", "body2", set()), - i.Issue(4, "doesnt match title", "body4", {"dontinherit"}), - i.Issue(3, "issue title", "body3", set()), - i.Issue(5, "pr match issue title", "body5", {"enhancement", "testing"}), - ] - return issues - - -@pytest.fixture -def domain_prs() -> list[pr.PullRequest]: - """Pull requests fixture.""" - prs = [ - pr.PullRequest( - "my pr title", - "my pr body", - set(), - False, - "", - False, - "main", - "branch", - False, - ), - pr.PullRequest( - "my pr title 2", - "my pr body 2", - {"testing", "refactor"}, - True, - "issue title", - True, - "main", - "branch", - False, - ), - ] - return prs - - -@pytest.fixture -def domain_mpr() -> mpr.PullRequestMerge: - """Pull request merge fixture.""" - return mpr.PullRequestMerge("branch", "main", "org name", False) - - -@pytest.fixture -def domain_branch() -> str: - """Branch fixture.""" - return "my-branch" - - @pytest.fixture def mock_github3_login(mocker: MockerFixture) -> MockerFixture: """Fixture for mocking github3.login.""" @@ -249,11 +226,10 @@ def test_get_username( def test_create_issue_from_repo_success( domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_issues: list[i.Issue], ) -> None: """It succeeds.""" response = gs.GithubService(domain_gh_conn_settings[0]).create_issue_from_repo( - REPO, domain_issues[0] + REPO, DOMAIN_ISSUES[0] ) assert response == f"{REPO}: create issue successful.\n" @@ -263,7 +239,6 @@ def test_create_issue_from_repo_fork( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_issues: list[i.Issue], ) -> None: """It gives a message error telling it is a fork.""" exception_mock = mocker.Mock() @@ -273,7 +248,7 @@ def test_create_issue_from_repo_fork( repo = mock_github3_login.return_value.repositories.return_value[1] repo.create_issue.side_effect = github3.exceptions.ClientError(exception_mock) response = gs.GithubService(domain_gh_conn_settings[0]).create_issue_from_repo( - REPO, domain_issues[0] + REPO, DOMAIN_ISSUES[0] ) assert response == f"{REPO}: Issues are disabled for this repo. It may be a fork.\n" @@ -283,7 +258,6 @@ def test_create_issue_from_repo_other_client_error( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_issues: list[i.Issue], ) -> None: """It gives the message error returned from the API.""" exception_mock = mocker.Mock() @@ -291,7 +265,7 @@ def test_create_issue_from_repo_other_client_error( repo = mock_github3_login.return_value.repositories.return_value[1] repo.create_issue.side_effect = github3.exceptions.ClientError(exception_mock) response = gs.GithubService(domain_gh_conn_settings[0]).create_issue_from_repo( - REPO, domain_issues[0] + REPO, DOMAIN_ISSUES[0] ) assert response == f"{REPO}: returned message.\n" @@ -301,7 +275,6 @@ def test_create_issue_from_repo_other_error( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_issues: list[i.Issue], ) -> None: """It gives the message error returned from the API.""" exception_mock = mocker.Mock() @@ -309,31 +282,30 @@ def test_create_issue_from_repo_other_error( repo = mock_github3_login.return_value.repositories.return_value[1] repo.create_issue.side_effect = github3.exceptions.ForbiddenError(exception_mock) - with pytest.raises(gs.GithubServiceError, match="org/repo-name: returned message"): + with pytest.raises(gs.GithubServiceError, match=f"{REPO}: returned message"): gs.GithubService(domain_gh_conn_settings[0]).create_issue_from_repo( - REPO, domain_issues[0] + REPO, DOMAIN_ISSUES[0] ) def test_list_issues_from_repo_title_filter( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], - domain_issues: list[i.Issue], mock_github3_login: MockerFixture, ) -> None: """It succeeds.""" label1 = mocker.Mock() - label1.name = "dontinherit" + label1.name = LABEL_DO_NOT_INHERIT label2 = mocker.Mock() - label2.name = "enhancement" + label2.name = LABEL_ENHANCEMENT label3 = mocker.Mock() - label3.name = "testing" + label3.name = LABEL_BUG - issue1 = mocker.Mock(title="issue title", number=3) - issue1.labels.return_value = [] - issue2 = mocker.Mock(title="doesnt match title", number=4) - issue2.labels.return_value = [label1] - issue3 = mocker.Mock(title="pr match issue title", number=5) + issue1 = mocker.Mock(number=DOMAIN_ISSUES[1].number, title=DOMAIN_ISSUES[1].title) + issue1.labels.return_value = [label1] + issue2 = mocker.Mock(number=DOMAIN_ISSUES[2].number, title=DOMAIN_ISSUES[2].title) + issue2.labels.return_value = [] + issue3 = mocker.Mock(number=DOMAIN_ISSUES[3].number, title=DOMAIN_ISSUES[3].title) issue3.labels.return_value = [label2, label3] repo = mock_github3_login.return_value.repositories.return_value[1] @@ -352,10 +324,10 @@ def test_list_issues_from_repo_title_filter( ) assert len(response) == 2 - assert response[0].number == domain_issues[3].number - assert response[0].title == domain_issues[3].title - assert response[1].number == domain_issues[4].number - assert response[1].title == domain_issues[4].title + assert response[0].number == DOMAIN_ISSUES[2].number + assert response[0].title == DOMAIN_ISSUES[2].title + assert response[1].number == DOMAIN_ISSUES[3].number + assert response[1].title == DOMAIN_ISSUES[3].title @pytest.mark.parametrize("value", ["issue", "pull request"]) @@ -363,19 +335,24 @@ def test_list_issues_from_repo_obj_filter( value: str, mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], - domain_issues: list[i.Issue], mock_github3_login: MockerFixture, ) -> None: """It succeeds.""" label1 = mocker.Mock() - label1.name = "enhancement" + label1.name = LABEL_ENHANCEMENT label2 = mocker.Mock() - label2.name = "testing" + label2.name = LABEL_BUG - issue1 = mocker.Mock(title="issue title", number=3, pull_request_urls=None) + issue1 = mocker.Mock( + number=DOMAIN_ISSUES[2].number, + title=DOMAIN_ISSUES[2].title, + pull_request_urls=None, + ) issue1.labels.return_value = [] issue2 = mocker.Mock( - title="pr match issue title", number=5, pull_request_urls="something" + number=DOMAIN_ISSUES[3].number, + title=DOMAIN_ISSUES[3].title, + pull_request_urls="something", ) issue2.labels.return_value = [label1, label2] @@ -395,21 +372,20 @@ def test_list_issues_from_repo_obj_filter( assert len(response) == 1 if value == "issue": - assert response[0].number == domain_issues[3].number - assert response[0].title == domain_issues[3].title + assert response[0].number == DOMAIN_ISSUES[2].number + assert response[0].title == DOMAIN_ISSUES[2].title if value == "pull request": - assert response[0].number == domain_issues[4].number - assert response[0].title == domain_issues[4].title + assert response[0].number == DOMAIN_ISSUES[3].number + assert response[0].title == DOMAIN_ISSUES[3].title def test_list_issues_from_repo_invalid_request( domain_gh_conn_settings: list[cs.GhConnectionSettings], - domain_issues: list[i.Issue], mock_github3_login: MockerFixture, ) -> None: """It returns empty result.""" response = gs.GithubService(domain_gh_conn_settings[0]).list_issues_from_repo( - REPO, INVALID_REQUEST_ISSUES + REPO, il.IssueListInvalidRequest() ) assert response == [] @@ -418,13 +394,12 @@ def test_list_issues_from_repo_invalid_request( def test_list_issues_from_repo_no_filter_request( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], - domain_issues: list[i.Issue], mock_github3_login: MockerFixture, ) -> None: """It returns empty result.""" - issue1 = mocker.Mock(title="issue title", number=3) + issue1 = mocker.Mock(number=DOMAIN_ISSUES[0].number, title=DOMAIN_ISSUES[0].title) issue1.labels.return_value = [] - issue2 = mocker.Mock(title="doesnt match title", number=4) + issue2 = mocker.Mock(number=DOMAIN_ISSUES[1].number, title=DOMAIN_ISSUES[1].title) issue2.labels.return_value = [] repo = mock_github3_login.return_value.repositories.return_value[1] repo.issues.return_value = [ @@ -433,25 +408,24 @@ def test_list_issues_from_repo_no_filter_request( ] response = gs.GithubService(domain_gh_conn_settings[0]).list_issues_from_repo( - REPO, NO_FILTER_REQUEST_ISSUES + REPO, il.IssueListValidRequest() ) assert len(response) == 2 - assert response[0].number == domain_issues[3].number - assert response[1].number == domain_issues[2].number - assert response[0].title == domain_issues[3].title - assert response[1].title == domain_issues[2].title + assert response[0].number == DOMAIN_ISSUES[0].number + assert response[0].title == DOMAIN_ISSUES[0].title + assert response[1].number == DOMAIN_ISSUES[1].number + assert response[1].title == DOMAIN_ISSUES[1].title def test_close_issues_from_repo_success( domain_gh_conn_settings: list[cs.GhConnectionSettings], - domain_issues: list[i.Issue], mock_github3_login: MockerFixture, ) -> None: """It succeeds.""" mock_github3_login.return_value.issue().is_closed.return_value = False response = gs.GithubService(domain_gh_conn_settings[0]).close_issues_from_repo( - REPO, domain_issues + REPO, DOMAIN_ISSUES ) assert response == f"{REPO}: close issues successful.\n" @@ -459,7 +433,6 @@ def test_close_issues_from_repo_success( def test_close_issues_from_repo_no_issue( domain_gh_conn_settings: list[cs.GhConnectionSettings], - domain_issues: list[i.Issue], mock_github3_login: MockerFixture, ) -> None: """It returns a not issue message.""" @@ -473,13 +446,12 @@ def test_close_issues_from_repo_no_issue( def test_close_issues_from_repo_already_closed( domain_gh_conn_settings: list[cs.GhConnectionSettings], - domain_issues: list[i.Issue], mock_github3_login: MockerFixture, ) -> None: """It succeeds.""" mock_github3_login.return_value.issue().is_closed.return_value = True response = gs.GithubService(domain_gh_conn_settings[0]).close_issues_from_repo( - REPO, domain_issues + REPO, DOMAIN_ISSUES ) assert response == f"{REPO}: close issues successful.\n" @@ -487,12 +459,11 @@ def test_close_issues_from_repo_already_closed( def test_reopen_issues_from_repo_success( domain_gh_conn_settings: list[cs.GhConnectionSettings], - domain_issues: list[i.Issue], mock_github3_login: MockerFixture, ) -> None: """It succeeds.""" response = gs.GithubService(domain_gh_conn_settings[0]).reopen_issues_from_repo( - REPO, domain_issues + REPO, DOMAIN_ISSUES ) assert response == f"{REPO}: reopen issues successful.\n" @@ -500,7 +471,6 @@ def test_reopen_issues_from_repo_success( def test_reopen_issues_from_repo_no_issue( domain_gh_conn_settings: list[cs.GhConnectionSettings], - domain_issues: list[i.Issue], mock_github3_login: MockerFixture, ) -> None: """It returns a not issue message.""" @@ -514,12 +484,11 @@ def test_reopen_issues_from_repo_no_issue( def test_create_pull_request_from_repo_success( domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_prs: list[pr.PullRequest], ) -> None: """It succeeds.""" response = gs.GithubService( domain_gh_conn_settings[0] - ).create_pull_request_from_repo(REPO, domain_prs[0]) + ).create_pull_request_from_repo(REPO, DOMAIN_PRS[0]) assert response == f"{REPO}: create PR successful.\n" @@ -527,12 +496,11 @@ def test_create_pull_request_from_repo_success( def test_create_pull_request_from_repo_with_labels( domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_prs: list[pr.PullRequest], ) -> None: """It succeeds.""" response = gs.GithubService( domain_gh_conn_settings[0] - ).create_pull_request_from_repo(REPO, domain_prs[1]) + ).create_pull_request_from_repo(REPO, DOMAIN_PRS[1]) assert response == f"{REPO}: create PR successful.\n" @@ -543,7 +511,6 @@ def test_create_pull_request_from_repo_invalid_branch( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_prs: list[pr.PullRequest], ) -> None: """It gives the message error informing the invalid field head.""" @@ -561,7 +528,7 @@ def _initiate_mocked_exception( repo.create_pull.side_effect = github3.exceptions.UnprocessableEntity response = gs.GithubService( domain_gh_conn_settings[0] - ).create_pull_request_from_repo(REPO, domain_prs[1]) + ).create_pull_request_from_repo(REPO, DOMAIN_PRS[1]) assert response == f"{REPO}: Validation Failed. Invalid field head.\n" @@ -571,7 +538,6 @@ def test_create_pull_request_from_repo_invalid_branch_unpatched_exception( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_prs: list[pr.PullRequest], ) -> None: """It gives the message error informing the invalid field head.""" mocked_response = mocker.Mock() @@ -586,7 +552,7 @@ def test_create_pull_request_from_repo_invalid_branch_unpatched_exception( ) response = gs.GithubService( domain_gh_conn_settings[0] - ).create_pull_request_from_repo(REPO, domain_prs[1]) + ).create_pull_request_from_repo(REPO, DOMAIN_PRS[1]) assert response == f"{REPO}: Validation Failed. Invalid field head.\n" @@ -597,7 +563,6 @@ def test_create_pull_request_from_repo_no_commits( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_prs: list[pr.PullRequest], ) -> None: """It gives the message error from the exception.""" @@ -615,7 +580,7 @@ def _initiate_mocked_exception( repo.create_pull.side_effect = github3.exceptions.UnprocessableEntity response = gs.GithubService( domain_gh_conn_settings[0] - ).create_pull_request_from_repo(REPO, domain_prs[1]) + ).create_pull_request_from_repo(REPO, DOMAIN_PRS[1]) assert response == ( f"{REPO}: Validation Failed. No commits between main and " "new-branch.\n" @@ -627,7 +592,6 @@ def test_create_pull_request_from_repo_no_commits_unpatched_exception( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_prs: list[pr.PullRequest], ) -> None: """It gives the message error from the exception.""" mocked_response = mocker.Mock() @@ -642,7 +606,7 @@ def test_create_pull_request_from_repo_no_commits_unpatched_exception( ) response = gs.GithubService( domain_gh_conn_settings[0] - ).create_pull_request_from_repo(REPO, domain_prs[1]) + ).create_pull_request_from_repo(REPO, DOMAIN_PRS[1]) assert response == ( f"{REPO}: Validation Failed. No commits between main and " "new-branch.\n" @@ -653,7 +617,6 @@ def test_create_pull_request_from_repo_other_error( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_prs: list[pr.PullRequest], ) -> None: """It gives the message error returned from the API.""" exception_mock = mocker.Mock() @@ -661,51 +624,45 @@ def test_create_pull_request_from_repo_other_error( repo = mock_github3_login.return_value.repositories.return_value[1] repo.create_pull.side_effect = github3.exceptions.ForbiddenError(exception_mock) - with pytest.raises(gs.GithubServiceError, match="org/repo-name: returned message"): + with pytest.raises(gs.GithubServiceError, match=f"{REPO}: returned message"): gs.GithubService(domain_gh_conn_settings[0]).create_pull_request_from_repo( - REPO, domain_prs[0] + REPO, DOMAIN_PRS[0] ) def test_link_issue_success( domain_gh_conn_settings: list[cs.GhConnectionSettings], - domain_issues: list[i.Issue], - domain_prs: list[pr.PullRequest], mock_github3_login: MockerFixture, ) -> None: """It succeeds.""" pr = gs.GithubService(domain_gh_conn_settings[0]).link_issues( - domain_prs[1], domain_issues[3:] + DOMAIN_PRS[1], DOMAIN_ISSUES[2:] ) - assert domain_prs[1].body == "my pr body 2" - assert pr.body == "my pr body 2\n\nCloses #3\nCloses #5\n" + assert pr.body == f"{DOMAIN_PRS[1].body}\n\nCloses #2\nCloses #3\n" case = unittest.TestCase() - case.assertCountEqual(domain_prs[1].labels, {"testing", "refactor"}) - case.assertCountEqual(pr.labels, {"testing", "refactor", "enhancement"}) + case.assertCountEqual(DOMAIN_PRS[1].labels, {LABEL_BUG}) + case.assertCountEqual(pr.labels, {LABEL_BUG, LABEL_ENHANCEMENT}) def test_link_issue_no_link( domain_gh_conn_settings: list[cs.GhConnectionSettings], - domain_issues: list[i.Issue], - domain_prs: list[pr.PullRequest], mock_github3_login: MockerFixture, ) -> None: """It succeeds without any linked issue.""" - gs.GithubService(domain_gh_conn_settings[0]).link_issues(domain_prs[1], []) + gs.GithubService(domain_gh_conn_settings[0]).link_issues(DOMAIN_PRS[1], []) - assert domain_prs[1].body == "my pr body 2" + assert DOMAIN_PRS[1].body == "my pr body 2" def test_delete_branch_from_repo_success( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_branch: str, ) -> None: """It succeeds.""" response = gs.GithubService(domain_gh_conn_settings[0]).delete_branch_from_repo( - REPO, domain_branch + REPO, BRANCH_NAME ) assert response == f"{REPO}: delete branch successful.\n" @@ -715,7 +672,6 @@ def test_delete_branch_from_repo_branch_not_found( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_branch: str, ) -> None: """It gives the message error returned from the API.""" @@ -732,7 +688,7 @@ def _initiate_mocked_exception( repo.ref.side_effect = github3.exceptions.NotFoundError response = gs.GithubService(domain_gh_conn_settings[0]).delete_branch_from_repo( - REPO, domain_branch + REPO, BRANCH_NAME ) assert response == f"{REPO}: Not found.\n" @@ -742,7 +698,6 @@ def test_delete_branch_from_repo_other_error( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_branch: str, ) -> None: """It gives the message error returned from the API.""" exception_mock = mocker.Mock() @@ -752,7 +707,7 @@ def test_delete_branch_from_repo_other_error( with pytest.raises(gs.GithubServiceError, match=f"{REPO}: returned message"): gs.GithubService(domain_gh_conn_settings[0]).delete_branch_from_repo( - REPO, domain_branch + REPO, BRANCH_NAME ) @@ -760,14 +715,13 @@ def test_merge_pull_request_from_repo_success( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_mpr: mpr.PullRequestMerge, ) -> None: """It succeeds.""" repo = mock_github3_login.return_value.repositories.return_value[1] repo.pull_requests.return_value = [mocker.Mock()] response = gs.GithubService( domain_gh_conn_settings[0] - ).merge_pull_request_from_repo(REPO, domain_mpr) + ).merge_pull_request_from_repo(REPO, DOMAIN_MPR) assert response == f"{REPO}: merge PR successful.\n" @@ -776,7 +730,6 @@ def test_merge_pull_request_from_repo_error_merging( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_mpr: mpr.PullRequestMerge, ) -> None: """It throws exception.""" repo = mock_github3_login.return_value.repositories.return_value[1] @@ -785,14 +738,13 @@ def test_merge_pull_request_from_repo_error_merging( repo.pull_requests.return_value = [pr] with pytest.raises(gs.GithubServiceError): gs.GithubService(domain_gh_conn_settings[0]).merge_pull_request_from_repo( - REPO, domain_mpr + REPO, DOMAIN_MPR ) def test_merge_pull_request_from_repo_not_found( domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_mpr: mpr.PullRequestMerge, ) -> None: """It gives error message.""" repo = mock_github3_login.return_value.repositories.return_value[1] @@ -802,7 +754,7 @@ def test_merge_pull_request_from_repo_not_found( gs.GithubServiceError, match=f"{REPO}: no open PR found for branch:main.\n" ): gs.GithubService(domain_gh_conn_settings[0]).merge_pull_request_from_repo( - REPO, domain_mpr + REPO, DOMAIN_MPR ) @@ -810,13 +762,12 @@ def test_merge_pull_request_from_repo_ambiguous( mocker: MockerFixture, domain_gh_conn_settings: list[cs.GhConnectionSettings], mock_github3_login: MockerFixture, - domain_mpr: mpr.PullRequestMerge, ) -> None: """It gives error message.""" repo = mock_github3_login.return_value.repositories.return_value[1] repo.pull_requests.return_value = [mocker.Mock(), mocker.Mock()] response = gs.GithubService( domain_gh_conn_settings[0] - ).merge_pull_request_from_repo(REPO, domain_mpr) + ).merge_pull_request_from_repo(REPO, DOMAIN_MPR) assert response == f"{REPO}: unexpected number of PRs for branch:main.\n" diff --git a/tests/test_main.py b/tests/test_main.py index f73bac11..abbf4fae 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,7 +1,10 @@ """Test cases for the __main__ module.""" +from __future__ import annotations + import pytest from click.testing import CliRunner from pytest_mock import MockerFixture +from tests.conftest import REPO import git_portfolio.__main__ import git_portfolio.domain.config as c @@ -9,10 +12,6 @@ import git_portfolio.responses as res -REPO = "org/repo-name" -REPO2 = "org/repo-name2" - - @pytest.fixture def runner() -> CliRunner: """Fixture for invoking command-line interfaces.""" @@ -151,8 +150,8 @@ def test_gitp_config_check_success( @git_portfolio.__main__.main.command("test") @git_portfolio.__main__.gitp_config_check - def _() -> res.ResponseSuccess: - return res.ResponseSuccess("success message") + def _() -> list[res.ResponseSuccess]: + return [res.ResponseSuccess("success message")] result = runner.invoke(git_portfolio.__main__.main, ["test"], prog_name="gitp") @@ -166,12 +165,12 @@ def test_gitp_config_check_execute_error( @git_portfolio.__main__.main.command("test") @git_portfolio.__main__.gitp_config_check - def _() -> res.ResponseFailure: - return res.ResponseFailure(res.ResponseTypes.SYSTEM_ERROR, "some error msg") + def _() -> list[res.ResponseFailure]: + return [res.ResponseFailure(res.ResponseTypes.SYSTEM_ERROR, "some error msg")] result = runner.invoke(git_portfolio.__main__.main, ["test"], prog_name="gitp") - assert "Error(s) found during execution:\nsome error msg" in result.output + assert "some error msg" in result.output assert result.exit_code == 4 diff --git a/tests/test_prompt.py b/tests/test_prompt.py index b70e5caa..8ea13484 100644 --- a/tests/test_prompt.py +++ b/tests/test_prompt.py @@ -1,6 +1,7 @@ """Test cases for user prompting module.""" import pytest from pytest_mock import MockerFixture +from tests.conftest import REPO import git_portfolio.domain.gh_connection_settings as gcs import git_portfolio.domain.issue as i @@ -9,10 +10,6 @@ import git_portfolio.prompt as p -REPO = "org/repo-name" -REPO2 = "org/repo-name2" - - @pytest.fixture def mock_inquirer_prompt(mocker: MockerFixture) -> MockerFixture: """Fixture for mocking inquirer.prompt.""" diff --git a/tests/test_views.py b/tests/test_views.py index 168c0540..c2808d2c 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -1,104 +1,58 @@ """Test cases for the Github list issue use case.""" from __future__ import annotations -import pytest from pytest_mock import MockerFixture +from tests.conftest import DOMAIN_ISSUES +from tests.conftest import REPO +from tests.test_github_service import FakeGithubService -import git_portfolio.domain.issue as i import git_portfolio.request_objects.issue_list as il import git_portfolio.responses as res import git_portfolio.views as views -REPO = "org/repo" - - -@pytest.fixture -def domain_issues() -> list[i.Issue]: - """Issues fixture.""" - issue_1 = i.Issue( - 0, - "my title", - "my body", - {"testing", "refactor"}, - ) - issue_2 = i.Issue( - 1, - "my title 2", - "my body2", - set(), - ) - return [issue_1, issue_2] - - -@pytest.fixture -def mock_github_service(mocker: MockerFixture) -> MockerFixture: - """Fixture for mocking GithubService.""" - mock = mocker.patch("git_portfolio.github_service.GithubService", autospec=True) - mock.return_value.list_issues_from_repo.return_value = "success message\n" - return mock - - -def test_action_without_parameters( - mock_github_service: MockerFixture, - domain_issues: list[i.Issue], -) -> None: +def test_action_without_parameters() -> None: """It returns a list of issues.""" - github_service = mock_github_service.return_value - github_service.list_issues_from_repo.return_value = domain_issues - request = il.build_list_request() - response = views.issues(REPO, github_service, request) + response = views.issues(REPO, FakeGithubService(), request) - assert bool(response) is True - assert response.value == domain_issues + assert isinstance(response, res.ResponseSuccess) + assert response.value == DOMAIN_ISSUES -def test_action_with_filters( - mock_github_service: MockerFixture, - domain_issues: list[i.Issue], -) -> None: +def test_action_with_filters() -> None: """It returns a list of issues.""" - github_service = mock_github_service.return_value - github_service.list_issues_from_repo.return_value = domain_issues - qry_filters = {"state__eq": "open"} request = il.build_list_request(filters=qry_filters) - response = views.issues(REPO, github_service, request) + response = views.issues(REPO, FakeGithubService(), request) - assert bool(response) is True - assert response.value == domain_issues + assert isinstance(response, res.ResponseSuccess) + assert response.value == DOMAIN_ISSUES -def test_action_handles_generic_error( - mock_github_service: MockerFixture, -) -> None: +def test_action_handles_generic_error(mocker: MockerFixture) -> None: """It returns a system error.""" - github_service = mock_github_service.return_value - github_service.list_issues_from_repo.side_effect = Exception( + mock = mocker.patch("git_portfolio.github_service.GithubService", autospec=True) + mock.return_value.list_issues_from_repo.side_effect = Exception( "Just an error message" ) request = il.build_list_request(filters={}) - response = views.issues(REPO, github_service, request) + response = views.issues(REPO, mock.return_value, request) - assert bool(response) is False + assert isinstance(response, res.ResponseFailure) assert response.value == { "type": res.ResponseTypes.SYSTEM_ERROR, "message": "Exception: Just an error message", } -def test_action_handles_bad_request( - mock_github_service: MockerFixture, -) -> None: +def test_action_handles_bad_request() -> None: """It returns a parameters error.""" - github_service = mock_github_service.return_value - request = il.build_list_request(filters=5) # type: ignore - response = views.issues(REPO, github_service, request) + response = views.issues(REPO, FakeGithubService(), request) - assert bool(response) is False + assert isinstance(response, res.ResponseFailure) assert response.value == { "type": res.ResponseTypes.PARAMETERS_ERROR, "message": "filters: Is not iterable", diff --git a/tests/use_cases/test_config_init.py b/tests/use_cases/test_config_init.py index c63fe475..676a775c 100644 --- a/tests/use_cases/test_config_init.py +++ b/tests/use_cases/test_config_init.py @@ -57,7 +57,7 @@ def test_execute_success( config_manager.config = mocker.Mock() response = ci.ConfigInitUseCase(config_manager).execute(domain_gh_conn_settings) - assert bool(response) is True + assert isinstance(response, res.ResponseSuccess) assert "gitp successfully configured." == response.value @@ -73,7 +73,7 @@ def test_execute_attribute_error( mock_github_service.side_effect = AttributeError("msg") response = ci.ConfigInitUseCase(config_manager).execute(domain_gh_conn_settings) - assert bool(response) is False + assert isinstance(response, res.ResponseFailure) assert response.type == res.ResponseTypes.PARAMETERS_ERROR assert response.value["message"] == "msg" @@ -90,7 +90,7 @@ def test_execute_connection_error( mock_github_service.side_effect = ConnectionError response = ci.ConfigInitUseCase(config_manager).execute(domain_gh_conn_settings) - assert bool(response) is False + assert isinstance(response, res.ResponseFailure) assert response.type == res.ResponseTypes.SYSTEM_ERROR assert ( response.value["message"] diff --git a/tests/use_cases/test_config_repos.py b/tests/use_cases/test_config_repos.py index 3ceee458..39d51f41 100644 --- a/tests/use_cases/test_config_repos.py +++ b/tests/use_cases/test_config_repos.py @@ -4,6 +4,7 @@ import git_portfolio.domain.config as c import git_portfolio.domain.gh_connection_settings as cs +import git_portfolio.responses as res import git_portfolio.use_cases.config_repos as cr @@ -33,5 +34,5 @@ def test_execute( domain_gh_conn_settings, ["user/repo"] ) - assert bool(response) is True + assert isinstance(response, res.ResponseSuccess) assert "gitp repositories successfully configured." == response.value diff --git a/tests/use_cases/test_gh.py b/tests/use_cases/test_gh.py index 01190d48..855fcaa4 100644 --- a/tests/use_cases/test_gh.py +++ b/tests/use_cases/test_gh.py @@ -1,14 +1,25 @@ """Test Github use case error handling.""" +from __future__ import annotations + import pytest from pytest_mock import MockerFixture +from tests.conftest import ERROR_MSG +from tests.conftest import REPO +from tests.conftest import REPO2 +from tests.conftest import SUCCESS_MSG +from tests.test_github_service import FakeGithubService import git_portfolio.domain.config as c -import git_portfolio.github_service as gs +import git_portfolio.responses as res import git_portfolio.use_cases.gh as gh -REPO = "org/repo-name" -REPO2 = "org/repo-name2" +class FakeGhUseCase(gh.GhUseCase): + """Github fake use case.""" + + def action(self, github_repo: str) -> None: # type: ignore[override] + """Fake action.""" + self.call_github_service("fake_success", github_repo) @pytest.fixture @@ -19,137 +30,71 @@ def mock_config_manager(mocker: MockerFixture) -> MockerFixture: return mock -@pytest.fixture -def mock_github_service(mocker: MockerFixture) -> MockerFixture: - """Fixture for mocking GithubService.""" - return mocker.patch("git_portfolio.github_service.GithubService", autospec=True) - - -@pytest.fixture -def mock_action(mocker: MockerFixture) -> MockerFixture: - """Fixture for mocking GhUseCase.action.""" - return mocker.patch("git_portfolio.use_cases.gh.GhUseCase.action") - - def test_call_github_service_ok( - mocker: MockerFixture, mock_config_manager: MockerFixture, - mock_github_service: MockerFixture, ) -> None: """It ouputs success message.""" config_manager = mock_config_manager.return_value - github_service = mock_github_service.return_value - github_service.create_issue_from_repo.return_value = "success message\n" - gh_use_case = gh.GhUseCase(config_manager, github_service) + gh_use_case = FakeGhUseCase(config_manager, FakeGithubService()) - gh_use_case.call_github_service( - "create_issue_from_repo", mocker.Mock(), mocker.Mock() - ) + response = gh_use_case.call_github_service("fake_success", REPO) - assert gh_use_case.output == "success message\n" + assert isinstance(response, res.ResponseSuccess) + assert response.value == SUCCESS_MSG def test_call_github_service_error( - mocker: MockerFixture, mock_config_manager: MockerFixture, - mock_github_service: MockerFixture, ) -> None: """It outputs error message from Github.""" config_manager = mock_config_manager.return_value - github_service = mock_github_service.return_value - github_service.create_issue_from_repo.side_effect = gs.GithubServiceError( - "some error" - ) - gh_use_case = gh.GhUseCase(config_manager, github_service) + gh_use_case = FakeGhUseCase(config_manager, FakeGithubService()) - gh_use_case.call_github_service( - "create_issue_from_repo", mocker.Mock(), mocker.Mock() - ) + response = gh_use_case.call_github_service("fake_error", REPO) - assert gh_use_case.output == "some error" + assert isinstance(response, res.ResponseFailure) + assert response.value["message"] == ERROR_MSG def test_call_github_service_unexpected_error( - mocker: MockerFixture, mock_config_manager: MockerFixture, - mock_github_service: MockerFixture, ) -> None: """It outputs instructions for issue creation.""" config_manager = mock_config_manager.return_value - github_service = mock_github_service.return_value - error_msg = "some error" - github_service.create_issue_from_repo.side_effect = Exception(error_msg) - gh_use_case = gh.GhUseCase(config_manager, github_service) + gh_use_case = FakeGhUseCase(config_manager, FakeGithubService()) - gh_use_case.call_github_service( - "create_issue_from_repo", mocker.Mock(), mocker.Mock() - ) + response = gh_use_case.call_github_service("fake_unexpected_error", REPO) - assert gh_use_case.output.startswith( + assert isinstance(response, res.ResponseFailure) + assert isinstance(response.value["message"], str) + assert response.value["message"].startswith( "An unexpected error occured. Please report at " ) - assert gh_use_case.output.endswith(f"{error_msg}\n") - - -def test_generate_response_success( - mock_config_manager: MockerFixture, mock_github_service: MockerFixture -) -> None: - """It returns a response success.""" - config_manager = mock_config_manager.return_value - github_service = mock_github_service.return_value - gh_use_case = gh.GhUseCase(config_manager, github_service) - gh_use_case.error = False - gh_use_case.output = "good output" - - response = gh_use_case.generate_response() - - assert bool(response) is True - assert response.value == "good output" - - -def test_generate_response_failure( - mock_config_manager: MockerFixture, mock_github_service: MockerFixture -) -> None: - """It returns a response failure.""" - config_manager = mock_config_manager.return_value - github_service = mock_github_service.return_value - gh_use_case = gh.GhUseCase(config_manager, github_service) - gh_use_case.error = True - gh_use_case.output = "bad output" - - response = gh_use_case.generate_response() - - assert bool(response) is False - assert response.value["message"] == "bad output" + assert response.value["message"].endswith(f"{ERROR_MSG}\n") def test_execute_for_all_repos( mock_config_manager: MockerFixture, - mock_github_service: MockerFixture, - mock_action: MockerFixture, ) -> None: """It returns success.""" config_manager = mock_config_manager.return_value - github_service = mock_github_service.return_value - gh_use_case = gh.GhUseCase(config_manager, github_service) + gh_use_case = FakeGhUseCase(config_manager, FakeGithubService()) - response = gh_use_case.execute() + responses = gh_use_case.execute() - assert mock_action.call_count == 2 - assert bool(response) is True + assert len(responses) == 2 + for response in responses: + assert bool(response) is True def test_execute_for_specific_repo( mock_config_manager: MockerFixture, - mock_github_service: MockerFixture, - mock_action: MockerFixture, ) -> None: """It returns success.""" config_manager = mock_config_manager.return_value - github_service = mock_github_service.return_value - gh_use_case = gh.GhUseCase(config_manager, github_service, REPO) + gh_use_case = FakeGhUseCase(config_manager, FakeGithubService(), REPO) - response = gh_use_case.execute() + responses = gh_use_case.execute() - assert mock_action.call_count == 1 - assert bool(response) is True + assert len(responses) == 1 + assert bool(responses[0]) is True diff --git a/tests/use_cases/test_gh_close_issue.py b/tests/use_cases/test_gh_close_issue.py index ea733f41..6ce7a29c 100644 --- a/tests/use_cases/test_gh_close_issue.py +++ b/tests/use_cases/test_gh_close_issue.py @@ -1,14 +1,13 @@ """Test cases for the Github close issue use case.""" import pytest from pytest_mock import MockerFixture +from tests.conftest import REPO import git_portfolio.domain.config as c import git_portfolio.request_objects.issue_list as il import git_portfolio.responses as res import git_portfolio.use_cases.gh_close_issue as ghci - -REPO = "org/repo-name" REQUEST_ISSUES = il.build_list_request( filters={"state__eq": "open", "title__contains": "title"} ) @@ -48,9 +47,12 @@ def test_action( github_service = mock_github_service.return_value mock_views_issues.return_value = res.ResponseSuccess() use_case = ghci.GhCloseIssueUseCase(config_manager, github_service) + use_case.action(REPO, REQUEST_ISSUES) + response = use_case.responses[0] - assert "success message\n" == use_case.output + assert isinstance(response, res.ResponseSuccess) + assert "success message\n" == response.value def test_action_failed( @@ -58,13 +60,16 @@ def test_action_failed( mock_github_service: MockerFixture, mock_views_issues: MockerFixture, ) -> None: - """It returns success.""" + """It returns error.""" config_manager = mock_config_manager.return_value github_service = mock_github_service.return_value mock_views_issues.return_value = res.ResponseFailure( - res.ResponseTypes.PARAMETERS_ERROR, "msg" + res.ResponseTypes.RESOURCE_ERROR, "msg" ) use_case = ghci.GhCloseIssueUseCase(config_manager, github_service) + use_case.action(REPO, REQUEST_ISSUES) + response = use_case.responses[0] - assert f"{REPO}: no issues match search.\n" == use_case.output + assert isinstance(response, res.ResponseFailure) + assert f"{REPO}: no issues match search.\n" == response.value["message"] diff --git a/tests/use_cases/test_gh_create_issue.py b/tests/use_cases/test_gh_create_issue.py index bdcae1a2..aa1d6169 100644 --- a/tests/use_cases/test_gh_create_issue.py +++ b/tests/use_cases/test_gh_create_issue.py @@ -1,16 +1,15 @@ """Test cases for the Github create issue use case.""" import pytest from pytest_mock import MockerFixture +from tests.conftest import DOMAIN_ISSUES +from tests.conftest import REPO +from tests.conftest import SUCCESS_MSG import git_portfolio.domain.config as c -import git_portfolio.domain.issue as i +import git_portfolio.responses as res import git_portfolio.use_cases.gh_create_issue as ghci -REPO = "org/repo-name" -REPO2 = "org/repo-name2" - - @pytest.fixture def mock_config_manager(mocker: MockerFixture) -> MockerFixture: """Fixture for mocking CONFIG_MANAGER.""" @@ -23,31 +22,21 @@ def mock_config_manager(mocker: MockerFixture) -> MockerFixture: def mock_github_service(mocker: MockerFixture) -> MockerFixture: """Fixture for mocking GithubService.""" mock = mocker.patch("git_portfolio.github_service.GithubService", autospec=True) - mock.return_value.create_issue_from_repo.return_value = "success message\n" + mock.return_value.create_issue_from_repo.return_value = SUCCESS_MSG return mock -@pytest.fixture -def domain_issue() -> i.Issue: - """Issue fixture.""" - issue = i.Issue( - 0, - "my title", - "my body", - {"testing", "refactor"}, - ) - return issue - - def test_action( mock_config_manager: MockerFixture, mock_github_service: MockerFixture, - domain_issue: i.Issue, ) -> None: """It returns success.""" config_manager = mock_config_manager.return_value github_service = mock_github_service.return_value use_case = ghci.GhCreateIssueUseCase(config_manager, github_service) - use_case.action(REPO, domain_issue) - assert "success message\n" == use_case.output + use_case.action(REPO, DOMAIN_ISSUES[0]) + response = use_case.responses[0] + + assert isinstance(response, res.ResponseSuccess) + assert SUCCESS_MSG == response.value diff --git a/tests/use_cases/test_gh_create_pr.py b/tests/use_cases/test_gh_create_pr.py index 463ff8a8..ba0cdd9b 100644 --- a/tests/use_cases/test_gh_create_pr.py +++ b/tests/use_cases/test_gh_create_pr.py @@ -3,15 +3,17 @@ import pytest from pytest_mock import MockerFixture +from tests.conftest import DOMAIN_PRS +from tests.conftest import REPO +from tests.conftest import SUCCESS_MSG +from tests.test_github_service import FakeGithubService import git_portfolio.domain.config as c -import git_portfolio.domain.pull_request as pr import git_portfolio.request_objects.issue_list as il import git_portfolio.responses as res import git_portfolio.use_cases.gh_create_pr as ghcp -REPO = "org/repo-name" REQUEST_ISSUES = il.build_list_request( filters={"state__eq": "open", "title__contains": "title"} ) @@ -25,14 +27,6 @@ def mock_config_manager(mocker: MockerFixture) -> MockerFixture: return mock -@pytest.fixture -def mock_github_service(mocker: MockerFixture) -> MockerFixture: - """Fixture for mocking GithubService.""" - mock = mocker.patch("git_portfolio.github_service.GithubService", autospec=True) - mock.return_value.create_pull_request_from_repo.return_value = "success message\n" - return mock - - @pytest.fixture def mock_views_issues(mocker: MockerFixture) -> MockerFixture: """Fixture for mocking views.issues.""" @@ -41,99 +35,69 @@ def mock_views_issues(mocker: MockerFixture) -> MockerFixture: ) -@pytest.fixture -def domain_prs() -> list[pr.PullRequest]: - """Pull requests fixture.""" - prs = [ - pr.PullRequest( - "my title", - "my body", - {"testing"}, - False, - "", - False, - "main", - "branch", - True, - ), - pr.PullRequest( - "my title", - "my body", - set(), - True, - "issue title", - True, - "main", - "branch", - True, - ), - ] - return prs +def test_action( + mock_config_manager: MockerFixture, +) -> None: + """It returns success.""" + config_manager = mock_config_manager.return_value + request = DOMAIN_PRS[0] + use_case = ghcp.GhCreatePrUseCase(config_manager, FakeGithubService()) + + use_case.action(REPO, request, REQUEST_ISSUES) + response = use_case.responses[0] + + assert isinstance(response, res.ResponseSuccess) + assert response.value == SUCCESS_MSG # TODO: improve output when issue list fails def test_action_link_issue_failed( mock_config_manager: MockerFixture, - mock_github_service: MockerFixture, mock_views_issues: MockerFixture, - domain_prs: list[pr.PullRequest], ) -> None: """It returns success.""" config_manager = mock_config_manager.return_value - github_service = mock_github_service.return_value mock_views_issues.return_value.action.return_value = res.ResponseFailure( res.ResponseTypes.PARAMETERS_ERROR, "msg" ) - request = domain_prs[1] - use_case = ghcp.GhCreatePrUseCase(config_manager, github_service) - use_case.action(REPO, request, REQUEST_ISSUES) - - assert "success message\n" == use_case.output + request = DOMAIN_PRS[1] + use_case = ghcp.GhCreatePrUseCase(config_manager, FakeGithubService()) - -def test_action( - mock_config_manager: MockerFixture, - mock_github_service: MockerFixture, - domain_prs: list[pr.PullRequest], -) -> None: - """It returns success.""" - config_manager = mock_config_manager.return_value - github_service = mock_github_service.return_value - request = domain_prs[0] - use_case = ghcp.GhCreatePrUseCase(config_manager, github_service) use_case.action(REPO, request, REQUEST_ISSUES) + response = use_case.responses[0] - assert "success message\n" == use_case.output + assert isinstance(response, res.ResponseSuccess) + assert response.value == SUCCESS_MSG def test_action_link_issue( mock_config_manager: MockerFixture, - mock_github_service: MockerFixture, mock_views_issues: MockerFixture, - domain_prs: list[pr.PullRequest], ) -> None: """It returns success.""" config_manager = mock_config_manager.return_value - github_service = mock_github_service.return_value mock_views_issues.return_value.action.return_value = res.ResponseSuccess() - request = domain_prs[1] - use_case = ghcp.GhCreatePrUseCase(config_manager, github_service) + request = DOMAIN_PRS[1] + use_case = ghcp.GhCreatePrUseCase(config_manager, FakeGithubService()) + use_case.action(REPO, request, REQUEST_ISSUES) + response = use_case.responses[0] - assert "success message\n" == use_case.output + assert isinstance(response, res.ResponseSuccess) + assert response.value == SUCCESS_MSG @pytest.mark.e2e def test_action_link_issue_e2e( mock_config_manager: MockerFixture, - mock_github_service: MockerFixture, - domain_prs: list[pr.PullRequest], ) -> None: """It returns success.""" config_manager = mock_config_manager.return_value - github_service = mock_github_service.return_value - request = domain_prs[1] - use_case = ghcp.GhCreatePrUseCase(config_manager, github_service) + request = DOMAIN_PRS[1] + use_case = ghcp.GhCreatePrUseCase(config_manager, FakeGithubService()) + use_case.action(REPO, request, REQUEST_ISSUES) + response = use_case.responses[0] - assert "success message\n" == use_case.output + assert isinstance(response, res.ResponseSuccess) + assert response.value == SUCCESS_MSG diff --git a/tests/use_cases/test_gh_delete_branch.py b/tests/use_cases/test_gh_delete_branch.py index f6471a81..06abef9a 100644 --- a/tests/use_cases/test_gh_delete_branch.py +++ b/tests/use_cases/test_gh_delete_branch.py @@ -1,14 +1,14 @@ """Test cases for the Github delete branch use case.""" import pytest from pytest_mock import MockerFixture +from tests.conftest import BRANCH_NAME +from tests.conftest import REPO import git_portfolio.domain.config as c +import git_portfolio.responses as res import git_portfolio.use_cases.gh_delete_branch as ghdb -REPO = "org/repo-name" - - @pytest.fixture def mock_config_manager(mocker: MockerFixture) -> MockerFixture: """Fixture for mocking CONFIG_MANAGER.""" @@ -25,21 +25,17 @@ def mock_github_service(mocker: MockerFixture) -> MockerFixture: return mock -@pytest.fixture -def domain_branch() -> str: - """Branch fixture.""" - return "my-branch" - - def test_action( mock_config_manager: MockerFixture, mock_github_service: MockerFixture, - domain_branch: str, ) -> None: """It returns success.""" config_manager = mock_config_manager.return_value github_service = mock_github_service.return_value use_case = ghdb.GhDeleteBranchUseCase(config_manager, github_service) - use_case.action(REPO, domain_branch) - assert "success message\n" == use_case.output + use_case.action(REPO, BRANCH_NAME) + response = use_case.responses[0] + + assert isinstance(response, res.ResponseSuccess) + assert "success message\n" == response.value diff --git a/tests/use_cases/test_gh_merge_pr.py b/tests/use_cases/test_gh_merge_pr.py index 72f00271..5a9960cf 100644 --- a/tests/use_cases/test_gh_merge_pr.py +++ b/tests/use_cases/test_gh_merge_pr.py @@ -3,15 +3,15 @@ import pytest from pytest_mock import MockerFixture +from tests.conftest import REPO import git_portfolio.domain.config as c import git_portfolio.domain.pull_request_merge as mpr +import git_portfolio.github_service as gs +import git_portfolio.responses as res import git_portfolio.use_cases.gh_merge_pr as ghmp -REPO = "org/repo-name" - - @pytest.fixture def mock_config_manager(mocker: MockerFixture) -> MockerFixture: """Fixture for mocking CONFIG_MANAGER.""" @@ -58,8 +58,10 @@ def test_action( use_case = ghmp.GhMergePrUseCase(config_manager, github_service) use_case.action(REPO, domain_mprs[0]) + response = use_case.responses[0] - assert "success message\n" == use_case.output + assert isinstance(response, res.ResponseSuccess) + assert "success message\n" == response.value def test_action_delete_branch( @@ -74,8 +76,10 @@ def test_action_delete_branch( use_case = ghmp.GhMergePrUseCase(config_manager, github_service) use_case.action(REPO, domain_mprs[1]) + response = use_case.responses[0] - assert "success message\n" == use_case.output + assert isinstance(response, res.ResponseSuccess) + assert "success message\n" == response.value mock_gh_delete_branch_use_case.assert_called_once() @@ -89,10 +93,12 @@ def test_action_delete_branch_with_error( config_manager = mock_config_manager.return_value github_service = mock_github_service.return_value use_case = ghmp.GhMergePrUseCase(config_manager, github_service) - use_case.error = True + github_service.merge_pull_request_from_repo.side_effect = gs.GithubServiceError use_case.action(REPO, domain_mprs[1]) + response = use_case.responses[0] + assert isinstance(response, res.ResponseFailure) assert not mock_gh_delete_branch_use_case.called @@ -108,6 +114,8 @@ def test_action_delete_branch_integration( use_case = ghmp.GhMergePrUseCase(config_manager, github_service) use_case.action(REPO, domain_mprs[1]) + response = use_case.responses[0] - assert "success message\n" == use_case.output + assert isinstance(response, res.ResponseSuccess) + assert "success message\n" == response.value github_service.delete_branch_from_repo.assert_called_once() diff --git a/tests/use_cases/test_gh_reopen_issue.py b/tests/use_cases/test_gh_reopen_issue.py index 7e9f50bc..03cf2b79 100644 --- a/tests/use_cases/test_gh_reopen_issue.py +++ b/tests/use_cases/test_gh_reopen_issue.py @@ -1,14 +1,13 @@ """Test cases for the Github reopen issue use case.""" import pytest from pytest_mock import MockerFixture +from tests.conftest import REPO import git_portfolio.domain.config as c import git_portfolio.request_objects.issue_list as il import git_portfolio.responses as res import git_portfolio.use_cases.gh_reopen_issue as ghri - -REPO = "org/repo-name" REQUEST_ISSUES = il.build_list_request( filters={"state__eq": "open", "title__contains": "title"} ) @@ -48,9 +47,12 @@ def test_action( github_service = mock_github_service.return_value mock_views_issues.return_value = res.ResponseSuccess() use_case = ghri.GhReopenIssueUseCase(config_manager, github_service) + use_case.action(REPO, REQUEST_ISSUES) + response = use_case.responses[0] - assert "success message\n" == use_case.output + assert isinstance(response, res.ResponseSuccess) + assert "success message\n" == response.value def test_action_failed( @@ -58,13 +60,16 @@ def test_action_failed( mock_github_service: MockerFixture, mock_views_issues: MockerFixture, ) -> None: - """It returns success.""" + """It returns error.""" config_manager = mock_config_manager.return_value github_service = mock_github_service.return_value mock_views_issues.return_value = res.ResponseFailure( - res.ResponseTypes.PARAMETERS_ERROR, "msg" + res.ResponseTypes.RESOURCE_ERROR, "msg" ) use_case = ghri.GhReopenIssueUseCase(config_manager, github_service) + use_case.action(REPO, REQUEST_ISSUES) + response = use_case.responses[0] - assert f"{REPO}: no issues match search.\n" == use_case.output + assert isinstance(response, res.ResponseFailure) + assert f"{REPO}: no issues match search.\n" == response.value["message"] diff --git a/tests/use_cases/test_git.py b/tests/use_cases/test_git.py index 6b18e88e..65238d44 100644 --- a/tests/use_cases/test_git.py +++ b/tests/use_cases/test_git.py @@ -1,7 +1,11 @@ """Test cases for git use case.""" import pytest from pytest_mock import MockerFixture +from tests.conftest import REPO +from tests.conftest import REPO2 +from tests.conftest import REPO_NAME +import git_portfolio.responses as res import git_portfolio.use_cases.git as git @@ -22,31 +26,31 @@ def mock_popen(mocker: MockerFixture) -> MockerFixture: def test_execute_success(mock_popen: MockerFixture) -> None: """It returns success messages.""" - response = git.GitUseCase().execute( - ["user/repo", "user/repo2"], "checkout", ("xx",) - ) + responses = git.GitUseCase().execute([REPO, REPO2], "checkout", ("xx",)) - assert bool(response) is True - assert response.value == "repo: some output\nrepo2: some output\n" + assert len(responses) == 2 + assert isinstance(responses[0], res.ResponseSuccess) + assert responses[0].value == f"{REPO_NAME}: some output\n" def test_execute_success_no_output(mock_popen: MockerFixture) -> None: """It returns success message.""" mock_popen.return_value.communicate.return_value = (b"", b"") # case where command success has no output with `gitp add .` - response = git.GitUseCase().execute(["user/repo", "user/repo2"], "add", (".",)) + responses = git.GitUseCase().execute([REPO, REPO2], "add", (".",)) - assert bool(response) is True - assert response.value == "repo: add successful.\nrepo2: add successful.\n" + assert len(responses) == 2 + assert isinstance(responses[0], res.ResponseSuccess) + assert responses[0].value == f"{REPO_NAME}: add successful.\n" def test_execute_git_not_installed(mock_command_checker: MockerFixture) -> None: """It returns failure with git not installed message.""" mock_command_checker.return_value = "error" - response = git.GitUseCase().execute(["user/dontcare"], "checkout", ("xx",)) + responses = git.GitUseCase().execute([REPO], "checkout", ("xx",)) - assert bool(response) is False - assert "error" == response.value["message"] + assert isinstance(responses[0], res.ResponseFailure) + assert "error" == responses[0].value["message"] def test_execute_no_folder( @@ -55,12 +59,15 @@ def test_execute_no_folder( """It returns error with msg file does not exist.""" mock_command_checker.return_value = "" mock_exception = FileNotFoundError(2, "No such file or directory") - mock_exception.filename = "/path/x" + mock_exception.filename = f"/path/{REPO_NAME}" mock_popen.side_effect = mock_exception - response = git.GitUseCase().execute(["user/x"], "checkout", ("xx",)) + responses = git.GitUseCase().execute([REPO], "checkout", ("xx",)) - assert bool(response) is False - assert response.value["message"] == "x: No such file or directory: /path/x\n" + assert isinstance(responses[0], res.ResponseFailure) + assert ( + responses[0].value["message"] + == f"{REPO_NAME}: No such file or directory: /path/{REPO_NAME}\n" + ) def test_execute_error_during_execution(mock_popen: MockerFixture) -> None: @@ -71,14 +78,12 @@ def test_execute_error_during_execution(mock_popen: MockerFixture) -> None: b"fatal: A branch named 'existingbranch' already exists.", ) # case where create branch already exists with `gitp checkout -b existingbranch` - response = git.GitUseCase().execute( - ["user/cloned"], "checkout", ("-b", "existingbranch") - ) + responses = git.GitUseCase().execute([REPO], "checkout", ("-b", "existingbranch")) - assert bool(response) is False + assert isinstance(responses[0], res.ResponseFailure) assert ( - response.value["message"] - == "cloned: fatal: A branch named 'existingbranch' already exists." + responses[0].value["message"] + == f"{REPO_NAME}: fatal: A branch named 'existingbranch' already exists." ) @@ -93,10 +98,10 @@ def test_execute_error_no_stderr(mock_popen: MockerFixture) -> None: b"", ) # case where is nothing to commit with `gitp commit` - response = git.GitUseCase().execute(["user/cloned"], "commit", ("",)) + responses = git.GitUseCase().execute([REPO], "commit", ("",)) - assert bool(response) is True - assert response.value == ( - "cloned: On branch main\nYour branch is up to date with 'origin/main'.\n\n" - "nothing to commit, working tree clean\n" + assert isinstance(responses[0], res.ResponseSuccess) + assert responses[0].value == ( + f"{REPO_NAME}: On branch main\nYour branch is up to date with 'origin/main'." + "\n\nnothing to commit, working tree clean\n" ) diff --git a/tests/use_cases/test_git_clone.py b/tests/use_cases/test_git_clone.py index fac54640..f8cf2fe1 100644 --- a/tests/use_cases/test_git_clone.py +++ b/tests/use_cases/test_git_clone.py @@ -3,7 +3,12 @@ import pytest from pytest_mock import MockerFixture +from tests.conftest import ERROR_MSG +from tests.conftest import REPO +from tests.conftest import REPO2 +from tests.conftest import REPO_NAME +import git_portfolio.responses as res from git_portfolio.use_cases import git_clone as gcuc @@ -38,10 +43,11 @@ def test_execute_success( ) -> None: """It returns success messages.""" github_service = mock_github_service.return_value - response = gcuc.GitCloneUseCase(github_service).execute(["user/repo", "user/repo2"]) + responses = gcuc.GitCloneUseCase(github_service).execute([REPO, REPO2]) - assert bool(response) is True - assert response.value == "repo: clone successful.\nrepo2: clone successful.\n" + assert len(responses) == 2 + assert isinstance(responses[0], res.ResponseSuccess) + assert responses[0].value == f"{REPO_NAME}: clone successful.\n" def test_execute_git_not_installed( @@ -49,13 +55,13 @@ def test_execute_git_not_installed( mock_command_checker: MockerFixture, ) -> None: """It returns failure with git not installed message.""" - mock_command_checker.return_value = "some error msg" + mock_command_checker.return_value = ERROR_MSG github_service = mock_github_service.return_value - response = gcuc.GitCloneUseCase(github_service).execute(["user/repo"]) + responses = gcuc.GitCloneUseCase(github_service).execute([REPO]) mock_command_checker.assert_called_with("git") - assert bool(response) is False - assert "some error msg" == response.value["message"] + assert isinstance(responses[0], res.ResponseFailure) + assert ERROR_MSG == responses[0].value["message"] @pytest.mark.e2e @@ -65,12 +71,12 @@ def test_execute_git_not_installed_e2e( """It returns failure with git not installed message.""" github_service = mock_github_service.return_value mock_popen.side_effect = FileNotFoundError - response = gcuc.GitCloneUseCase(github_service).execute(["user/repo"]) + responses = gcuc.GitCloneUseCase(github_service).execute([REPO]) - assert bool(response) is False + assert isinstance(responses[0], res.ResponseFailure) assert ( "This command requires git executable installed and on system path." - == response.value["message"] + == responses[0].value["message"] ) @@ -79,17 +85,20 @@ def test_execute_error_during_execution( mock_command_checker: MockerFixture, mock_popen: MockerFixture, ) -> None: - """It returns success message with the error on output.""" + """It returns error.""" github_service = mock_github_service.return_value mock_popen.return_value.returncode = 1 mock_popen().communicate.return_value = ( b"", - b"fatal: destination path 'x' already exists and is not an empty directory.\n", + ( + f"fatal: destination path '{REPO_NAME}' already exists and is not " + "an empty directory.\n" + ).encode(), ) - response = gcuc.GitCloneUseCase(github_service).execute(["user/x"]) + responses = gcuc.GitCloneUseCase(github_service).execute([REPO]) - assert bool(response) is True - assert response.value == ( - "x: fatal: destination path 'x' already exists and is not an empty " - "directory.\n" + assert isinstance(responses[0], res.ResponseFailure) + assert responses[0].value["message"] == ( + f"{REPO_NAME}: fatal: destination path '{REPO_NAME}' already exists and is not " + "an empty directory.\n" ) diff --git a/tests/use_cases/test_poetry.py b/tests/use_cases/test_poetry.py index e69ceace..2f048549 100644 --- a/tests/use_cases/test_poetry.py +++ b/tests/use_cases/test_poetry.py @@ -1,7 +1,11 @@ """Test cases for poetry use case.""" import pytest from pytest_mock import MockerFixture +from tests.conftest import REPO +from tests.conftest import REPO2 +from tests.conftest import REPO_NAME +import git_portfolio.responses as res import git_portfolio.use_cases.poetry as poetry @@ -25,12 +29,12 @@ def test_execute_success( ) -> None: """It returns success messages.""" mock_command_checker.return_value = "" - response = poetry.PoetryUseCase().execute( - ["user/repo", "user/repo2"], "poetry", ("version",) - ) - assert bool(response) is True - assert response.value == "repo: some output\nrepo2: some output\n" + responses = poetry.PoetryUseCase().execute([REPO, REPO2], "poetry", ("version",)) + + assert len(responses) == 2 + assert isinstance(responses[0], res.ResponseSuccess) + assert responses[0].value == f"{REPO_NAME}: some output\n" # TODO: this is only to maintain logic from git use case @@ -39,23 +43,23 @@ def test_execute_success( def test_execute_success_no_output(mock_popen: MockerFixture) -> None: """It returns success message.""" mock_popen.return_value.communicate.return_value = (b"", b"") - response = poetry.PoetryUseCase().execute( - ["user/repo", "user/repo2"], "poetry", ("someoptionwithoutoutput",) + + responses = poetry.PoetryUseCase().execute( + [REPO], "poetry", ("someoptionwithoutoutput",) ) - assert bool(response) is True - assert response.value == "repo: poetry successful.\nrepo2: poetry successful.\n" + assert isinstance(responses[0], res.ResponseSuccess) + assert responses[0].value == f"{REPO_NAME}: poetry successful.\n" def test_execute_poetry_not_installed(mock_command_checker: MockerFixture) -> None: """It returns failure with poetry not installed message.""" mock_command_checker.return_value = "error" - response = poetry.PoetryUseCase().execute( - ["user/notcloned"], "poetry", ("version",) - ) - assert bool(response) is False - assert "error" == response.value["message"] + responses = poetry.PoetryUseCase().execute([REPO], "poetry", ("version",)) + + assert isinstance(responses[0], res.ResponseFailure) + assert "error" == responses[0].value["message"] def test_execute_no_folder( @@ -66,10 +70,11 @@ def test_execute_no_folder( mock_exception = FileNotFoundError(2, "No such file or directory") mock_exception.filename = "/path/x" mock_popen.side_effect = mock_exception - response = poetry.PoetryUseCase().execute(["user/x"], "poetry", ("version",)) - assert bool(response) is False - assert response.value["message"] == "x: No such file or directory: /path/x\n" + responses = poetry.PoetryUseCase().execute(["user/x"], "poetry", ("version",)) + + assert isinstance(responses[0], res.ResponseFailure) + assert responses[0].value["message"] == "x: No such file or directory: /path/x\n" def test_execute_error_during_execution(mock_popen: MockerFixture) -> None: @@ -79,12 +84,10 @@ def test_execute_error_during_execution(mock_popen: MockerFixture) -> None: b"", b"error: pathspec 'xyz' did not match any file(s) known to poetry", ) - response = poetry.PoetryUseCase().execute( - ["user/notcloned"], "poetry", ("version",) - ) + responses = poetry.PoetryUseCase().execute([REPO], "poetry", ("version",)) - assert bool(response) is False - assert ( - response.value["message"] - == "notcloned: error: pathspec 'xyz' did not match any file(s) known to poetry" + assert isinstance(responses[0], res.ResponseFailure) + assert responses[0].value["message"] == ( + f"{REPO_NAME}: error: pathspec 'xyz' did not match any file(s) known to " + "poetry" )