Package: git-buildpackage Followup-For: Bug #1010751 Hello.
0001 seems obsolete. 0002 is improved by IntEnum 0004-6 are improved by NamedTuple, making 0003 unnecessary All tests pass and mypy is happy. By the way, the source package differs a lot from the git repository. It embeds lots of things into tests/component/deb/data/*. Is this deliberate?
>From 28076a16a87d57b395dc7529b88c18565548813b Mon Sep 17 00:00:00 2001 From: Nicolas Boulenguez <[email protected]> Date: Sat, 30 Nov 2024 13:29:13 +0100 Subject: [PATCH 1/2] clone: make ExitCodes a subclass of IntEnum --- gbp/scripts/clone.py | 16 +++++++--------- gbp/scripts/common/__init__.py | 3 ++- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/gbp/scripts/clone.py b/gbp/scripts/clone.py index c72c74b8..ac063b09 100755 --- a/gbp/scripts/clone.py +++ b/gbp/scripts/clone.py @@ -178,26 +178,24 @@ def parse_args(argv): def main(argv) -> int: - retval = 0 - (options, args) = parse_args(argv) if not options: return ExitCodes.parse_error if len(args) < 2: gbp.log.err("Need a repository to clone.") - return 1 + return ExitCodes.failed else: remote_repo = args[1] source = repo_to_url(remote_repo) if options.aliases else remote_repo if not source: - return 1 + return ExitCodes.failed clone_to, auto_name = (os.path.curdir, True) if len(args) < 3 else (args[2], False) try: GitRepository(clone_to) gbp.log.err("Can't run inside a git repository.") - return 1 + return ExitCodes.failed except GitRepositoryError: pass @@ -250,17 +248,17 @@ def main(argv) -> int: )() except KeyboardInterrupt: - retval = 1 gbp.log.err("Interrupted. Aborting.") + return ExitCodes.failed except GitRepositoryError as err: gbp.log.err("Git command failed: %s" % err) - retval = 1 + return ExitCodes.failed except GbpError as err: if str(err): gbp.log.err(err) - retval = 1 + return ExitCodes.failed - return retval + return ExitCodes.ok if __name__ == '__main__': diff --git a/gbp/scripts/common/__init__.py b/gbp/scripts/common/__init__.py index ff39b257..59b197a9 100644 --- a/gbp/scripts/common/__init__.py +++ b/gbp/scripts/common/__init__.py @@ -16,6 +16,7 @@ # <http://www.gnu.org/licenses/> """Parts shared between the deb and rpm commands""" +import enum import re import os import traceback @@ -25,7 +26,7 @@ from gbp.pkg import Archive from gbp.deb.upstreamsource import DebianAdditionalTarball -class ExitCodes(object): +class ExitCodes(enum.IntEnum): ok = 0, failed = 1 # All other errors no_value = 2 # Value does not exist (gbp config only) -- 2.47.3
>From 9e02f887fcbb6aeaaab77665c77bfb10a834ddf7 Mon Sep 17 00:00:00 2001 From: Nicolas Boulenguez <[email protected]> Date: Tue, 24 Feb 2026 01:52:14 +0100 Subject: [PATCH 2/2] clone: handle -b optional branch specification in VCS-Git Add typing annotations and match statements Test repo_to_url, vcs_git_url is an implementation detail. Remove the confusing case with '-b foo' from the version selection test. --- gbp/scripts/clone.py | 80 +++++++++++++++++++++++--------------- tests/test_29_gbp_clone.py | 50 ++++++++++++++++++++---- 2 files changed, 90 insertions(+), 40 deletions(-) diff --git a/gbp/scripts/clone.py b/gbp/scripts/clone.py index ac063b09..dfedf0e1 100755 --- a/gbp/scripts/clone.py +++ b/gbp/scripts/clone.py @@ -22,6 +22,7 @@ import re import sys import os +import typing import yaml from gbp.config import (GbpOptionParser, GbpOptionGroup) from gbp.deb.git import DebianGitRepository @@ -37,6 +38,11 @@ import gbp.log from functools import cmp_to_key +class VCSGit(typing.NamedTuple): + repo: str + branch: str | None = None + + def apt_showsrc(pkg: str) -> str: try: aptsrc = Command("apt-cache", ["showsrc", pkg], capture_stdout=True) @@ -46,19 +52,22 @@ def apt_showsrc(pkg: str) -> str: return '' -def vcs_git_url(pkg: str) -> str | None: - repos = {} +def vcs_git_url(pkg: str) -> VCSGit | None: + repos = dict[str, VCSGit]() out = apt_showsrc(pkg) - vcs_re = re.compile(r'(x-)?vcs-git:\s*(?P<repo>[\S]+).*$', re.I) + vcs_re = re.compile( + r'(?:x-)?vcs-git:\s*(?P<repo>\S+)(?:\s+-b\s+(?P<branch>\S+))?$', re.I + ) version_re = re.compile(r'Version:\s*(?P<version>.*)$', re.I) end_re = re.compile(r'\s*$') - version = repo = None + version: str | None = None + repo: VCSGit | None = None for line in out.split('\n'): m = vcs_re.match(line) if m: - repo = m.group('repo') + repo = VCSGit(repo=m['repo'], branch=m['branch']) continue m = version_re.match(line) if m: @@ -78,29 +87,24 @@ def vcs_git_url(pkg: str) -> str | None: return repos[s[-1]] -def repo_to_url(repo: str) -> str | None: +def repo_to_url(repo: str) -> VCSGit | None: """ >>> repo_to_url("https://foo.example.com") - 'https://foo.example.com' + VCSGit(repo='https://foo.example.com', branch=None) >>> repo_to_url("salsa:agx/git-buildpackage") - 'https://salsa.debian.org/agx/git-buildpackage.git' + VCSGit(repo='https://salsa.debian.org/agx/git-buildpackage.git', branch=None) >>> repo_to_url("github:agx/git-buildpackage") - 'https://github.com/agx/git-buildpackage.git' + VCSGit(repo='https://github.com/agx/git-buildpackage.git', branch=None) """ - parts = repo.split(":", 1) - if len(parts) != 2: - return repo - else: - proto, path = parts - - if proto == 'salsa': - return 'https://salsa.debian.org/%s.git' % path - if proto == 'github': - return 'https://github.com/%s.git' % path - elif proto in ['vcsgit', 'vcs-git']: - return vcs_git_url(path) - else: - return repo + match repo.split(":", 1): + case 'salsa', path: + return VCSGit(repo='https://salsa.debian.org/%s.git' % path) + case 'github', path: + return VCSGit(repo='https://github.com/%s.git' % path) + case 'vcsgit' | 'vcs-git', path: + return vcs_git_url(path) + case _: + return VCSGit(repo=repo) def add_upstream_vcs(repo): @@ -182,16 +186,23 @@ def main(argv) -> int: if not options: return ExitCodes.parse_error - if len(args) < 2: - gbp.log.err("Need a repository to clone.") - return ExitCodes.failed - else: - remote_repo = args[1] - source = repo_to_url(remote_repo) if options.aliases else remote_repo + match args: + case _, remote_repo: + clone_to = os.path.curdir + auto_name = True + case _, remote_repo, clone_to: + auto_name = False + case _: + gbp.log.err("Expected a repository and an optional directory.") + return ExitCodes.failed + + if options.aliases: + source = repo_to_url(remote_repo) if not source: return ExitCodes.failed + else: + source = VCSGit(repo=remote_repo) - clone_to, auto_name = (os.path.curdir, True) if len(args) < 3 else (args[2], False) try: GitRepository(clone_to) gbp.log.err("Can't run inside a git repository.") @@ -200,8 +211,8 @@ def main(argv) -> int: pass try: - gbp.log.info("Cloning from '%s'%s" % (source, " into '%s'" % clone_to if not auto_name else '')) - repo = DebianGitRepository.clone(clone_to, source, options.depth, + gbp.log.info("Cloning from '%s'%s" % (source.repo, '' if auto_name else " into '%s'" % clone_to)) + repo = DebianGitRepository.clone(clone_to, source.repo, options.depth, auto_name=auto_name, reference=options.reference) os.chdir(repo.path) @@ -210,6 +221,11 @@ def main(argv) -> int: postclone = options.postclone (options, args) = parse_args(argv) + if source.branch and source.branch != options.debian_branch: + gbp.log.warn(f"VCS-Git: -b {source.branch} overrides" + f" --debian-branch={options.debian_branch}") + options.debian_branch = source.branch + # Track all branches: if options.all: remotes = repo.get_remote_branches() diff --git a/tests/test_29_gbp_clone.py b/tests/test_29_gbp_clone.py index 96bd905e..a47fa754 100644 --- a/tests/test_29_gbp_clone.py +++ b/tests/test_29_gbp_clone.py @@ -1,5 +1,5 @@ # vim: set fileencoding=utf-8 : -from gbp.scripts.clone import vcs_git_url +from gbp.scripts.clone import VCSGit, repo_to_url import unittest from unittest.mock import patch @@ -8,15 +8,41 @@ from . testutils import skip_without_cmd class TestGbpClone(unittest.TestCase): + + def test_repo_to_url(self): + arg = "https://foo.example.com" + exp = VCSGit(arg, None) + self.assertEqual(repo_to_url(arg), exp) + + def test_repo_to_url_salsa(self): + arg = "salsa:agx/git-buildpackage" + exp = VCSGit("https://salsa.debian.org/agx/git-buildpackage.git", None) + self.assertEqual(repo_to_url(arg), exp) + + def test_repo_to_url_github(self): + arg = "github:agx/git-buildpackage" + exp = VCSGit("https://github.com/agx/git-buildpackage.git", None) + self.assertEqual(repo_to_url(arg), exp) + + @skip_without_cmd("dpkg") + @patch("gbp.scripts.clone.apt_showsrc", return_value="VCS-Git: https://a") + def test_repo_to_url_vcs_git(self, patch): + arg = "vcs-git:pkg" + exp = VCSGit("https://a", None) + self.assertEqual(repo_to_url(arg), exp) + + @skip_without_cmd("dpkg") + @patch("gbp.scripts.clone.apt_showsrc", return_value="VCS-Git: https://a") + def test_repo_to_url_vcs_git_alias(self, patch): + arg = "vcsgit:pkg" + exp = VCSGit("https://a", None) + self.assertEqual(repo_to_url(arg), exp) + show_src = """ Version: 0.6.22 Standards-Version: 3.9.4 Vcs-Git: git://honk.sigxcpu.org/git/git-buildpackage.git -Version: 0.8.14 -Standards-Version: 3.9.8 -Vcs-Git: https://git.sigxcpu.org/cgit/git-buildpackage/ -b foo - Version: 0.8.12.2 Standards-Version: 3.9.8 Vcs-Git: https://git.sigxcpu.org/cgit/git-buildpackage/ @@ -29,6 +55,14 @@ Vcs-Git: git://honk.sigxcpu.org/git/git-buildpackage.git @skip_without_cmd('dpkg') @patch('gbp.scripts.clone.apt_showsrc', return_value=show_src) - def test_vcs_git_url(self, patch): - self.assertEqual(vcs_git_url('git-buildpackage'), - 'https://git.sigxcpu.org/cgit/git-buildpackage/') + def test_repo_to_url_vcs_git_version(self, patch): + arg = 'vcs-git:git-buildpackage' + exp = VCSGit('https://git.sigxcpu.org/cgit/git-buildpackage/', None) + self.assertEqual(repo_to_url(arg), exp) + + @skip_without_cmd('dpkg') + @patch('gbp.scripts.clone.apt_showsrc', return_value='VCS-Git: h://a -b d') + def test_repo_to_url_vcs_git_branch(self, patch): + arg = 'vcs-git:pkg' + exp = VCSGit('h://a', 'd') + self.assertEqual(repo_to_url(arg), exp) -- 2.47.3

