Skip to content

Commit

Permalink
Add type of change to files_dict of a commit
Browse files Browse the repository at this point in the history
This allows to not only get the total, inserted or deleted number of
lines being changed but also the type of change like
Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R),
type changed (T), Unmerged (U), Unknown (X), or pairing Broken (B)
  • Loading branch information
JonasScharpf committed Jul 17, 2024
1 parent 3d3c86c commit ce8a69a
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 16 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,6 @@ Contributors are:
-Wenhan Zhu <wzhu.cosmos _at_ gmail.com>
-Eliah Kagan <eliah.kagan _at_ gmail.com>
-Ethan Lin <et.repositories _at_ gmail.com>
-Jonas Scharpf <jonas.scharpf _at_ checkmk.com>

Portions derived from other open source works and are clearly marked.
24 changes: 17 additions & 7 deletions git/objects/commit.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,15 +377,25 @@ def stats(self) -> Stats:
:return:
:class:`Stats`
"""
if not self.parents:
text = self.repo.git.diff_tree(self.hexsha, "--", numstat=True, no_renames=True, root=True)
text2 = ""
for line in text.splitlines()[1:]:

def process_lines(lines: List[str]) -> str:
text = ""
for file_info, line in zip(lines, lines[len(lines) // 2 :]):
change_type = file_info.split("\t")[0][-1]
(insertions, deletions, filename) = line.split("\t")
text2 += "%s\t%s\t%s\n" % (insertions, deletions, filename)
text = text2
text += "%s\t%s\t%s\t%s\n" % (change_type, insertions, deletions, filename)
return text

if not self.parents:
lines = self.repo.git.diff_tree(
self.hexsha, "--", numstat=True, no_renames=True, root=True, raw=True
).splitlines()[1:]
text = process_lines(lines)
else:
text = self.repo.git.diff(self.parents[0].hexsha, self.hexsha, "--", numstat=True, no_renames=True)
lines = self.repo.git.diff(
self.parents[0].hexsha, self.hexsha, "--", numstat=True, no_renames=True, raw=True
).splitlines()
text = process_lines(lines)
return Stats._list_from_string(self.repo, text)

@property
Expand Down
1 change: 1 addition & 0 deletions git/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ class Files_TD(TypedDict):
insertions: int
deletions: int
lines: int
change_type: str


class Total_TD(TypedDict):
Expand Down
4 changes: 3 additions & 1 deletion git/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,7 @@ class Stats:
deletions = number of deleted lines as int
insertions = number of inserted lines as int
lines = total number of lines changed as int, or deletions + insertions
change_type = type of change as str, A|C|D|M|R|T|U|X|B
``full-stat-dict``
Expand Down Expand Up @@ -938,7 +939,7 @@ def _list_from_string(cls, repo: "Repo", text: str) -> "Stats":
"files": {},
}
for line in text.splitlines():
(raw_insertions, raw_deletions, filename) = line.split("\t")
(change_type, raw_insertions, raw_deletions, filename) = line.split("\t")
insertions = raw_insertions != "-" and int(raw_insertions) or 0
deletions = raw_deletions != "-" and int(raw_deletions) or 0
hsh["total"]["insertions"] += insertions
Expand All @@ -949,6 +950,7 @@ def _list_from_string(cls, repo: "Repo", text: str) -> "Stats":
"insertions": insertions,
"deletions": deletions,
"lines": insertions + deletions,
"change_type": change_type,
}
hsh["files"][filename.strip()] = files_dict
return Stats(hsh["total"], hsh["files"])
Expand Down
5 changes: 3 additions & 2 deletions test/fixtures/diff_numstat
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
29 18 a.txt
0 5 b.txt
M 29 18 a.txt
M 0 5 b.txt
A 7 0 c.txt
9 changes: 6 additions & 3 deletions test/test_commit.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,12 @@ def test_stats(self):
commit = self.rorepo.commit("33ebe7acec14b25c5f84f35a664803fcab2f7781")
stats = commit.stats

def check_entries(d):
def check_entries(d, has_change_type=False):
assert isinstance(d, dict)
for key in ("insertions", "deletions", "lines"):
keys = ("insertions", "deletions", "lines")
if has_change_type:
keys += ("change_type",)
for key in keys:
assert key in d

# END assertion helper
Expand All @@ -148,7 +151,7 @@ def check_entries(d):
assert "files" in stats.total

for _filepath, d in stats.files.items():
check_entries(d)
check_entries(d, True)
# END for each stated file

# Check that data is parsed properly.
Expand Down
12 changes: 9 additions & 3 deletions test/test_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,19 @@ def test_list_from_string(self):
output = fixture("diff_numstat").decode(defenc)
stats = Stats._list_from_string(self.rorepo, output)

self.assertEqual(2, stats.total["files"])
self.assertEqual(52, stats.total["lines"])
self.assertEqual(29, stats.total["insertions"])
self.assertEqual(3, stats.total["files"])
self.assertEqual(59, stats.total["lines"])
self.assertEqual(36, stats.total["insertions"])
self.assertEqual(23, stats.total["deletions"])

self.assertEqual(29, stats.files["a.txt"]["insertions"])
self.assertEqual(18, stats.files["a.txt"]["deletions"])
self.assertEqual("M", stats.files["a.txt"]["change_type"])

self.assertEqual(0, stats.files["b.txt"]["insertions"])
self.assertEqual(5, stats.files["b.txt"]["deletions"])
self.assertEqual("M", stats.files["b.txt"]["change_type"])

self.assertEqual(7, stats.files["c.txt"]["insertions"])
self.assertEqual(0, stats.files["c.txt"]["deletions"])
self.assertEqual("A", stats.files["c.txt"]["change_type"])

0 comments on commit ce8a69a

Please sign in to comment.