Skip to content

Commit 123abbc

Browse files
committed
scan: add --git-remote option to select remote
For repos with multiple remotes, it might be useful to select a specific remote to use (and not the default origin). This can be set using the `--git-remote` option for cmd call, or by adding `git-remote=value` to the config file. Resolves: #600 Signed-off-by: Arthur Zamarin <arthurzam@gentoo.org>
1 parent 4e9dbc1 commit 123abbc

2 files changed

Lines changed: 50 additions & 30 deletions

File tree

src/pkgcheck/addons/git.py

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -342,16 +342,16 @@ class _ScanGit(argparse.Action):
342342
def __init__(self, *args, staged=False, **kwargs):
343343
super().__init__(*args, **kwargs)
344344
if staged:
345-
default_ref = "HEAD"
346345
diff_cmd = ["git", "diff-index", "--name-only", "--cached", "-z"]
347346
else:
348-
default_ref = "origin..HEAD"
349347
diff_cmd = ["git", "diff-tree", "-r", "--name-only", "-z"]
350348

351349
self.staged = staged
352-
self.default_ref = default_ref
353350
self.diff_cmd = diff_cmd
354351

352+
def default_ref(self, remote):
353+
return "HEAD" if self.staged else f"{remote}..HEAD"
354+
355355
def generate_restrictions(self, parser, namespace, ref):
356356
"""Generate restrictions for a given diff command."""
357357
try:
@@ -363,10 +363,10 @@ def generate_restrictions(self, parser, namespace, ref):
363363
check=True,
364364
encoding="utf8",
365365
)
366-
except FileNotFoundError as e:
367-
parser.error(str(e))
368-
except subprocess.CalledProcessError as e:
369-
error = e.stderr.splitlines()[0]
366+
except FileNotFoundError as exc:
367+
parser.error(str(exc))
368+
except subprocess.CalledProcessError as exc:
369+
error = exc.stderr.splitlines()[0]
370370
parser.error(f"failed running git: {error}")
371371

372372
if not p.stdout:
@@ -417,7 +417,7 @@ def __call__(self, parser, namespace, value, option_string=None):
417417
namespace.enabled_checks.update(objects.CHECKS.select(GitCommitsCheck).values())
418418

419419
# determine target ref
420-
ref = value if value is not None else self.default_ref
420+
ref = value if value is not None else self.default_ref(namespace.git_remote)
421421
setattr(namespace, self.dest, ref)
422422

423423
# generate scanning restrictions
@@ -441,14 +441,17 @@ class GitAddon(caches.CachedAddon):
441441
Additionally, the origin/HEAD ref must exist. If it doesn't, running ``git
442442
remote set-head origin master`` or similar for other branches will create
443443
it.
444+
445+
You can override the default git remote used for all git comparison using
446+
``--git-remote``.
444447
"""
445448

446449
# cache registry
447450
cache = caches.CacheData(type="git", file="git.pickle", version=5)
448451

449452
@classmethod
450453
def mangle_argparser(cls, parser):
451-
group = parser.add_argument_group("git", docs=cls.__doc__)
454+
group: argparse.ArgumentParser = parser.add_argument_group("git", docs=cls.__doc__)
452455
git_opts = group.add_mutually_exclusive_group()
453456
git_opts.add_argument(
454457
"--commits",
@@ -484,6 +487,17 @@ def mangle_argparser(cls, parser):
484487
temporarily stashing them during the scanning process.
485488
""",
486489
)
490+
group.add_argument(
491+
"--git-remote",
492+
default="origin",
493+
metavar="REMOTE",
494+
help="git remote used for all git comparison and operations",
495+
docs="""
496+
The git remote to be used for all operations by pkgcheck. The
497+
default value, and the recommended value is ``origin``, but
498+
you can use any valid git remote name.
499+
""",
500+
)
487501

488502
def __init__(self, *args):
489503
super().__init__(*args)
@@ -551,11 +565,11 @@ def _get_current_branch(path, commit="HEAD"):
551565
return p.stdout.strip()
552566

553567
@staticmethod
554-
def _get_default_branch(path):
568+
def _get_default_branch(path, remote):
555569
"""Retrieve a git repo's default branch used with origin remote."""
556570
try:
557571
p = subprocess.run(
558-
["git", "symbolic-ref", "refs/remotes/origin/HEAD"],
572+
["git", "symbolic-ref", f"refs/remotes/{remote}/HEAD"],
559573
stdout=subprocess.PIPE,
560574
stderr=subprocess.DEVNULL,
561575
cwd=path,
@@ -591,10 +605,11 @@ def pkg_history(repo, commit_range, data=None, local=False, verbosity=-1):
591605

592606
def update_cache(self, force=False):
593607
"""Update related cache and push updates to disk."""
608+
remote = self.options.git_remote
594609
for repo in self.options.target_repo.trees:
595610
try:
596611
branch = self._get_current_branch(repo.location)
597-
default_branch = self._get_default_branch(repo.location)
612+
default_branch = self._get_default_branch(repo.location, remote)
598613
# skip cache usage when not running on the default branch
599614
if branch != default_branch:
600615
logger.debug(
@@ -603,7 +618,7 @@ def update_cache(self, force=False):
603618
branch,
604619
)
605620
continue
606-
commit = self._get_commit_hash(repo.location, "origin/HEAD")
621+
commit = self._get_commit_hash(repo.location, f"{remote}/HEAD")
607622
except GitError:
608623
continue
609624

@@ -619,17 +634,17 @@ def update_cache(self, force=False):
619634
logger.debug("updating %s git repo cache to %s", repo, commit[:13])
620635
if git_cache is None:
621636
data = {}
622-
commit_range = "origin/HEAD"
637+
commit_range = f"{remote}/HEAD"
623638
else:
624639
data = git_cache.data
625-
commit_range = f"{git_cache.commit}..origin/HEAD"
640+
commit_range = f"{git_cache.commit}..{remote}/HEAD"
626641

627642
try:
628643
self.pkg_history(
629644
repo, commit_range, data=data, verbosity=self.options.verbosity
630645
)
631-
except GitError as e:
632-
raise PkgcheckUserException(str(e))
646+
except GitError as exc:
647+
raise PkgcheckUserException(str(exc))
633648
git_cache = GitCache(data, self.cache, commit=commit)
634649
else:
635650
cache_repo = False
@@ -652,29 +667,31 @@ def cached_repo(self, repo_cls):
652667

653668
def commits_repo(self, repo_cls):
654669
target_repo = self.options.target_repo
670+
remote = self.options.git_remote
655671
data = {}
656672

657673
try:
658-
origin = self._get_commit_hash(target_repo.location, "origin/HEAD")
674+
origin = self._get_commit_hash(target_repo.location, f"{remote}/HEAD")
659675
head = self._get_commit_hash(target_repo.location, "HEAD")
660676
if origin != head:
661-
data = self.pkg_history(target_repo, "origin/HEAD..HEAD", local=True)
662-
except GitError as e:
663-
raise PkgcheckUserException(str(e))
677+
data = self.pkg_history(target_repo, f"{remote}/HEAD..HEAD", local=True)
678+
except GitError as exc:
679+
raise PkgcheckUserException(str(exc))
664680

665681
repo_id = f"{target_repo.repo_id}-commits"
666682
return repo_cls(data, repo_id=repo_id)
667683

668684
def commits(self):
669685
target_repo = self.options.target_repo
686+
remote = self.options.git_remote
670687
commits = ()
671688

672689
try:
673-
origin = self._get_commit_hash(target_repo.location, "origin/HEAD")
690+
origin = self._get_commit_hash(target_repo.location, f"{remote}/HEAD")
674691
head = self._get_commit_hash(target_repo.location, "HEAD")
675692
if origin != head:
676-
commits = GitRepoCommits(target_repo.location, "origin/HEAD..HEAD")
677-
except GitError as e:
678-
raise PkgcheckUserException(str(e))
693+
commits = GitRepoCommits(target_repo.location, f"{remote}/HEAD..HEAD")
694+
except GitError as exc:
695+
raise PkgcheckUserException(str(exc))
679696

680697
return iter(commits)

tests/addons/test_git.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ def test_commits_nonexistent(self, make_repo, make_git_repo, tmp_path):
7171
options, _func = self.tool.parse_args(self.args + ["-r", local.path, "--commits"])
7272
assert excinfo.value.code == 0
7373

74-
def test_commits_existing(self, make_repo, make_git_repo, tmp_path):
74+
@pytest.mark.parametrize("remote", ("origin", "pkgcheck"))
75+
def test_commits_existing(self, remote, make_repo, make_git_repo, tmp_path):
7576
# create parent repo
7677
parent = make_repo()
7778
origin = make_git_repo(parent.location, commit=True)
@@ -80,9 +81,9 @@ def test_commits_existing(self, make_repo, make_git_repo, tmp_path):
8081

8182
# create child repo and pull from parent
8283
local = make_git_repo(str(tmp_path), commit=False)
83-
local.run(["git", "remote", "add", "origin", origin.path])
84-
local.run(["git", "pull", "origin", "main"])
85-
local.run(["git", "remote", "set-head", "origin", "main"])
84+
local.run(["git", "remote", "add", remote, origin.path])
85+
local.run(["git", "pull", remote, "main"])
86+
local.run(["git", "remote", "set-head", remote, "main"])
8687
child = make_repo(local.path)
8788

8889
# create local commits on child repo
@@ -91,7 +92,9 @@ def test_commits_existing(self, make_repo, make_git_repo, tmp_path):
9192
child.create_ebuild("cat/pkg-2")
9293
local.add_all("cat/pkg-2")
9394

94-
options, _func = self.tool.parse_args(self.args + ["-r", local.path, "--commits"])
95+
options, _func = self.tool.parse_args(
96+
self.args + ["-r", local.path, "--commits", "--git-remote", remote]
97+
)
9598
atom_restricts = [atom_cls("cat/pkg")]
9699
assert list(options.restrictions) == [
97100
(base.package_scope, packages.OrRestriction(*atom_restricts))

0 commit comments

Comments
 (0)