Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 36 additions & 15 deletions codeowners_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import difflib
import functools
import glob
import operator
import os.path
import re
import subprocess
Expand Down Expand Up @@ -69,9 +68,12 @@ def of(self, filepath: str) -> tuple[str, ...]:

class MarkdownPrinter:
def __init__(
self, changed_owners: Mapping[str, Mapping[str, tuple[str, ...]]],
self,
changed_owners: Mapping[str, Mapping[str, tuple[str, ...]]],
max_files_to_print: int | None,
) -> None:
self.changed_owners = changed_owners
self.max_files_to_print = max_files_to_print

def render_lines(self) -> Iterator[str]:
if not self.changed_owners:
Expand All @@ -80,24 +82,38 @@ def render_lines(self) -> Iterator[str]:

yield f'{len(self.changed_owners)} files have changed ownership:'
yield ''
yield from tabulate(

files_to_print = list(
sorted(
(
{
'file': f'`{file}`',
**{
self._column_title(ref): ', '.join(owners_)
for ref, owners_ in owners.items()
},
}
for file, owners in self.changed_owners.items()
),
key=operator.itemgetter('file'), # type: ignore[arg-type]
self.changed_owners.items(),
),
)[:self.max_files_to_print]

yield from tabulate(
(
{
'file': f'`{file}`',
**{
self._column_title(ref): ', '.join(owners_)
for ref, owners_ in owners.items()
},
}
for file, owners in files_to_print
),
headers='keys',
tablefmt='pipe',
).splitlines()

if (
self.max_files_to_print is not None and
(len(self.changed_owners) > self.max_files_to_print)
):
yield ''
yield (
'Note that the above table was truncated to '
f'{self.max_files_to_print} items.'
)

def _column_title(self, ref: str) -> str:
if ref:
return f'`{ref}`'
Expand Down Expand Up @@ -151,6 +167,11 @@ def main(argv: Sequence[str] | None = None) -> int:
dest='repo_root', default=None,
help='git repository to run the tool in (default: current directory)',
)
parser.add_argument(
'--limit',
default=None,
help='maximum files to show in diff message (default: no limit)',
)
args = parser.parse_args(argv)

git_repo = GitRepo(args.repo_root)
Expand Down Expand Up @@ -180,7 +201,7 @@ def main(argv: Sequence[str] | None = None) -> int:
if base_file_owners[file] != head_file_owners[file]
}

printer = MarkdownPrinter(changed_file_owners)
printer = MarkdownPrinter(changed_file_owners, max_files_to_print=args.limit)
print(*printer.render_lines(), sep='\n')

return 0
Expand Down
53 changes: 42 additions & 11 deletions tests/codeowners_diff_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,18 @@ def test_handle_missing_codeowners_file(

class TestMarkdownPrinter:
def test_render_lines(self) -> None:
printer = codeowners_diff.MarkdownPrinter({
'foo/bar/baz.py': {
'base': ('@some-owner', '@some/team'),
'HEAD': ('@another/team',),
},
'foo/bar/bang.py': {
'base': ('@some/team',),
'HEAD': ('@another/team', '@some-user'),
},
})
printer = codeowners_diff.MarkdownPrinter(
{
'foo/bar/baz.py': {
'base': ('@some-owner', '@some/team'),
'HEAD': ('@another/team',),
},
'foo/bar/bang.py': {
'base': ('@some/team',),
'HEAD': ('@another/team', '@some-user'),
},
}, None,
)

lines = printer.render_lines()
assert '\n'.join(lines) == """\
Expand All @@ -130,7 +132,36 @@ def test_render_lines(self) -> None:
| `foo/bar/baz.py` | @some-owner, @some/team | @another/team |"""

def test_no_changes(self) -> None:
printer = codeowners_diff.MarkdownPrinter({})
printer = codeowners_diff.MarkdownPrinter({}, None)

lines = printer.render_lines()
assert '\n'.join(lines) == 'No files have changed ownership.'

def test_max_files_to_print(self) -> None:
printer = codeowners_diff.MarkdownPrinter(
{
'foo/bar/baz.py': {
'base': ('@some-owner', '@some/team'),
'HEAD': ('@another/team',),
},
'foo/bar/bash.py': {
'base': ('@some-owner', '@some/team'),
'HEAD': ('@another/team',),
},
'foo/bar/bang.py': {
'base': ('@some/team',),
'HEAD': ('@another/team', '@some-user'),
},
}, None,
)

lines = printer.render_lines()
assert '\n'.join(lines) == """\
3 files have changed ownership:

| file | `base` | `HEAD` |
|:------------------|:------------------------|:--------------------------|
| `foo/bar/bang.py` | @some/team | @another/team, @some-user |
| `foo/bar/baz.py` | @some-owner, @some/team | @another/team |

Note that the above table was truncated to 2 items."""
23 changes: 23 additions & 0 deletions tests/end_to_end_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,29 @@ def test_compare_working_tree_with_HEAD(
assert captured.err == ''


def test_limit_is_respected(
tmp_path: Path, capsys: pytest.CaptureFixture[str],
) -> None:
_create_git_repo(tmp_path)
_create_branch(tmp_path, 'branch-a', '@some-user')
_create_branch(tmp_path, 'branch-b', '@another/team')

codeowners_diff.main(
('branch-a', 'branch-b', '-C', str(tmp_path), '--limit', '0'),
)

captured = capsys.readouterr()
assert captured.out == """\
1 files have changed ownership:

| file | `branch-a` | `branch-b` |
|:-----------------|:-------------|:--------------|

Note that the above table was truncated to 0 items.
"""
assert captured.err == ''


def _create_git_repo(root_dir: Path) -> None:
subprocess.run(('git', 'init'), cwd=root_dir)

Expand Down