From a89ecbb0aaedbe2e9db8c2377b784d3118a5244b Mon Sep 17 00:00:00 2001 From: Lubomír Sedlář Date: Feb 09 2018 20:17:28 +0000 Subject: Get correct default branch The API does not provide this information, but we don't really need it. In ideal word we could just do `git ls-remote --symref GIT_URL HEAD` and get the information, but for some reason this does not currently work with Pagure. Default branch should be whatever HEAD points to in the remote repo, and since we most likely work in a clone of it, the ref will exist locally as well. --- diff --git a/pag/utils.py b/pag/utils.py index e6d75e2..be08f22 100644 --- a/pag/utils.py +++ b/pag/utils.py @@ -18,12 +18,13 @@ except ImportError: CONF_FILE = os.path.expanduser('~/.config/pag') -def run(cmd, echo=True, graceful=True): - click.echo(' $ ' + " ".join(cmd)) +def run(cmd, echo=True, graceful=True, silent=False): + if not silent: + click.echo(' $ ' + " ".join(cmd)) proc = sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.STDOUT) output, _ = proc.communicate() output = output.decode('utf-8') - if echo: + if echo and not silent: click.echo(DIM + output + RESET) if not graceful and proc.returncode != 0: sys.exit(1) @@ -65,20 +66,21 @@ def eager_command(func): return inner -def get_default_upstream_branch(name): - url = 'https://pagure.io/api/0/projects' - response = requests.get(url, params=dict(pattern=name, fork=False)) - if not bool(response): - raise IOError("Failed to talk to %r %r", (url, response)) - data = response.json() - projects = data['projects'] - if not projects: - raise ValueError("No such project %r" % name) - if len(projects) > 1: - raise ValueError("More than one project called %r found " - "(%i of them, in fact)." % (name, len(projects))) - project = projects[0] - return project['default_branch'] +def get_default_upstream_branch(): + """The default branch is whatever HEAD points to in the remote repo. + Usually the main repo will be either `upstream` or `origin`, so try both. + Returns ``None`` if no default branch could be found. + """ + # TODO We should instead use `git ls-remote --symref REMOTE_URL HEAD`, but + # that does not currently work. + # https://pagure.io/pagure/issue/2955 + for remote in ('upstream', 'origin'): + ref = '%s/HEAD' % remote + ret, stdout = run(['git', 'rev-parse', '--abbrev-ref', ref], silent=True) + if ret == 0: + real_ref = stdout.strip() + assert real_ref.startswith('%s/' % remote) + return real_ref[len(remote) + 1:] def get_current_local_branch(): diff --git a/tests/test_utils.py b/tests/test_utils.py index df6199e..bc18b9e 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -8,12 +8,16 @@ import unittest from pag import utils -class TestGetCurrentBranch(unittest.TestCase): +class GitTestCase(unittest.TestCase): + """ + A base class for tests that need a git repo. It creates a temporary repo + with a single commit for each test and changes to that directory. + """ - def cmd(self, cmd, *args, **kwargs): + def cmd(self, cmd, cwd=None, *args, **kwargs): print('$ %s' % ' '.join(shlex.quote(x) for x in cmd)) cp = subprocess.run(cmd, *args, - cwd=self.repo, + cwd=cwd or self.repo, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, @@ -34,6 +38,55 @@ class TestGetCurrentBranch(unittest.TestCase): def tearDown(self): shutil.rmtree(self.repo) + +class TestGetDefaultBranch(GitTestCase): + """ + This test treats the inherited repo as upstream and clones it into a + separate directory, in which it runs the actual function. It can check out + a different branch in the "upstream" repo and thus effectively change the + default branch. + """ + + def setUp(self): + super().setUp() + self.clone = tempfile.mkdtemp(prefix='cloned_repo_') + + def tearDown(self): + super().tearDown() + shutil.rmtree(self.clone) + + def _clone_to(self, remote, branch): + if branch != 'master': + self.cmd(['git', 'checkout', '-b', branch]) + self.cmd(['git', 'clone', self.repo, self.clone, '-o', remote]) + os.chdir(self.clone) + + def test_origin_master(self): + self._clone_to('origin', 'master') + + self.assertEqual(utils.get_default_upstream_branch(), 'master') + + def test_origin_develop(self): + self._clone_to('origin', 'develop') + + self.assertEqual(utils.get_default_upstream_branch(), 'develop') + + def test_upstream_master(self): + self._clone_to('upstream', 'master') + + self.assertEqual(utils.get_default_upstream_branch(), 'master') + + def test_upstream_develop(self): + self._clone_to('upstream', 'develop') + + self.assertEqual(utils.get_default_upstream_branch(), 'develop') + + def test_no_remote(self): + self.assertEqual(utils.get_default_upstream_branch(), None) + + +class TestGetCurrentBranch(GitTestCase): + def test_single_branch(self): self.cmd(['git', 'checkout', '-b', 'test']) self.cmd(['git', 'commit', '--allow-empty', '-m', 'Dummy commit'])