Skip to content

Commit 7ff346a

Browse files
Output to json format (#100)
Fix #99 * 99 : output to json format * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent c523f31 commit 7ff346a

File tree

4 files changed

+174
-12
lines changed

4 files changed

+174
-12
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ artifactory-cleanup --days-in-future=10
135135
# Not satisfied with built-in rules? Write your own rules in python and connect them!
136136
artifactory-cleanup --load-rules=myrule.py
137137
docker run -v "$(pwd)":/app devopshq/artifactory-cleanup artifactory-cleanup --load-rules=myrule.py
138+
139+
# Save the table summary in a file
140+
artifactory-cleanup --output=myfile.txt
141+
142+
# Save the summary in a Json file
143+
artifactory-cleanup --output=myfile.txt --output-format=json
138144
```
139145

140146
# Rules

artifactory_cleanup/cli.py

+60-12
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import json
12
import logging
23
import sys
34
from datetime import timedelta, date
45

56
import requests
67
from hurry.filesize import size
78
from plumbum import cli
9+
from plumbum.cli.switches import Set
810
from prettytable import PrettyTable
911
from requests.auth import HTTPBasicAuth
1012

@@ -62,6 +64,19 @@ class ArtifactoryCleanupCLI(cli.Application):
6264
mandatory=False,
6365
)
6466

67+
_output_file = cli.SwitchAttr(
68+
"--output", help="Choose the output file", mandatory=False
69+
)
70+
71+
_output_format = cli.SwitchAttr(
72+
"--output-format",
73+
Set("table", "json", case_sensitive=False),
74+
help="Choose the output format",
75+
default="table",
76+
requires=["--output"],
77+
mandatory=False,
78+
)
79+
6580
@property
6681
def VERSION(self):
6782
# To prevent circular imports
@@ -83,6 +98,36 @@ def _get_today(self):
8398
print(f"Simulating cleanup actions that will occur on {today}")
8499
return today
85100

101+
def _format_table(self, result) -> PrettyTable:
102+
table = PrettyTable()
103+
table.field_names = ["Cleanup Policy", "Files count", "Size"]
104+
table.align["Cleanup Policy"] = "l"
105+
106+
for policy_result in result["policies"]:
107+
row = [
108+
policy_result["name"],
109+
policy_result["file_count"],
110+
size(policy_result["size"]),
111+
]
112+
table.add_row(row)
113+
114+
table.add_row(["", "", ""])
115+
table.add_row(["Total size: {}".format(size(result["total_size"])), "", ""])
116+
return table
117+
118+
def _print_table(self, result: dict):
119+
print(self._format_table(result))
120+
121+
def _create_output_file(self, result, filename, format):
122+
text = None
123+
if format == "table":
124+
text = self._format_table(result).get_string()
125+
else:
126+
text = json.dumps(result)
127+
128+
with open(filename, "w") as file:
129+
file.write(text)
130+
86131
def main(self):
87132
today = self._get_today()
88133
if self._load_rules:
@@ -112,9 +157,7 @@ def main(self):
112157
if self._policy:
113158
cleanup.only(self._policy)
114159

115-
table = PrettyTable()
116-
table.field_names = ["Cleanup Policy", "Files count", "Size"]
117-
table.align["Cleanup Policy"] = "l"
160+
result = {"policies": [], "total_size": 0}
118161
total_size = 0
119162

120163
block_ctx_mgr, test_ctx_mgr = get_context_managers()
@@ -124,16 +167,21 @@ def main(self):
124167
if summary is None:
125168
continue
126169
total_size += summary.artifacts_size
127-
row = [
128-
summary.policy_name,
129-
summary.artifacts_removed,
130-
size(summary.artifacts_size),
131-
]
132-
table.add_row(row)
133170

134-
table.add_row(["", "", ""])
135-
table.add_row(["Total size: {}".format(size(total_size)), "", ""])
136-
print(table)
171+
result["policies"].append(
172+
{
173+
"name": summary.policy_name,
174+
"file_count": summary.artifacts_removed,
175+
"size": summary.artifacts_size,
176+
}
177+
)
178+
179+
result["total_size"] = total_size
180+
181+
self._print_table(result)
182+
183+
if self._output_file:
184+
self._create_output_file(result, self._output_file, self._output_format)
137185

138186

139187
if __name__ == "__main__":

tests/data/expected_output.txt

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
+--------------------------------------------------------+-------------+------+
2+
| Cleanup Policy | Files count | Size |
3+
+--------------------------------------------------------+-------------+------+
4+
| Remove all files from repo-name-here older then 7 days | 1 | 528B |
5+
| Use your own rules! | 1 | 528B |
6+
| | | |
7+
| Total size: 1K | | |
8+
+--------------------------------------------------------+-------------+------+

tests/test_cli.py

+100
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import json
12
import pytest
3+
from filecmp import cmp
24

35
from artifactory_cleanup import ArtifactoryCleanupCLI
46

@@ -69,3 +71,101 @@ def test_destroy(capsys, shared_datadir, requests_mock):
6971
last_request.url
7072
== "https://repo.example.com/artifactory/repo-name-here/path/to/file/filename1.json"
7173
)
74+
75+
76+
@pytest.mark.usefixtures("requests_repo_name_here")
77+
def test_output_table(capsys, shared_datadir, requests_mock):
78+
_, code = ArtifactoryCleanupCLI.run(
79+
[
80+
"ArtifactoryCleanupCLI",
81+
"--config",
82+
str(shared_datadir / "cleanup.yaml"),
83+
"--load-rules",
84+
str(shared_datadir / "myrule.py"),
85+
],
86+
exit=False,
87+
)
88+
stdout, stderr = capsys.readouterr()
89+
print(stdout)
90+
assert code == 0, stdout
91+
assert (
92+
"| Cleanup Policy | Files count | Size |"
93+
in stdout
94+
)
95+
96+
97+
@pytest.mark.usefixtures("requests_repo_name_here")
98+
def test_output_table(capsys, shared_datadir, requests_mock, tmp_path):
99+
output_file = tmp_path / "output.txt"
100+
_, code = ArtifactoryCleanupCLI.run(
101+
[
102+
"ArtifactoryCleanupCLI",
103+
"--config",
104+
str(shared_datadir / "cleanup.yaml"),
105+
"--load-rules",
106+
str(shared_datadir / "myrule.py"),
107+
"--output-format",
108+
"table",
109+
"--output",
110+
str(output_file),
111+
],
112+
exit=False,
113+
)
114+
stdout, stderr = capsys.readouterr()
115+
print(stdout)
116+
assert code == 0, stdout
117+
assert cmp(output_file, shared_datadir / "expected_output.txt") is True
118+
119+
120+
@pytest.mark.usefixtures("requests_repo_name_here")
121+
def test_output_json(capsys, shared_datadir, requests_mock, tmp_path):
122+
output_json = tmp_path / "output.json"
123+
_, code = ArtifactoryCleanupCLI.run(
124+
[
125+
"ArtifactoryCleanupCLI",
126+
"--config",
127+
str(shared_datadir / "cleanup.yaml"),
128+
"--load-rules",
129+
str(shared_datadir / "myrule.py"),
130+
"--output-format",
131+
"json",
132+
"--output",
133+
str(output_json),
134+
],
135+
exit=False,
136+
)
137+
stdout, stderr = capsys.readouterr()
138+
assert code == 0, stdout
139+
with open(output_json, "r") as file:
140+
assert json.load(file) == {
141+
"policies": [
142+
{
143+
"name": "Remove all files from repo-name-here older then 7 days",
144+
"file_count": 1,
145+
"size": 528,
146+
},
147+
{"name": "Use your own rules!", "file_count": 1, "size": 528},
148+
],
149+
"total_size": 1056,
150+
}
151+
152+
153+
@pytest.mark.usefixtures("requests_repo_name_here")
154+
def test_require_output_json(capsys, shared_datadir, requests_mock):
155+
_, code = ArtifactoryCleanupCLI.run(
156+
[
157+
"ArtifactoryCleanupCLI",
158+
"--config",
159+
str(shared_datadir / "cleanup.yaml"),
160+
"--load-rules",
161+
str(shared_datadir / "myrule.py"),
162+
"--output-format",
163+
"json",
164+
],
165+
exit=False,
166+
)
167+
assert code == 2, stdout
168+
stdout, stderr = capsys.readouterr()
169+
assert (
170+
"Error: Given --output-format, the following are missing ['output']" in stdout
171+
)

0 commit comments

Comments
 (0)