Skip to content

Commit d3d3a57

Browse files
add gitinfo class
1 parent 1c9fec5 commit d3d3a57

2 files changed

Lines changed: 92 additions & 43 deletions

File tree

bdiff/git_bdiff.py

Lines changed: 71 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,10 @@ def __init__(self, cmd):
3737
)
3838

3939

40-
class GitBDiff:
41-
"""Class which generates a branch diff."""
42-
43-
# Name of primary branch - default is main
44-
primary_branch = "main"
45-
46-
# Match hex commit IDs
47-
_hash_pattern = re.compile(r"^\s*([0-9a-f]{40})\s*$")
40+
class GitBase:
41+
"""
42+
Base class for gitbdiff functionality
43+
"""
4844

4945
# Match branch names. This should catch all valid names but may
5046
# also some invalid names through. This should matter given that
@@ -53,15 +49,65 @@ class GitBDiff:
5349
_branch_pattern = re.compile(r"^\s*([^\s~\^\:\?\*\[]+[^.])\s*$")
5450

5551
def __init__(self, parent=None, repo=None):
56-
self.parent = parent or self.primary_branch
57-
5852
if repo is None:
5953
self._repo = None
6054
else:
6155
self._repo = Path(repo)
6256
if not self._repo.is_dir():
6357
raise GitBDiffError(f"{repo} is not a directory")
6458

59+
def get_branch_name(self):
60+
"""Get the name of the current branch."""
61+
result = None
62+
for line in self.run_git(["branch", "--show-current"]):
63+
if m := self._branch_pattern.match(line):
64+
result = m.group(1)
65+
break
66+
else:
67+
raise GitBDiffError("unable to get branch name")
68+
return result
69+
70+
def run_git(self, args):
71+
"""Run a git command and yield the output."""
72+
73+
if not isinstance(args, list):
74+
raise TypeError("args must be a list")
75+
cmd = ["git"] + args
76+
77+
# Run the the command in the repo directory, capture the
78+
# output, and check for errors. The build in error check is
79+
# not used to allow specific git errors to be treated more
80+
# precisely
81+
proc = subprocess.run(
82+
cmd, capture_output=True, check=False, shell=False, cwd=self._repo
83+
)
84+
85+
for line in proc.stderr.decode("utf-8").split("\n"):
86+
if line.startswith("fatal: not a git repository"):
87+
raise GitBDiffNotGit(cmd)
88+
if line.startswith("fatal: "):
89+
raise GitBDiffError(line[7:])
90+
91+
if proc.returncode != 0:
92+
raise GitBDiffError(f"command returned {proc.returncode}")
93+
94+
yield from proc.stdout.decode("utf-8").split("\n")
95+
96+
97+
class GitBDiff(GitBase):
98+
"""Class which generates a branch diff."""
99+
100+
# Name of primary branch - default is main
101+
primary_branch = "main"
102+
103+
# Match hex commit IDs
104+
_hash_pattern = re.compile(r"^\s*([0-9a-f]{40})\s*$")
105+
106+
def __init__(self, parent=None, repo=None):
107+
self.parent = parent or self.primary_branch
108+
109+
super().__init__(parent, repo)
110+
65111
self.ancestor = self.get_branch_point()
66112
self.current = self.get_latest_commit()
67113
self.branch = self.get_branch_name()
@@ -96,17 +142,6 @@ def get_latest_commit(self):
96142
raise GitBDiffError("current revision not found")
97143
return result
98144

99-
def get_branch_name(self):
100-
"""Get the name of the current branch."""
101-
result = None
102-
for line in self.run_git(["branch", "--show-current"]):
103-
if m := self._branch_pattern.match(line):
104-
result = m.group(1)
105-
break
106-
else:
107-
raise GitBDiffError("unable to get branch name")
108-
return result
109-
110145
@property
111146
def is_branch(self):
112147
"""Whether this is a branch or main."""
@@ -126,28 +161,23 @@ def files(self):
126161
if line != "":
127162
yield line
128163

129-
def run_git(self, args):
130-
"""Run a git command and yield the output."""
131164

132-
if not isinstance(args, list):
133-
raise TypeError("args must be a list")
134-
cmd = ["git"] + args
165+
class GitInfo(GitBase):
166+
"""
167+
Class to contain info of a git repo
168+
"""
135169

136-
# Run the the command in the repo directory, capture the
137-
# output, and check for errors. The build in error check is
138-
# not used to allow specific git errors to be treated more
139-
# precisely
140-
proc = subprocess.run(
141-
cmd, capture_output=True, check=False, shell=False, cwd=self._repo
142-
)
170+
def __init__(self, repo=None):
171+
super().__init__(repo=repo)
143172

144-
for line in proc.stderr.decode("utf-8").split("\n"):
145-
if line.startswith("fatal: not a git repository"):
146-
raise GitBDiffNotGit(cmd)
147-
if line.startswith("fatal: "):
148-
raise GitBDiffError(line[7:])
173+
self.branch = self.get_branch_name()
149174

150-
if proc.returncode != 0:
151-
raise GitBDiffError(f"command returned {proc.returncode}")
175+
def is_main(self):
176+
"""
177+
Returns true if branch matches a main-like branch name as defined below
178+
"""
152179

153-
yield from proc.stdout.decode("utf-8").split("\n")
180+
main_like = ("main", "stable", "trunk", "master")
181+
if self.branch in main_like:
182+
return True
183+
return False

bdiff/tests/test_git_bdiff.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import subprocess
1313
import pytest
1414

15-
from git_bdiff import GitBDiff, GitBDiffError, GitBDiffNotGit
15+
from git_bdiff import GitBDiff, GitBDiffError, GitBDiffNotGit, GitInfo
1616

1717

1818
# Disable warnings caused by the use of pytest fixtures
@@ -58,9 +58,14 @@ def git_repo(tmpdir_factory):
5858
subprocess.run(["git", "checkout", "-b", "overwrite"], check=True)
5959
add_to_repo(0, 10, "Overwriting", "at")
6060

61-
# Switch back to the main branch ready for testing
61+
# Switch back to the main branch
6262
subprocess.run(["git", "checkout", "main"], check=True)
6363

64+
# Add other trunk-like branches, finishing back in main
65+
for branch in ("stable", "master", "trunk"):
66+
subprocess.run(["git", "checkout", "-b", branch], check=True)
67+
subprocess.run(["git", "checkout", "main"], check=True)
68+
6469
return location
6570

6671

@@ -214,3 +219,17 @@ def test_git_run(git_repo):
214219
# Run a command that should return non-zero
215220
list(i for i in bdiff.run_git(["commit", "-m", "''"]))
216221
assert "command returned 1" in str(exc.value)
222+
223+
224+
def test_is_main(git_repo):
225+
"""Test is_trunk function"""
226+
227+
os.chdir(git_repo)
228+
229+
for branch in ("stable", "master", "trunk", "main", "mybranch"):
230+
info = GitInfo()
231+
subprocess.run(["git", "checkout", branch], check=True)
232+
if branch == "my_branch":
233+
assert not info.is_main()
234+
else:
235+
assert info.is_main()

0 commit comments

Comments
 (0)