Skip to content

Commit f5540c4

Browse files
feat(deploy): Add option to print commit information as JSON
Add a command line option to print a JSON object containing an array with long hashes of every commit made during deploy.
2 parents 5f3a443 + d091a7b commit f5540c4

File tree

7 files changed

+128
-23
lines changed

7 files changed

+128
-23
lines changed

docs/commands/deploy.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ optional arguments:
165165
--merge-method MERGE_METHOD
166166
Merge Method (e.g., 'squash', 'rebase', 'merge')
167167
(default: merge)
168+
--json
169+
Print a JSON object containing deployment information
168170
-v [VERBOSE], --verbose [VERBOSE]
169171
Verbose exception logging
170172
```

gitopscli/cliparser.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,13 @@ def __create_deploy_parser() -> ArgumentParser:
105105
type=str,
106106
default="merge",
107107
)
108+
parser.add_argument(
109+
"--json",
110+
help="Print a JSON object containing deployment information",
111+
nargs="?",
112+
type=__parse_bool,
113+
default=False,
114+
)
108115
__add_verbose_arg(parser)
109116
return parser
110117

gitopscli/commands/deploy.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import json
12
import logging
23
import uuid
34
from dataclasses import dataclass
4-
from typing import Any, Dict, Optional, Tuple, Literal
5+
from typing import Any, Dict, Optional, Tuple, Literal, List
56
from gitopscli.git_api import GitApiConfig, GitRepo, GitRepoApi, GitRepoApiFactory
67
from gitopscli.io_api.yaml_util import update_yaml_file, yaml_dump, YAMLException
78
from gitopscli.gitops_exception import GitOpsException
@@ -25,10 +26,13 @@ class Args(GitApiConfig):
2526

2627
create_pr: bool
2728
auto_merge: bool
29+
json: bool
30+
2831
merge_method: Literal["squash", "rebase", "merge"] = "merge"
2932

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

3337
def execute(self) -> None:
3438
git_repo_api = self.__create_git_repo_api()
@@ -54,6 +58,9 @@ def execute(self) -> None:
5458
git_repo_api.merge_pull_request(pr_id, self.__args.merge_method)
5559
git_repo_api.delete_branch(pr_branch)
5660

61+
if self.__args.json:
62+
print(json.dumps({"commits": [{"hash": h} for h in self.__commit_hashes]}, indent=4))
63+
5764
def __create_git_repo_api(self) -> GitRepoApi:
5865
return GitRepoApiFactory.create(self.__args, self.__args.organisation, self.__args.repository_name)
5966

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

108115
def __commit(self, git_repo: GitRepo, message: str) -> None:
109-
git_repo.commit(self.__args.git_user, self.__args.git_email, message)
116+
commit_hash = git_repo.commit(self.__args.git_user, self.__args.git_email, message)
117+
if commit_hash:
118+
self.__commit_hashes.append(commit_hash)

gitopscli/git_api/git_repo.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def new_branch(self, branch: str) -> None:
6767
except GitError as ex:
6868
raise GitOpsException(f"Error creating new branch '{branch}'.") from ex
6969

70-
def commit(self, git_user: str, git_email: str, message: str) -> None:
70+
def commit(self, git_user: str, git_email: str, message: str) -> Optional[str]:
7171
repo = self.__get_repo()
7272
try:
7373
repo.git.add("--all")
@@ -76,8 +76,10 @@ def commit(self, git_user: str, git_email: str, message: str) -> None:
7676
repo.config_writer().set_value("user", "name", git_user).release()
7777
repo.config_writer().set_value("user", "email", git_email).release()
7878
repo.git.commit("-m", message, "--author", f"{git_user} <{git_email}>")
79+
return str(repo.head.commit.hexsha)
7980
except GitError as ex:
8081
raise GitOpsException(f"Error creating commit.") from ex
82+
return None
8183

8284
def push(self, branch: Optional[str] = None) -> None:
8385
repo = self.__get_repo()

tests/commands/test_deploy.py

Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
from io import StringIO
12
import logging
3+
from textwrap import dedent
24
import uuid
35
import unittest
4-
from uuid import UUID
6+
from unittest import mock
57
from unittest.mock import call
8+
from uuid import UUID
69
import pytest
710
from gitopscli.gitops_exception import GitOpsException
811
from gitopscli.commands.deploy import DeployCommand
@@ -40,13 +43,15 @@ def setUp(self):
4043
self.git_repo_mock.__exit__.return_value = False
4144
self.git_repo_mock.clone.return_value = None
4245
self.git_repo_mock.new_branch.return_value = None
43-
self.git_repo_mock.commit.return_value = None
46+
self.example_commit_hash = "5f3a443e7ecb3723c1a71b9744e2993c0b6dfc00"
47+
self.git_repo_mock.commit.return_value = self.example_commit_hash
4448
self.git_repo_mock.push.return_value = None
4549
self.git_repo_mock.get_full_file_path.side_effect = lambda x: f"/tmp/created-tmp-dir/{x}"
4650

4751
self.seal_mocks()
4852

49-
def test_happy_flow(self):
53+
@mock.patch("sys.stdout", new_callable=StringIO)
54+
def test_happy_flow(self, mock_print):
5055
args = DeployCommand.Args(
5156
file="test/file.yml",
5257
values={"a.b.c": "foo", "a.b.d": "bar"},
@@ -62,6 +67,7 @@ def test_happy_flow(self):
6267
git_provider=GitProvider.GITHUB,
6368
git_provider_url=None,
6469
commit_message=None,
70+
json=False,
6571
)
6672
DeployCommand(args).execute()
6773

@@ -79,7 +85,11 @@ def test_happy_flow(self):
7985
call.GitRepo.push(),
8086
]
8187

82-
def test_create_pr_single_value_change_happy_flow(self):
88+
no_output = ""
89+
self.assertMultiLineEqual(mock_print.getvalue(), no_output)
90+
91+
@mock.patch("sys.stdout", new_callable=StringIO)
92+
def test_create_pr_single_value_change_happy_flow_with_output(self, mock_print):
8393
args = DeployCommand.Args(
8494
file="test/file.yml",
8595
values={"a.b.c": "foo"},
@@ -95,6 +105,7 @@ def test_create_pr_single_value_change_happy_flow(self):
95105
git_provider=GitProvider.GITHUB,
96106
git_provider_url=None,
97107
commit_message=None,
108+
json=True,
98109
)
99110
DeployCommand(args).execute()
100111

@@ -116,7 +127,19 @@ def test_create_pr_single_value_change_happy_flow(self):
116127
),
117128
]
118129

119-
def test_create_pr_multiple_value_changes_happy_flow(self):
130+
expected_output = f"""\
131+
{{
132+
"commits": [
133+
{{
134+
"hash": "{self.example_commit_hash}"
135+
}}
136+
]
137+
}}
138+
"""
139+
self.assertMultiLineEqual(mock_print.getvalue(), dedent(expected_output))
140+
141+
@mock.patch("sys.stdout", new_callable=StringIO)
142+
def test_create_pr_multiple_value_changes_happy_flow_with_output(self, mock_print):
120143
args = DeployCommand.Args(
121144
file="test/file.yml",
122145
values={"a.b.c": "foo", "a.b.d": "bar"},
@@ -132,6 +155,7 @@ def test_create_pr_multiple_value_changes_happy_flow(self):
132155
git_provider=GitProvider.GITHUB,
133156
git_provider_url=None,
134157
commit_message=None,
158+
json=True,
135159
)
136160
DeployCommand(args).execute()
137161

@@ -156,7 +180,22 @@ def test_create_pr_multiple_value_changes_happy_flow(self):
156180
),
157181
]
158182

159-
def test_create_pr_and_merge_happy_flow(self):
183+
expected_output = f"""\
184+
{{
185+
"commits": [
186+
{{
187+
"hash": "{self.example_commit_hash}"
188+
}},
189+
{{
190+
"hash": "{self.example_commit_hash}"
191+
}}
192+
]
193+
}}
194+
"""
195+
self.assertMultiLineEqual(mock_print.getvalue(), dedent(expected_output))
196+
197+
@mock.patch("sys.stdout", new_callable=StringIO)
198+
def test_create_pr_and_merge_happy_flow(self, mock_print):
160199
args = DeployCommand.Args(
161200
file="test/file.yml",
162201
values={"a.b.c": "foo", "a.b.d": "bar"},
@@ -172,6 +211,7 @@ def test_create_pr_and_merge_happy_flow(self):
172211
git_provider=GitProvider.GITHUB,
173212
git_provider_url=None,
174213
commit_message=None,
214+
json=False,
175215
)
176216
DeployCommand(args).execute()
177217

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

201-
def test_single_commit_happy_flow(self):
241+
no_output = ""
242+
self.assertMultiLineEqual(mock_print.getvalue(), no_output)
243+
244+
@mock.patch("sys.stdout", new_callable=StringIO)
245+
def test_single_commit_happy_flow(self, mock_print):
202246
args = DeployCommand.Args(
203247
file="test/file.yml",
204248
values={"a.b.c": "foo", "a.b.d": "bar"},
@@ -214,6 +258,7 @@ def test_single_commit_happy_flow(self):
214258
git_provider=GitProvider.GITHUB,
215259
git_provider_url=None,
216260
commit_message=None,
261+
json=False,
217262
)
218263
DeployCommand(args).execute()
219264

@@ -226,11 +271,19 @@ def test_single_commit_happy_flow(self):
226271
call.logging.info("Updated yaml property %s to %s", "a.b.c", "foo"),
227272
call.update_yaml_file("/tmp/created-tmp-dir/test/file.yml", "a.b.d", "bar"),
228273
call.logging.info("Updated yaml property %s to %s", "a.b.d", "bar"),
229-
call.GitRepo.commit("GIT_USER", "GIT_EMAIL", "updated 2 values in test/file.yml\n\na.b.c: foo\na.b.d: bar"),
274+
call.GitRepo.commit(
275+
"GIT_USER",
276+
"GIT_EMAIL",
277+
"updated 2 values in test/file.yml\n\na.b.c: foo\na.b.d: bar",
278+
),
230279
call.GitRepo.push(),
231280
]
232281

233-
def test_single_commit_single_value_change_happy_flow(self):
282+
no_output = ""
283+
self.assertMultiLineEqual(mock_print.getvalue(), no_output)
284+
285+
@mock.patch("sys.stdout", new_callable=StringIO)
286+
def test_single_commit_single_value_change_happy_flow(self, mock_print):
234287
args = DeployCommand.Args(
235288
file="test/file.yml",
236289
values={"a.b.c": "foo"},
@@ -246,6 +299,7 @@ def test_single_commit_single_value_change_happy_flow(self):
246299
git_provider=GitProvider.GITHUB,
247300
git_provider_url=None,
248301
commit_message=None,
302+
json=False,
249303
)
250304
DeployCommand(args).execute()
251305

@@ -260,7 +314,11 @@ def test_single_commit_single_value_change_happy_flow(self):
260314
call.GitRepo.push(),
261315
]
262316

263-
def test_commit_message_multiple_value_changes_happy_flow(self):
317+
no_output = ""
318+
self.assertMultiLineEqual(mock_print.getvalue(), no_output)
319+
320+
@mock.patch("sys.stdout", new_callable=StringIO)
321+
def test_commit_message_multiple_value_changes_happy_flow(self, mock_print):
264322
args = DeployCommand.Args(
265323
file="test/file.yml",
266324
values={"a.b.c": "foo", "a.b.d": "bar"},
@@ -276,6 +334,7 @@ def test_commit_message_multiple_value_changes_happy_flow(self):
276334
git_provider=GitProvider.GITHUB,
277335
git_provider_url=None,
278336
commit_message="testcommit",
337+
json=False,
279338
)
280339
DeployCommand(args).execute()
281340

@@ -292,6 +351,9 @@ def test_commit_message_multiple_value_changes_happy_flow(self):
292351
call.GitRepo.push(),
293352
]
294353

354+
no_output = ""
355+
self.assertEqual(mock_print.getvalue(), no_output)
356+
295357
def test_clone_error(self):
296358
clone_exception = GitOpsException("dummy clone error")
297359
self.git_repo_mock.clone.side_effect = clone_exception
@@ -311,6 +373,7 @@ def test_clone_error(self):
311373
git_provider=GitProvider.GITHUB,
312374
git_provider_url=None,
313375
commit_message=None,
376+
json=False,
314377
)
315378
with pytest.raises(GitOpsException) as ex:
316379
DeployCommand(args).execute()
@@ -340,6 +403,7 @@ def test_file_not_found(self):
340403
git_provider=GitProvider.GITHUB,
341404
git_provider_url=None,
342405
commit_message=None,
406+
json=False,
343407
)
344408
with pytest.raises(GitOpsException) as ex:
345409
DeployCommand(args).execute()
@@ -371,6 +435,7 @@ def test_file_parse_error(self):
371435
git_provider=GitProvider.GITHUB,
372436
git_provider_url=None,
373437
commit_message=None,
438+
json=False,
374439
)
375440
with pytest.raises(GitOpsException) as ex:
376441
DeployCommand(args).execute()
@@ -402,6 +467,7 @@ def test_key_not_found(self):
402467
git_provider=GitProvider.GITHUB,
403468
git_provider_url=None,
404469
commit_message=None,
470+
json=False,
405471
)
406472
with pytest.raises(GitOpsException) as ex:
407473
DeployCommand(args).execute()
@@ -433,6 +499,7 @@ def test_nothing_to_update(self):
433499
git_provider=GitProvider.GITHUB,
434500
git_provider_url=None,
435501
commit_message=None,
502+
json=False,
436503
)
437504
DeployCommand(args).execute()
438505

0 commit comments

Comments
 (0)