Skip to content

Commit

Permalink
feat(GitOpsCli): optionally print JSON on deploy
Browse files Browse the repository at this point in the history
Add a command line option to print a JSON object containing an array
with long hashes of every commit made during deploy.
  • Loading branch information
Robert Grönsfeld committed Oct 14, 2022
1 parent 5f3a443 commit d091a7b
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 23 deletions.
2 changes: 2 additions & 0 deletions docs/commands/deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ optional arguments:
--merge-method MERGE_METHOD
Merge Method (e.g., 'squash', 'rebase', 'merge')
(default: merge)
--json
Print a JSON object containing deployment information
-v [VERBOSE], --verbose [VERBOSE]
Verbose exception logging
```
7 changes: 7 additions & 0 deletions gitopscli/cliparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ def __create_deploy_parser() -> ArgumentParser:
type=str,
default="merge",
)
parser.add_argument(
"--json",
help="Print a JSON object containing deployment information",
nargs="?",
type=__parse_bool,
default=False,
)
__add_verbose_arg(parser)
return parser

Expand Down
13 changes: 11 additions & 2 deletions gitopscli/commands/deploy.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import json
import logging
import uuid
from dataclasses import dataclass
from typing import Any, Dict, Optional, Tuple, Literal
from typing import Any, Dict, Optional, Tuple, Literal, List
from gitopscli.git_api import GitApiConfig, GitRepo, GitRepoApi, GitRepoApiFactory
from gitopscli.io_api.yaml_util import update_yaml_file, yaml_dump, YAMLException
from gitopscli.gitops_exception import GitOpsException
Expand All @@ -25,10 +26,13 @@ class Args(GitApiConfig):

create_pr: bool
auto_merge: bool
json: bool

merge_method: Literal["squash", "rebase", "merge"] = "merge"

def __init__(self, args: Args) -> None:
self.__args = args
self.__commit_hashes: List[str] = []

def execute(self) -> None:
git_repo_api = self.__create_git_repo_api()
Expand All @@ -54,6 +58,9 @@ def execute(self) -> None:
git_repo_api.merge_pull_request(pr_id, self.__args.merge_method)
git_repo_api.delete_branch(pr_branch)

if self.__args.json:
print(json.dumps({"commits": [{"hash": h} for h in self.__commit_hashes]}, indent=4))

def __create_git_repo_api(self) -> GitRepoApi:
return GitRepoApiFactory.create(self.__args, self.__args.organisation, self.__args.repository_name)

Expand Down Expand Up @@ -106,4 +113,6 @@ def __create_pull_request_title_and_description(self, updated_values: Dict[str,
return title, description

def __commit(self, git_repo: GitRepo, message: str) -> None:
git_repo.commit(self.__args.git_user, self.__args.git_email, message)
commit_hash = git_repo.commit(self.__args.git_user, self.__args.git_email, message)
if commit_hash:
self.__commit_hashes.append(commit_hash)
4 changes: 3 additions & 1 deletion gitopscli/git_api/git_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def new_branch(self, branch: str) -> None:
except GitError as ex:
raise GitOpsException(f"Error creating new branch '{branch}'.") from ex

def commit(self, git_user: str, git_email: str, message: str) -> None:
def commit(self, git_user: str, git_email: str, message: str) -> Optional[str]:
repo = self.__get_repo()
try:
repo.git.add("--all")
Expand All @@ -76,8 +76,10 @@ def commit(self, git_user: str, git_email: str, message: str) -> None:
repo.config_writer().set_value("user", "name", git_user).release()
repo.config_writer().set_value("user", "email", git_email).release()
repo.git.commit("-m", message, "--author", f"{git_user} <{git_email}>")
return str(repo.head.commit.hexsha)
except GitError as ex:
raise GitOpsException(f"Error creating commit.") from ex
return None

def push(self, branch: Optional[str] = None) -> None:
repo = self.__get_repo()
Expand Down
87 changes: 77 additions & 10 deletions tests/commands/test_deploy.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from io import StringIO
import logging
from textwrap import dedent
import uuid
import unittest
from uuid import UUID
from unittest import mock
from unittest.mock import call
from uuid import UUID
import pytest
from gitopscli.gitops_exception import GitOpsException
from gitopscli.commands.deploy import DeployCommand
Expand Down Expand Up @@ -40,13 +43,15 @@ def setUp(self):
self.git_repo_mock.__exit__.return_value = False
self.git_repo_mock.clone.return_value = None
self.git_repo_mock.new_branch.return_value = None
self.git_repo_mock.commit.return_value = None
self.example_commit_hash = "5f3a443e7ecb3723c1a71b9744e2993c0b6dfc00"
self.git_repo_mock.commit.return_value = self.example_commit_hash
self.git_repo_mock.push.return_value = None
self.git_repo_mock.get_full_file_path.side_effect = lambda x: f"/tmp/created-tmp-dir/{x}"

self.seal_mocks()

def test_happy_flow(self):
@mock.patch("sys.stdout", new_callable=StringIO)
def test_happy_flow(self, mock_print):
args = DeployCommand.Args(
file="test/file.yml",
values={"a.b.c": "foo", "a.b.d": "bar"},
Expand All @@ -62,6 +67,7 @@ def test_happy_flow(self):
git_provider=GitProvider.GITHUB,
git_provider_url=None,
commit_message=None,
json=False,
)
DeployCommand(args).execute()

Expand All @@ -79,7 +85,11 @@ def test_happy_flow(self):
call.GitRepo.push(),
]

def test_create_pr_single_value_change_happy_flow(self):
no_output = ""
self.assertMultiLineEqual(mock_print.getvalue(), no_output)

@mock.patch("sys.stdout", new_callable=StringIO)
def test_create_pr_single_value_change_happy_flow_with_output(self, mock_print):
args = DeployCommand.Args(
file="test/file.yml",
values={"a.b.c": "foo"},
Expand All @@ -95,6 +105,7 @@ def test_create_pr_single_value_change_happy_flow(self):
git_provider=GitProvider.GITHUB,
git_provider_url=None,
commit_message=None,
json=True,
)
DeployCommand(args).execute()

Expand All @@ -116,7 +127,19 @@ def test_create_pr_single_value_change_happy_flow(self):
),
]

def test_create_pr_multiple_value_changes_happy_flow(self):
expected_output = f"""\
{{
"commits": [
{{
"hash": "{self.example_commit_hash}"
}}
]
}}
"""
self.assertMultiLineEqual(mock_print.getvalue(), dedent(expected_output))

@mock.patch("sys.stdout", new_callable=StringIO)
def test_create_pr_multiple_value_changes_happy_flow_with_output(self, mock_print):
args = DeployCommand.Args(
file="test/file.yml",
values={"a.b.c": "foo", "a.b.d": "bar"},
Expand All @@ -132,6 +155,7 @@ def test_create_pr_multiple_value_changes_happy_flow(self):
git_provider=GitProvider.GITHUB,
git_provider_url=None,
commit_message=None,
json=True,
)
DeployCommand(args).execute()

Expand All @@ -156,7 +180,22 @@ def test_create_pr_multiple_value_changes_happy_flow(self):
),
]

def test_create_pr_and_merge_happy_flow(self):
expected_output = f"""\
{{
"commits": [
{{
"hash": "{self.example_commit_hash}"
}},
{{
"hash": "{self.example_commit_hash}"
}}
]
}}
"""
self.assertMultiLineEqual(mock_print.getvalue(), dedent(expected_output))

@mock.patch("sys.stdout", new_callable=StringIO)
def test_create_pr_and_merge_happy_flow(self, mock_print):
args = DeployCommand.Args(
file="test/file.yml",
values={"a.b.c": "foo", "a.b.d": "bar"},
Expand All @@ -172,6 +211,7 @@ def test_create_pr_and_merge_happy_flow(self):
git_provider=GitProvider.GITHUB,
git_provider_url=None,
commit_message=None,
json=False,
)
DeployCommand(args).execute()

Expand All @@ -198,7 +238,11 @@ def test_create_pr_and_merge_happy_flow(self):
call.GitRepoApi.delete_branch("gitopscli-deploy-b973b5bb"),
]

def test_single_commit_happy_flow(self):
no_output = ""
self.assertMultiLineEqual(mock_print.getvalue(), no_output)

@mock.patch("sys.stdout", new_callable=StringIO)
def test_single_commit_happy_flow(self, mock_print):
args = DeployCommand.Args(
file="test/file.yml",
values={"a.b.c": "foo", "a.b.d": "bar"},
Expand All @@ -214,6 +258,7 @@ def test_single_commit_happy_flow(self):
git_provider=GitProvider.GITHUB,
git_provider_url=None,
commit_message=None,
json=False,
)
DeployCommand(args).execute()

Expand All @@ -226,11 +271,19 @@ def test_single_commit_happy_flow(self):
call.logging.info("Updated yaml property %s to %s", "a.b.c", "foo"),
call.update_yaml_file("/tmp/created-tmp-dir/test/file.yml", "a.b.d", "bar"),
call.logging.info("Updated yaml property %s to %s", "a.b.d", "bar"),
call.GitRepo.commit("GIT_USER", "GIT_EMAIL", "updated 2 values in test/file.yml\n\na.b.c: foo\na.b.d: bar"),
call.GitRepo.commit(
"GIT_USER",
"GIT_EMAIL",
"updated 2 values in test/file.yml\n\na.b.c: foo\na.b.d: bar",
),
call.GitRepo.push(),
]

def test_single_commit_single_value_change_happy_flow(self):
no_output = ""
self.assertMultiLineEqual(mock_print.getvalue(), no_output)

@mock.patch("sys.stdout", new_callable=StringIO)
def test_single_commit_single_value_change_happy_flow(self, mock_print):
args = DeployCommand.Args(
file="test/file.yml",
values={"a.b.c": "foo"},
Expand All @@ -246,6 +299,7 @@ def test_single_commit_single_value_change_happy_flow(self):
git_provider=GitProvider.GITHUB,
git_provider_url=None,
commit_message=None,
json=False,
)
DeployCommand(args).execute()

Expand All @@ -260,7 +314,11 @@ def test_single_commit_single_value_change_happy_flow(self):
call.GitRepo.push(),
]

def test_commit_message_multiple_value_changes_happy_flow(self):
no_output = ""
self.assertMultiLineEqual(mock_print.getvalue(), no_output)

@mock.patch("sys.stdout", new_callable=StringIO)
def test_commit_message_multiple_value_changes_happy_flow(self, mock_print):
args = DeployCommand.Args(
file="test/file.yml",
values={"a.b.c": "foo", "a.b.d": "bar"},
Expand All @@ -276,6 +334,7 @@ def test_commit_message_multiple_value_changes_happy_flow(self):
git_provider=GitProvider.GITHUB,
git_provider_url=None,
commit_message="testcommit",
json=False,
)
DeployCommand(args).execute()

Expand All @@ -292,6 +351,9 @@ def test_commit_message_multiple_value_changes_happy_flow(self):
call.GitRepo.push(),
]

no_output = ""
self.assertEqual(mock_print.getvalue(), no_output)

def test_clone_error(self):
clone_exception = GitOpsException("dummy clone error")
self.git_repo_mock.clone.side_effect = clone_exception
Expand All @@ -311,6 +373,7 @@ def test_clone_error(self):
git_provider=GitProvider.GITHUB,
git_provider_url=None,
commit_message=None,
json=False,
)
with pytest.raises(GitOpsException) as ex:
DeployCommand(args).execute()
Expand Down Expand Up @@ -340,6 +403,7 @@ def test_file_not_found(self):
git_provider=GitProvider.GITHUB,
git_provider_url=None,
commit_message=None,
json=False,
)
with pytest.raises(GitOpsException) as ex:
DeployCommand(args).execute()
Expand Down Expand Up @@ -371,6 +435,7 @@ def test_file_parse_error(self):
git_provider=GitProvider.GITHUB,
git_provider_url=None,
commit_message=None,
json=False,
)
with pytest.raises(GitOpsException) as ex:
DeployCommand(args).execute()
Expand Down Expand Up @@ -402,6 +467,7 @@ def test_key_not_found(self):
git_provider=GitProvider.GITHUB,
git_provider_url=None,
commit_message=None,
json=False,
)
with pytest.raises(GitOpsException) as ex:
DeployCommand(args).execute()
Expand Down Expand Up @@ -433,6 +499,7 @@ def test_nothing_to_update(self):
git_provider=GitProvider.GITHUB,
git_provider_url=None,
commit_message=None,
json=False,
)
DeployCommand(args).execute()

Expand Down
Loading

0 comments on commit d091a7b

Please sign in to comment.