Skip to content

Commit 3483925

Browse files
authored
Merge pull request #159 from github/simplify-main-fn
2 parents 33fb3a9 + 538da8d commit 3483925

File tree

2 files changed

+157
-29
lines changed

2 files changed

+157
-29
lines changed

cleanowners.py

+60-29
Original file line numberDiff line numberDiff line change
@@ -82,26 +82,7 @@ def main(): # pragma: no cover
8282

8383
# Check to see if repository has a CODEOWNERS file
8484
file_changed = False
85-
codeowners_file_contents = None
86-
codeowners_filepath = None
87-
try:
88-
if repo.file_contents(".github/CODEOWNERS").size > 0:
89-
codeowners_file_contents = repo.file_contents(".github/CODEOWNERS")
90-
codeowners_filepath = ".github/CODEOWNERS"
91-
except github3.exceptions.NotFoundError:
92-
pass
93-
try:
94-
if repo.file_contents("CODEOWNERS").size > 0:
95-
codeowners_file_contents = repo.file_contents("CODEOWNERS")
96-
codeowners_filepath = "CODEOWNERS"
97-
except github3.exceptions.NotFoundError:
98-
pass
99-
try:
100-
if repo.file_contents("docs/CODEOWNERS").size > 0:
101-
codeowners_file_contents = repo.file_contents("docs/CODEOWNERS")
102-
codeowners_filepath = "docs/CODEOWNERS"
103-
except github3.exceptions.NotFoundError:
104-
pass
85+
codeowners_file_contents, codeowners_filepath = get_codeowners_file(repo)
10586

10687
if not codeowners_file_contents:
10788
print(f"Skipping {repo.full_name} as it does not have a CODEOWNERS file")
@@ -171,6 +152,65 @@ def main(): # pragma: no cover
171152
continue
172153

173154
# Report the statistics from this run
155+
print_stats(
156+
pull_count=pull_count,
157+
eligble_for_pr_count=eligble_for_pr_count,
158+
no_codeowners_count=no_codeowners_count,
159+
codeowners_count=codeowners_count,
160+
users_count=users_count,
161+
)
162+
163+
if issue_report:
164+
write_to_markdown(
165+
users_count,
166+
pull_count,
167+
no_codeowners_count,
168+
codeowners_count,
169+
repo_and_users_to_remove,
170+
)
171+
172+
173+
def get_codeowners_file(repo):
174+
"""
175+
Get the CODEOWNERS file from the repository and return
176+
the file contents and file path or None if it doesn't exist
177+
"""
178+
codeowners_file_contents = None
179+
codeowners_filepath = None
180+
try:
181+
if (
182+
repo.file_contents(".github/CODEOWNERS")
183+
and repo.file_contents(".github/CODEOWNERS").size > 0
184+
):
185+
codeowners_file_contents = repo.file_contents(".github/CODEOWNERS")
186+
codeowners_filepath = ".github/CODEOWNERS"
187+
except github3.exceptions.NotFoundError:
188+
pass
189+
try:
190+
if (
191+
repo.file_contents("CODEOWNERS")
192+
and repo.file_contents("CODEOWNERS").size > 0
193+
):
194+
codeowners_file_contents = repo.file_contents("CODEOWNERS")
195+
codeowners_filepath = "CODEOWNERS"
196+
except github3.exceptions.NotFoundError:
197+
pass
198+
try:
199+
if (
200+
repo.file_contents("docs/CODEOWNERS")
201+
and repo.file_contents("docs/CODEOWNERS").size > 0
202+
):
203+
codeowners_file_contents = repo.file_contents("docs/CODEOWNERS")
204+
codeowners_filepath = "docs/CODEOWNERS"
205+
except github3.exceptions.NotFoundError:
206+
pass
207+
return codeowners_file_contents, codeowners_filepath
208+
209+
210+
def print_stats(
211+
pull_count, eligble_for_pr_count, no_codeowners_count, codeowners_count, users_count
212+
):
213+
"""Print the statistics from this run to the terminal output"""
174214
print(f"Found {users_count} users to remove")
175215
print(f"Created {pull_count} pull requests successfully")
176216
print(f"Skipped {no_codeowners_count} repositories without a CODEOWNERS file")
@@ -188,15 +228,6 @@ def main(): # pragma: no cover
188228
f"{round((codeowners_count / (codeowners_count + no_codeowners_count)) * 100, 2)}% of repositories had CODEOWNERS files"
189229
)
190230

191-
if issue_report:
192-
write_to_markdown(
193-
users_count,
194-
pull_count,
195-
no_codeowners_count,
196-
codeowners_count,
197-
repo_and_users_to_remove,
198-
)
199-
200231

201232
def get_repos_iterator(organization, repository_list, github_connection):
202233
"""Get the repositories from the organization or list of repositories"""

test_cleanowners.py

+97
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@
22

33
import unittest
44
import uuid
5+
from io import StringIO
56
from unittest.mock import MagicMock, patch
67

78
import github3
89
from cleanowners import (
910
commit_changes,
11+
get_codeowners_file,
1012
get_org,
1113
get_repos_iterator,
1214
get_usernames_from_codeowners,
15+
print_stats,
1316
)
1417

1518

@@ -182,3 +185,97 @@ def test_get_repos_iterator_with_repository_list(self, mock_github):
182185

183186
# Assert that the function returned the expected result
184187
self.assertEqual(result, mock_repository_list)
188+
189+
190+
class TestPrintStats(unittest.TestCase):
191+
"""Test the print_stats function in cleanowners.py"""
192+
193+
@patch("sys.stdout", new_callable=StringIO)
194+
def test_print_stats_all_counts(self, mock_stdout):
195+
"""Test the print_stats function with all counts."""
196+
print_stats(5, 10, 2, 3, 4)
197+
expected_output = (
198+
"Found 4 users to remove\n"
199+
"Created 5 pull requests successfully\n"
200+
"Skipped 2 repositories without a CODEOWNERS file\n"
201+
"Processed 3 repositories with a CODEOWNERS file\n"
202+
"50.0% of eligible repositories had pull requests created\n"
203+
"60.0% of repositories had CODEOWNERS files\n"
204+
)
205+
self.assertEqual(mock_stdout.getvalue(), expected_output)
206+
207+
@patch("sys.stdout", new_callable=StringIO)
208+
def test_print_stats_no_pull_requests_needed(self, mock_stdout):
209+
"""Test the print_stats function with no pull requests needed."""
210+
print_stats(0, 0, 2, 3, 4)
211+
expected_output = (
212+
"Found 4 users to remove\n"
213+
"Created 0 pull requests successfully\n"
214+
"Skipped 2 repositories without a CODEOWNERS file\n"
215+
"Processed 3 repositories with a CODEOWNERS file\n"
216+
"No pull requests were needed\n"
217+
"60.0% of repositories had CODEOWNERS files\n"
218+
)
219+
self.assertEqual(mock_stdout.getvalue(), expected_output)
220+
221+
@patch("sys.stdout", new_callable=StringIO)
222+
def test_print_stats_no_repositories_processed(self, mock_stdout):
223+
"""Test the print_stats function with no repositories processed."""
224+
print_stats(0, 0, 0, 0, 0)
225+
expected_output = (
226+
"Found 0 users to remove\n"
227+
"Created 0 pull requests successfully\n"
228+
"Skipped 0 repositories without a CODEOWNERS file\n"
229+
"Processed 0 repositories with a CODEOWNERS file\n"
230+
"No pull requests were needed\n"
231+
"No repositories were processed\n"
232+
)
233+
self.assertEqual(mock_stdout.getvalue(), expected_output)
234+
235+
236+
class TestGetCodeownersFile(unittest.TestCase):
237+
"""Test the get_codeowners_file function in cleanowners.py"""
238+
239+
def setUp(self):
240+
self.repo = MagicMock()
241+
242+
def test_codeowners_in_github_folder(self):
243+
"""Test that a CODEOWNERS file in the .github folder is considered valid."""
244+
self.repo.file_contents.side_effect = lambda path: (
245+
MagicMock(size=1) if path == ".github/CODEOWNERS" else None
246+
)
247+
contents, path = get_codeowners_file(self.repo)
248+
self.assertIsNotNone(contents)
249+
self.assertEqual(path, ".github/CODEOWNERS")
250+
251+
def test_codeowners_in_root(self):
252+
"""Test that a CODEOWNERS file in the root is considered valid."""
253+
self.repo.file_contents.side_effect = lambda path: (
254+
MagicMock(size=1) if path == "CODEOWNERS" else None
255+
)
256+
contents, path = get_codeowners_file(self.repo)
257+
self.assertIsNotNone(contents)
258+
self.assertEqual(path, "CODEOWNERS")
259+
260+
def test_codeowners_in_docs_folder(self):
261+
"""Test that a CODEOWNERS file in a docs folder is considered valid."""
262+
self.repo.file_contents.side_effect = lambda path: (
263+
MagicMock(size=1) if path == "docs/CODEOWNERS" else None
264+
)
265+
contents, path = get_codeowners_file(self.repo)
266+
self.assertIsNotNone(contents)
267+
self.assertEqual(path, "docs/CODEOWNERS")
268+
269+
def test_codeowners_not_found(self):
270+
"""Test that a missing CODEOWNERS file is not considered valid because it doesn't exist."""
271+
self.repo.file_contents.side_effect = lambda path: None
272+
contents, path = get_codeowners_file(self.repo)
273+
self.assertIsNone(contents)
274+
self.assertIsNone(path)
275+
276+
def test_codeowners_empty_file(self):
277+
"""Test that an empty CODEOWNERS file is not considered valid because it is empty."""
278+
self.repo.file_contents.side_effect = lambda path: MagicMock(size=0)
279+
contents, path = get_codeowners_file(self.repo)
280+
self.assertIsNone(contents)
281+
self.assertIsNone(path)

0 commit comments

Comments
 (0)