Skip to content

Commit 242ccae

Browse files
authored
Merge pull request #4052 from stsewd/use-git-python-for-tags
Use gitpython for tags
2 parents 8203748 + fdba591 commit 242ccae

File tree

4 files changed

+69
-96
lines changed

4 files changed

+69
-96
lines changed

readthedocs/rtd_tests/tests/test_backend.py

+17-25
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
from __future__ import absolute_import
1+
# -*- coding: utf-8 -*-
2+
3+
from __future__ import absolute_import, unicode_literals
24
from os.path import exists
35

46
import pytest
@@ -9,7 +11,7 @@
911
from readthedocs.projects.models import Project, Feature
1012
from readthedocs.rtd_tests.base import RTDTestCase
1113

12-
from readthedocs.rtd_tests.utils import make_test_git, make_test_hg
14+
from readthedocs.rtd_tests.utils import create_git_tag, make_test_git, make_test_hg
1315

1416

1517
class TestGitBackend(RTDTestCase):
@@ -57,29 +59,19 @@ def test_git_checkout(self):
5759
repo.checkout()
5860
self.assertTrue(exists(repo.working_dir))
5961

60-
def test_parse_git_tags(self):
61-
data = """\
62-
3b32886c8d3cb815df3793b3937b2e91d0fb00f1 refs/tags/2.0.0
63-
bd533a768ff661991a689d3758fcfe72f455435d refs/tags/2.0.1
64-
c0288a17899b2c6818f74e3a90b77e2a1779f96a refs/tags/2.0.2
65-
a63a2de628a3ce89034b7d1a5ca5e8159534eef0 refs/tags/2.1.0.beta2
66-
c7fc3d16ed9dc0b19f0d27583ca661a64562d21e refs/tags/2.1.0.rc1
67-
edc0a2d02a0cc8eae8b67a3a275f65cd126c05b1 refs/tags/2.1.0.rc2
68-
274a5a8c988a804e40da098f59ec6c8f0378fe34 refs/tags/release/foobar
69-
"""
70-
expected_tags = [
71-
('3b32886c8d3cb815df3793b3937b2e91d0fb00f1', '2.0.0'),
72-
('bd533a768ff661991a689d3758fcfe72f455435d', '2.0.1'),
73-
('c0288a17899b2c6818f74e3a90b77e2a1779f96a', '2.0.2'),
74-
('a63a2de628a3ce89034b7d1a5ca5e8159534eef0', '2.1.0.beta2'),
75-
('c7fc3d16ed9dc0b19f0d27583ca661a64562d21e', '2.1.0.rc1'),
76-
('edc0a2d02a0cc8eae8b67a3a275f65cd126c05b1', '2.1.0.rc2'),
77-
('274a5a8c988a804e40da098f59ec6c8f0378fe34', 'release/foobar'),
78-
]
79-
80-
given_ids = [(x.identifier, x.verbose_name) for x in
81-
self.project.vcs_repo().parse_tags(data)]
82-
self.assertEqual(expected_tags, given_ids)
62+
def test_git_tags(self):
63+
repo_path = self.project.repo
64+
create_git_tag(repo_path, 'v01')
65+
create_git_tag(repo_path, 'v02', annotated=True)
66+
create_git_tag(repo_path, 'release-ünîø∂é')
67+
repo = self.project.vcs_repo()
68+
# We aren't cloning the repo,
69+
# so we need to hack the repo path
70+
repo.working_dir = repo_path
71+
self.assertEqual(
72+
set(['v01', 'v02', 'release-ünîø∂é']),
73+
set(vcs.verbose_name for vcs in repo.tags)
74+
)
8375

8476
def test_check_for_submodules(self):
8577
repo = self.project.vcs_repo()

readthedocs/rtd_tests/utils.py

+44-31
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Utility functions for use in tests."""
22

3-
from __future__ import absolute_import
3+
from __future__ import absolute_import, unicode_literals
44

55
import logging
66
import subprocess
@@ -16,12 +16,12 @@
1616
log = logging.getLogger(__name__)
1717

1818

19-
def check_output(l, env=()):
20-
if env == ():
21-
output = subprocess.Popen(l, stdout=subprocess.PIPE).communicate()[0]
22-
else:
23-
output = subprocess.Popen(l, stdout=subprocess.PIPE,
24-
env=env).communicate()[0]
19+
def check_output(command, env=None):
20+
output = subprocess.Popen(
21+
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
22+
env=env
23+
).communicate()[0]
24+
log.info(output)
2525
return output
2626

2727

@@ -36,63 +36,76 @@ def make_test_git():
3636
chdir(directory)
3737

3838
# Initialize and configure
39-
# TODO: move the ``log.info`` call inside the ``check_output```
40-
log.info(check_output(['git', 'init'] + [directory], env=env))
41-
log.info(check_output(
39+
check_output(['git', 'init'] + [directory], env=env)
40+
check_output(
4241
['git', 'config', 'user.email', '[email protected]'],
4342
env=env
44-
))
45-
log.info(check_output(
43+
)
44+
check_output(
4645
['git', 'config', 'user.name', 'Read the Docs'],
4746
env=env
48-
))
47+
)
4948

5049
# Set up the actual repository
51-
log.info(check_output(['git', 'add', '.'], env=env))
52-
log.info(check_output(['git', 'commit', '-m"init"'], env=env))
50+
check_output(['git', 'add', '.'], env=env)
51+
check_output(['git', 'commit', '-m"init"'], env=env)
5352

5453
# Add fake repo as submodule. We need to fake this here because local path
5554
# URL are not allowed and using a real URL will require Internet to clone
5655
# the repo
57-
log.info(check_output(['git', 'checkout', '-b', 'submodule', 'master'], env=env))
56+
check_output(['git', 'checkout', '-b', 'submodule', 'master'], env=env)
5857
# https://stackoverflow.com/a/37378302/2187091
5958
mkdir(pjoin(directory, 'foobar'))
6059
gitmodules_path = pjoin(directory, '.gitmodules')
6160
with open(gitmodules_path, 'w') as fh:
6261
fh.write('''[submodule "foobar"]\n\tpath = foobar\n\turl = https://foobar.com/git\n''')
63-
log.info(check_output(
62+
check_output(
6463
[
6564
'git', 'update-index', '--add', '--cacheinfo', '160000',
6665
'233febf4846d7a0aeb95b6c28962e06e21d13688', 'foobar',
6766
],
6867
env=env,
69-
))
70-
log.info(check_output(['git', 'add', '.'], env=env))
71-
log.info(check_output(['git', 'commit', '-m"Add submodule"'], env=env))
68+
)
69+
check_output(['git', 'add', '.'], env=env)
70+
check_output(['git', 'commit', '-m"Add submodule"'], env=env)
7271

7372
# Add a relative submodule URL in the relativesubmodule branch
74-
log.info(check_output(['git', 'checkout', '-b', 'relativesubmodule', 'master'], env=env))
75-
log.info(check_output(
73+
check_output(['git', 'checkout', '-b', 'relativesubmodule', 'master'], env=env)
74+
check_output(
7675
['git', 'submodule', 'add', '-b', 'master', './', 'relativesubmodule'],
7776
env=env
78-
))
79-
log.info(check_output(['git', 'add', '.'], env=env))
80-
log.info(check_output(['git', 'commit', '-m"Add relative submodule"'], env=env))
77+
)
78+
check_output(['git', 'add', '.'], env=env)
79+
check_output(['git', 'commit', '-m"Add relative submodule"'], env=env)
8180
# Add an invalid submodule URL in the invalidsubmodule branch
82-
log.info(check_output(['git', 'checkout', '-b', 'invalidsubmodule', 'master'], env=env))
83-
log.info(check_output(
81+
check_output(['git', 'checkout', '-b', 'invalidsubmodule', 'master'], env=env)
82+
check_output(
8483
['git', 'submodule', 'add', '-b', 'master', './', 'invalidsubmodule'],
8584
env=env,
86-
))
87-
log.info(check_output(['git', 'add', '.'], env=env))
88-
log.info(check_output(['git', 'commit', '-m"Add invalid submodule"'], env=env))
85+
)
86+
check_output(['git', 'add', '.'], env=env)
87+
check_output(['git', 'commit', '-m"Add invalid submodule"'], env=env)
8988

9089
# Checkout to master branch again
91-
log.info(check_output(['git', 'checkout', 'master'], env=env))
90+
check_output(['git', 'checkout', 'master'], env=env)
9291
chdir(path)
9392
return directory
9493

9594

95+
def create_git_tag(directory, tag, annotated=False):
96+
env = environ.copy()
97+
env['GIT_DIR'] = pjoin(directory, '.git')
98+
path = getcwd()
99+
chdir(directory)
100+
101+
command = ['git', 'tag']
102+
if annotated:
103+
command.extend(['-a', '-m', 'Some tag'])
104+
command.append(tag)
105+
check_output(command, env=env)
106+
chdir(path)
107+
108+
96109
def make_test_hg():
97110
directory = mkdtemp()
98111
path = getcwd()

readthedocs/vcs_support/backends/git.py

+7-40
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from readthedocs.core.validators import validate_submodule_url
1818
from readthedocs.projects.exceptions import RepositoryError
1919
from readthedocs.vcs_support.base import BaseVCS, VCSVersion
20+
from builtins import str
2021

2122
log = logging.getLogger(__name__)
2223

@@ -122,46 +123,12 @@ def clone(self):
122123

123124
@property
124125
def tags(self):
125-
retcode, stdout, _ = self.run(
126-
'git',
127-
'show-ref',
128-
'--tags',
129-
record_as_success=True,
130-
)
131-
# error (or no tags found)
132-
if retcode != 0:
133-
return []
134-
return self.parse_tags(stdout)
135-
136-
def parse_tags(self, data):
137-
"""
138-
Parses output of show-ref --tags, eg:
139-
140-
3b32886c8d3cb815df3793b3937b2e91d0fb00f1 refs/tags/2.0.0
141-
bd533a768ff661991a689d3758fcfe72f455435d refs/tags/2.0.1
142-
c0288a17899b2c6818f74e3a90b77e2a1779f96a refs/tags/2.0.2
143-
a63a2de628a3ce89034b7d1a5ca5e8159534eef0 refs/tags/2.1.0.beta2
144-
c7fc3d16ed9dc0b19f0d27583ca661a64562d21e refs/tags/2.1.0.rc1
145-
edc0a2d02a0cc8eae8b67a3a275f65cd126c05b1 refs/tags/2.1.0.rc2
146-
147-
Into VCSTag objects with the tag name as verbose_name and the commit
148-
hash as identifier.
149-
"""
150-
# parse the lines into a list of tuples (commit-hash, tag ref name)
151-
# StringIO below is expecting Unicode data, so ensure that it gets it.
152-
if not isinstance(data, str):
153-
data = str(data)
154-
delimiter = str(' ').encode('utf-8') if PY2 else str(' ')
155-
raw_tags = csv.reader(StringIO(data), delimiter=delimiter)
156-
vcs_tags = []
157-
for row in raw_tags:
158-
row = [f for f in row if f != '']
159-
if row == []:
160-
continue
161-
commit_hash, name = row
162-
clean_name = name.replace('refs/tags/', '')
163-
vcs_tags.append(VCSVersion(self, commit_hash, clean_name))
164-
return vcs_tags
126+
repo = git.Repo(self.working_dir)
127+
versions = [
128+
VCSVersion(self, str(tag.commit), str(tag))
129+
for tag in repo.tags
130+
]
131+
return versions
165132

166133
@property
167134
def branches(self):

tox.ini

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ setenv =
1414
PYTHONPATH={toxinidir}/readthedocs:{toxinidir}
1515
DJANGO_SETTINGS_MODULE=readthedocs.settings.test
1616
LANG=C
17+
LC_CTYPE=C.UTF-8
1718
DJANGO_SETTINGS_SKIP_LOCAL=True
1819
deps = -r{toxinidir}/requirements/testing.txt
1920
changedir = {toxinidir}/readthedocs

0 commit comments

Comments
 (0)