Skip to content

Commit

Permalink
fix: handling of aws and git failures
Browse files Browse the repository at this point in the history
By catching the stderr and error codes from the aws and git executions we render a proper error message.

Issue: #26
  • Loading branch information
Joris Conijn committed Feb 20, 2022
1 parent 539406c commit 522ae56
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 18 deletions.
17 changes: 10 additions & 7 deletions pull_request_codecommit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@ def main(
"""
pull-request-codecommit
"""
repo = __load_repository(repository_path=repository_path, target_branch=branch)
__display_repository_information(repo)
pr = __create_pull_request(repo)

if auto_merge:
status = pr.merge()
click.echo(f"Auto merging resulted in: {status}")
try:
repo = __load_repository(repository_path=repository_path, target_branch=branch)
__display_repository_information(repo)
pr = __create_pull_request(repo)

if auto_merge:
status = pr.merge()
click.echo(f"Auto merging resulted in: {status}")
except Exception as exception:
raise click.ClickException(str(exception))


def __load_repository(
Expand Down
11 changes: 10 additions & 1 deletion pull_request_codecommit/aws/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,16 @@ def base_command(self) -> List[str]:
def __execute(self, parameters: List[str]) -> str:
command = self.base_command
command.extend(parameters)
response = subprocess.run(command, stdout=subprocess.PIPE)
response = subprocess.run(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)

if response.returncode != 0:
message = response.stderr.decode("utf-8").strip("\n")
last_line = message.splitlines()[-1]
raise Exception(
f"Failed to execute: `{command}`\n\n{last_line}\n\nYou can execute the command manually to troubleshoot!"
)

return response.stdout.decode("utf-8").strip("\n")

Expand Down
15 changes: 14 additions & 1 deletion pull_request_codecommit/git/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,23 @@ def __init__(self, path: str):

def __execute(self, parameters: List[str]) -> str:
parameters.insert(0, "git")
response = subprocess.run(parameters, cwd=self.__path, stdout=subprocess.PIPE)
response = subprocess.run(
parameters, cwd=self.__path, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)

if response.returncode != 0:
last_line = self.__resolve_error_message(response.stderr)
command = " ".join(parameters)
raise Exception(
f"Failed to execute: `{command}`\n\n{last_line}\n\nYou can execute the command manually to troubleshoot!"
)

return response.stdout.decode("utf-8").strip("\n")

def __resolve_error_message(self, stderr: bytes) -> str:
message = stderr.decode("utf-8").strip("\n")
return message.splitlines()[-1]

def remote(self, name: str = "origin") -> str:
return self.__execute(["config", "--get", f"remote.{name}.url"])

Expand Down
42 changes: 41 additions & 1 deletion tests/test_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ def edit_message(message: str) -> str:
return message


def aws_client_execute_side_effect(parameters, stdout) -> MagicMock:
def aws_client_execute_side_effect(parameters, stdout, stderr) -> MagicMock:
data: Dict[str, Any] = {}
assert -1 == stdout
mock_stdout = MagicMock()
mock_stdout.returncode = 0

if "create-pull-request" in parameters:
data = {"pullRequest": {"pullRequestId": "1"}}
Expand Down Expand Up @@ -250,3 +251,42 @@ def test_invoke_no_repository_name(
result = runner.invoke(main)
assert result.exit_code == 1
assert "Error: The repository is not compatible with this tool!" in result.output


@pytest.mark.parametrize(
"remote, region, profile, config, commits, parameters",
generate_invoke_parameters([[]]),
)
@patch("pull_request_codecommit.aws.client.subprocess.run")
@patch("pull_request_codecommit.repository.GitClient")
@patch("pull_request_codecommit.click.edit")
def test_aws_failure(
mock_edit: MagicMock,
mock_git_client: MagicMock,
mock_aws_client: MagicMock,
remote: str,
region: str,
profile: str,
config: bytes,
commits: str,
parameters: List[str],
) -> None:
mock_edit.side_effect = edit_message
mock_git_client.return_value.get_commit_messages.return_value = Commits(commits)

mock_git_client.return_value.remote.return_value = remote
mock_git_client.return_value.current_branch = "feat/my-feature"

def side_effect(parameters, stdout, stderr):
data = {}
mock_stdout = MagicMock()
mock_stdout.stderr = bytes("Some aws failure", "utf-8")
mock_stdout.returncode = 1
return mock_stdout

configparser.open = MagicMock(return_value=TextIOWrapper(BytesIO(config))) # type: ignore
mock_aws_client.side_effect = side_effect

runner = CliRunner()
result = runner.invoke(main, parameters)
assert result.exit_code == 1
54 changes: 46 additions & 8 deletions tests/test_git_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ def test_remote(
) -> None:
mock_isdir.return_value = True

def execute(parameters, cwd, stdout):
def execute(parameters, cwd, stdout, stderr):
assert path == cwd
assert -1 == stdout
assert -1 == stderr
mock_stdout = MagicMock()
mock_stdout.stdout = bytes(f"\n\n{remote}\n\n", "utf-8")
mock_stdout.returncode = 0
return mock_stdout

mock_run.side_effect = execute
Expand Down Expand Up @@ -62,11 +64,13 @@ def test_current_branch(
) -> None:
mock_isdir.return_value = True

def execute(parameters, cwd, stdout):
def execute(parameters, cwd, stdout, stderr):
assert path == cwd
assert -1 == stdout
assert -1 == stderr
mock_stdout = MagicMock()
mock_stdout.stdout = bytes(f"\n\n{branch}\n\n", "utf-8")
mock_stdout.returncode = 0
return mock_stdout

mock_run.side_effect = execute
Expand All @@ -91,11 +95,13 @@ def test_get_commit_messages(
) -> None:
mock_isdir.return_value = True

def execute(parameters, cwd, stdout):
def execute(parameters, cwd, stdout, stderr):
assert path == cwd
assert -1 == stdout
assert -1 == stderr
mock_stdout = MagicMock()
mock_stdout.stdout = bytes(COMMITS, "utf-8")
mock_stdout.returncode = 0
return mock_stdout

mock_run.side_effect = execute
Expand All @@ -116,10 +122,12 @@ def execute(parameters, cwd, stdout):
def test_get_no_commit_messages(mock_isdir: MagicMock, mock_run: MagicMock) -> None:
mock_isdir.return_value = True

def execute(parameters, cwd, stdout):
def execute(parameters, cwd, stdout, stderr):
assert -1 == stdout
assert -1 == stderr
mock_stdout = MagicMock()
mock_stdout.stdout = bytes("", "utf-8")
mock_stdout.returncode = 0
return mock_stdout

mock_run.side_effect = execute
Expand All @@ -134,11 +142,13 @@ def execute(parameters, cwd, stdout):
def test_push(mock_isdir: MagicMock, mock_run: MagicMock) -> None:
mock_isdir.return_value = True

def execute(parameters, cwd, stdout):
def execute(parameters, cwd, stdout, stderr):
assert parameters == ["git", "push", "--set-upstream", "origin", "HEAD"]
assert -1 == stdout
assert -1 == stderr
mock_stdout = MagicMock()
mock_stdout.stdout = bytes("", "utf-8")
mock_stdout.returncode = 0
return mock_stdout

mock_run.side_effect = execute
Expand All @@ -150,11 +160,13 @@ def execute(parameters, cwd, stdout):
def test_pull(mock_isdir: MagicMock, mock_run: MagicMock) -> None:
mock_isdir.return_value = True

def execute(parameters, cwd, stdout):
def execute(parameters, cwd, stdout, stderr):
assert parameters == ["git", "pull"]
assert -1 == stdout
assert -1 == stderr
mock_stdout = MagicMock()
mock_stdout.stdout = bytes("", "utf-8")
mock_stdout.returncode = 0
return mock_stdout

mock_run.side_effect = execute
Expand All @@ -166,11 +178,13 @@ def execute(parameters, cwd, stdout):
def test_delete_branch(mock_isdir: MagicMock, mock_run: MagicMock) -> None:
mock_isdir.return_value = True

def execute(parameters, cwd, stdout):
def execute(parameters, cwd, stdout, stderr):
assert parameters == ["git", "branch", "-d", "feat/my-feature"]
assert -1 == stdout
assert -1 == stderr
mock_stdout = MagicMock()
mock_stdout.stdout = bytes("", "utf-8")
mock_stdout.returncode = 0
return mock_stdout

mock_run.side_effect = execute
Expand All @@ -182,12 +196,36 @@ def execute(parameters, cwd, stdout):
def test_checkout(mock_isdir: MagicMock, mock_run: MagicMock) -> None:
mock_isdir.return_value = True

def execute(parameters, cwd, stdout):
def execute(parameters, cwd, stdout, stderr):
assert parameters == ["git", "checkout", "master"]
assert -1 == stdout
assert -1 == stderr
mock_stdout = MagicMock()
mock_stdout.stdout = bytes("", "utf-8")
mock_stdout.returncode = 0
return mock_stdout

mock_run.side_effect = execute
Client("my-path").checkout("master")


@patch("pull_request_codecommit.git.client.subprocess.run")
@patch("pull_request_codecommit.git.client.os.path.isdir")
def test_git_failure(mock_isdir: MagicMock, mock_run: MagicMock) -> None:
mock_isdir.return_value = True

def execute(parameters, cwd, stdout, stderr):
assert parameters == ["git", "checkout", "master"]
assert -1 == stdout
assert -1 == stderr
mock_stdout = MagicMock()
mock_stdout.stderr = bytes("some git failure", "utf-8")
mock_stdout.returncode = 1
return mock_stdout

mock_run.side_effect = execute

with pytest.raises(Exception) as exception:
Client("my-path").checkout("master")

assert "some git failure" in str(exception.value)

0 comments on commit 522ae56

Please sign in to comment.