Skip to content

Commit 47ea3f3

Browse files
authored
Merge pull request #5012 from stsewd/more-hints-invalid-submodules
More hints for invalid submodules
2 parents 660d2a1 + 297aa25 commit 47ea3f3

File tree

4 files changed

+72
-39
lines changed

4 files changed

+72
-39
lines changed

readthedocs/projects/exceptions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class RepositoryError(BuildEnvironmentError):
4040
)
4141

4242
INVALID_SUBMODULES = _(
43-
'One or more submodule URLs are not valid.'
43+
'One or more submodule URLs are not valid: {}.'
4444
)
4545

4646
DUPLICATED_RESERVED_VERSIONS = _(

readthedocs/rtd_tests/tests/test_backend.py

+12-12
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ def test_git_branches(self, checkout_path):
5656
default_branches = [
5757
# comes from ``make_test_git`` function
5858
'submodule',
59-
'relativesubmodule',
6059
'invalidsubmodule',
6160
]
6261
branches = [
@@ -89,7 +88,6 @@ def test_git_branches_unicode(self, checkout_path):
8988
default_branches = [
9089
# comes from ``make_test_git`` function
9190
'submodule',
92-
'relativesubmodule',
9391
'invalidsubmodule',
9492
]
9593
branches = [
@@ -176,15 +174,19 @@ def test_check_submodule_urls(self):
176174
repo.checkout('submodule')
177175
valid, _ = repo.validate_submodules(self.dummy_conf)
178176
self.assertTrue(valid)
179-
repo.checkout('relativesubmodule')
180-
valid, _ = repo.validate_submodules(self.dummy_conf)
181-
self.assertTrue(valid)
182177

183-
@pytest.mark.xfail(strict=True, reason="Fixture is not working correctly")
184178
def test_check_invalid_submodule_urls(self):
179+
repo = self.project.vcs_repo()
180+
repo.update()
181+
r = repo.checkout('invalidsubmodule')
185182
with self.assertRaises(RepositoryError) as e:
186-
repo.checkout('invalidsubmodule')
187-
self.assertEqual(e.msg, RepositoryError.INVALID_SUBMODULES)
183+
repo.update_submodules(self.dummy_conf)
184+
# `invalid` is created in `make_test_git`
185+
# it's a url in ssh form.
186+
self.assertEqual(
187+
str(e.exception),
188+
RepositoryError.INVALID_SUBMODULES.format(['invalid'])
189+
)
188190

189191
@patch('readthedocs.projects.models.Project.checkout_path')
190192
def test_fetch_clean_tags_and_branches(self, checkout_path):
@@ -210,8 +212,7 @@ def test_fetch_clean_tags_and_branches(self, checkout_path):
210212
)
211213
self.assertEqual(
212214
set([
213-
'relativesubmodule', 'invalidsubmodule',
214-
'master', 'submodule', 'newbranch',
215+
'invalidsubmodule', 'master', 'submodule', 'newbranch',
215216
]),
216217
set(vcs.verbose_name for vcs in repo.branches)
217218
)
@@ -225,8 +226,7 @@ def test_fetch_clean_tags_and_branches(self, checkout_path):
225226
)
226227
self.assertEqual(
227228
set([
228-
'relativesubmodule', 'invalidsubmodule',
229-
'master', 'submodule'
229+
'invalidsubmodule', 'master', 'submodule'
230230
]),
231231
set(vcs.verbose_name for vcs in repo.branches)
232232
)

readthedocs/rtd_tests/utils.py

+47-23
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@
22
"""Utility functions for use in tests."""
33

44
from __future__ import (
5-
absolute_import, division, print_function, unicode_literals)
5+
absolute_import,
6+
division,
7+
print_function,
8+
unicode_literals,
9+
)
610

711
import logging
812
import subprocess
13+
import textwrap
914
from os import chdir, environ, mkdir
1015
from os.path import abspath
1116
from os.path import join as pjoin
@@ -55,34 +60,16 @@ def make_test_git():
5560
# URL are not allowed and using a real URL will require Internet to clone
5661
# the repo
5762
check_output(['git', 'checkout', '-b', 'submodule', 'master'], env=env)
58-
# https://stackoverflow.com/a/37378302/2187091
59-
mkdir(pjoin(directory, 'foobar'))
60-
gitmodules_path = pjoin(directory, '.gitmodules')
61-
with open(gitmodules_path, 'w') as fh:
62-
fh.write('''[submodule "foobar"]\n\tpath = foobar\n\turl = https://foobar.com/git\n''')
63-
check_output(
64-
[
65-
'git', 'update-index', '--add', '--cacheinfo', '160000',
66-
'233febf4846d7a0aeb95b6c28962e06e21d13688', 'foobar',
67-
],
68-
env=env,
63+
add_git_submodule_without_cloning(
64+
directory, 'foobar', 'https://foobar.com/git'
6965
)
7066
check_output(['git', 'add', '.'], env=env)
7167
check_output(['git', 'commit', '-m"Add submodule"'], env=env)
7268

73-
# Add a relative submodule URL in the relativesubmodule branch
74-
check_output(['git', 'checkout', '-b', 'relativesubmodule', 'master'], env=env)
75-
check_output(
76-
['git', 'submodule', 'add', '-b', 'master', './', 'relativesubmodule'],
77-
env=env
78-
)
79-
check_output(['git', 'add', '.'], env=env)
80-
check_output(['git', 'commit', '-m"Add relative submodule"'], env=env)
8169
# Add an invalid submodule URL in the invalidsubmodule branch
8270
check_output(['git', 'checkout', '-b', 'invalidsubmodule', 'master'], env=env)
83-
check_output(
84-
['git', 'submodule', 'add', '-b', 'master', './', 'invalidsubmodule'],
85-
env=env,
71+
add_git_submodule_without_cloning(
72+
directory, 'invalid', '[email protected]:rtfd/readthedocs.org.git'
8673
)
8774
check_output(['git', 'add', '.'], env=env)
8875
check_output(['git', 'commit', '-m"Add invalid submodule"'], env=env)
@@ -92,6 +79,43 @@ def make_test_git():
9279
return directory
9380

9481

82+
@restoring_chdir
83+
def add_git_submodule_without_cloning(directory, submodule, url):
84+
"""
85+
Add a submodule without cloning it.
86+
87+
We write directly to the git index, more details in:
88+
https://stackoverflow.com/a/37378302/2187091
89+
90+
:param directory: The directory where the git repo is
91+
:type directory: str
92+
:param submodule: The name of the submodule to be created
93+
:type submodule: str
94+
:param url: The url where the submodule points to
95+
:type url: str
96+
"""
97+
env = environ.copy()
98+
env['GIT_DIR'] = pjoin(directory, '.git')
99+
chdir(directory)
100+
101+
mkdir(pjoin(directory, submodule))
102+
gitmodules_path = pjoin(directory, '.gitmodules')
103+
with open(gitmodules_path, 'w+') as fh:
104+
content = textwrap.dedent('''
105+
[submodule "{submodule}"]
106+
path = {submodule}
107+
url = {url}
108+
''')
109+
fh.write(content.format(submodule=submodule, url=url))
110+
check_output(
111+
[
112+
'git', 'update-index', '--add', '--cacheinfo', '160000',
113+
'233febf4846d7a0aeb95b6c28962e06e21d13688', submodule,
114+
],
115+
env=env,
116+
)
117+
118+
95119
@restoring_chdir
96120
def make_git_repo(directory, name='sample_repo'):
97121
path = get_readthedocs_app_path()

readthedocs/vcs_support/backends/git.py

+12-3
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,16 @@ def validate_submodules(self, config):
9898
9999
:returns: tuple(bool, list)
100100
101-
Returns true if all required submodules URLs are valid.
101+
Returns `True` if all required submodules URLs are valid.
102102
Returns a list of all required submodules:
103103
- Include is `ALL`, returns all submodules avaliable.
104104
- Include is a list, returns just those.
105105
- Exclude is `ALL` - this should never happen.
106106
- Exlude is a list, returns all avaliable submodules
107107
but those from the list.
108+
109+
Returns `False` if at least one submodule is invalid.
110+
Returns the list of invalid submodules.
108111
"""
109112
repo = git.Repo(self.working_dir)
110113
submodules = {
@@ -124,11 +127,15 @@ def validate_submodules(self, config):
124127
submodules_include[path] = submodules[path]
125128
submodules = submodules_include
126129

130+
invalid_submodules = []
127131
for path, submodule in submodules.items():
128132
try:
129133
validate_submodule_url(submodule.url)
130134
except ValidationError:
131-
return False, []
135+
invalid_submodules.append(path)
136+
137+
if invalid_submodules:
138+
return False, invalid_submodules
132139
return True, submodules.keys()
133140

134141
def use_shallow_clone(self):
@@ -243,7 +250,9 @@ def update_submodules(self, config):
243250
if valid:
244251
self.checkout_submodules(submodules, config)
245252
else:
246-
raise RepositoryError(RepositoryError.INVALID_SUBMODULES)
253+
raise RepositoryError(
254+
RepositoryError.INVALID_SUBMODULES.format(submodules)
255+
)
247256

248257
def checkout_submodules(self, submodules, config):
249258
"""Checkout all repository submodules."""

0 commit comments

Comments
 (0)