Skip to content

Commit 5ef8f9e

Browse files
committed
Cloning from push remote instead of origin.
If HTML files are pushed to another repo other than origin it doesn't make sense to clone from origin (previous files won't be available).
1 parent 2865ba8 commit 5ef8f9e

File tree

5 files changed

+118
-34
lines changed

5 files changed

+118
-34
lines changed

README.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ Changelog
4444

4545
This project adheres to `Semantic Versioning <http://semver.org/>`_.
4646

47+
Unreleased
48+
----------
49+
50+
Fixed
51+
* Cloning from push remote instead of origin. If HTML files are pushed to another repo other than origin it doesn't
52+
make sense to clone from origin (previous files won't be available).
53+
4754
2.1.1 - 2016-08-23
4855
------------------
4956

sphinxcontrib/versioning/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ def push(ctx, config, rel_source, dest_branch, rel_dest, **options):
365365
with TempDir() as temp_dir:
366366
log.info('Cloning %s into temporary directory...', dest_branch)
367367
try:
368-
clone(config.git_root, temp_dir, dest_branch, rel_dest, config.grm_exclude)
368+
clone(config.git_root, temp_dir, config.push_remote, dest_branch, rel_dest, config.grm_exclude)
369369
except GitError as exc:
370370
log.error(exc.message)
371371
log.error(exc.output)

sphinxcontrib/versioning/git.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -299,32 +299,36 @@ def export(local_root, commit, target):
299299
log.debug('Skipping broken symlink: %s', args[0])
300300

301301

302-
def clone(local_root, new_root, branch, rel_dest, exclude):
302+
def clone(local_root, new_root, remote, branch, rel_dest, exclude):
303303
"""Clone "local_root" origin into a new directory and check out a specific branch. Optionally run "git rm".
304304
305305
:raise CalledProcessError: Unhandled git command failure.
306306
:raise GitError: Handled git failures.
307307
308308
:param str local_root: Local path to git root directory.
309309
:param str new_root: Local path empty directory in which branch will be cloned into.
310+
:param str remote: The git remote to clone from to.
310311
:param str branch: Checkout this branch.
311312
:param str rel_dest: Run "git rm" on this directory if exclude is truthy.
312313
:param iter exclude: List of strings representing relative file paths to exclude from "git rm".
313314
"""
314315
log = logging.getLogger(__name__)
315316
output = run_command(local_root, ['git', 'remote', '-v'])
316-
matches = RE_ALL_REMOTES.findall(output)
317-
if not matches:
317+
remotes = dict()
318+
for match in RE_ALL_REMOTES.findall(output):
319+
remotes.setdefault(match[0], [None, None])
320+
if match[2] == 'fetch':
321+
remotes[match[0]][0] = match[1]
322+
else:
323+
remotes[match[0]][1] = match[1]
324+
if not remotes:
318325
raise GitError('Git repo has no remotes.', output)
319-
remotes = {m[0]: [m[1], ''] for m in matches if m[2] == 'fetch'}
320-
for match in (m for m in matches if m[2] == 'push'):
321-
remotes[match[0]][1] = match[1]
322-
if 'origin' not in remotes:
323-
raise GitError('Git repo missing remote "origin".', output)
326+
if remote not in remotes:
327+
raise GitError('Git repo missing remote "{}".'.format(remote), output)
324328

325329
# Clone.
326330
try:
327-
run_command(new_root, ['git', 'clone', remotes['origin'][0], '--depth=1', '--branch', branch, '.'])
331+
run_command(new_root, ['git', 'clone', remotes[remote][0], '--depth=1', '--branch', branch, '.'])
328332
except CalledProcessError as exc:
329333
raise GitError('Failed to clone from remote repo URL.', exc.output)
330334

@@ -336,8 +340,7 @@ def clone(local_root, new_root, branch, rel_dest, exclude):
336340

337341
# Copy all remotes from original repo.
338342
for name, (fetch, push) in remotes.items():
339-
if name != 'origin':
340-
run_command(new_root, ['git', 'remote', 'add', name, fetch])
343+
run_command(new_root, ['git', 'remote', 'set-url' if name == 'origin' else 'add', name, fetch])
341344
run_command(new_root, ['git', 'remote', 'set-url', '--push', name, push])
342345

343346
# Done if no exclude.

tests/test__main__/test_main_push_scenarios.py

Lines changed: 84 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -164,41 +164,115 @@ def test_race(tmpdir, local_docs_ghp, remote, run, urls, give_up):
164164
assert actual == 'Orphaned branch for HTML docs.changed'
165165

166166

167-
def test_second_remote(tmpdir, local_docs_ghp, run, urls):
168-
"""Test pushing to a non-origin remote.
167+
def test_different_push(tmpdir, local_docs_ghp, run, urls):
168+
"""Test pushing to a different remote URL.
169169
170170
:param tmpdir: pytest fixture.
171171
:param local_docs_ghp: conftest fixture.
172172
:param run: conftest fixture.
173173
:param urls: conftest fixture.
174174
"""
175+
remote2 = tmpdir.ensure_dir('remote2')
176+
run(local_docs_ghp, ['git', 'remote', 'set-url', 'origin', '--push', remote2])
177+
175178
# Error out because remote2 doesn't exist yet.
176179
with pytest.raises(CalledProcessError) as exc:
177-
run(local_docs_ghp, ['sphinx-versioning', 'push', '.', 'gh-pages', '.', '-P', 'remote2'])
180+
run(local_docs_ghp, ['sphinx-versioning', 'push', '.', 'gh-pages', '.'])
178181
assert 'Traceback' not in exc.value.output
179182
assert 'Failed to push to remote.' in exc.value.output
180-
assert "fatal: 'remote2' does not appear to be a git repository" in exc.value.output
183+
assert "remote2' does not appear to be a git repository" in exc.value.output
184+
185+
# Create remote2.
186+
run(remote2, ['git', 'init', '--bare'])
187+
188+
# Run again.
189+
output = run(local_docs_ghp, ['sphinx-versioning', 'push', '.', 'gh-pages', '.'])
190+
assert 'Traceback' not in output
191+
assert 'Successfully pushed to remote repository.' in output
192+
193+
# Check files.
194+
run(local_docs_ghp, ['git', 'fetch', 'origin'])
195+
run(local_docs_ghp, ['git', 'checkout', 'origin/gh-pages'])
196+
assert not local_docs_ghp.join('contents.html').check()
197+
assert not local_docs_ghp.join('master').check()
198+
run(local_docs_ghp, ['git', 'remote', 'add', 'remote2', remote2])
199+
run(local_docs_ghp, ['git', 'fetch', 'remote2'])
200+
run(local_docs_ghp, ['git', 'checkout', 'remote2/gh-pages'])
201+
urls(local_docs_ghp.join('contents.html'), ['<li><a href="master/contents.html">master</a></li>'])
202+
urls(local_docs_ghp.join('master', 'contents.html'), ['<li><a href="contents.html">master</a></li>'])
203+
204+
205+
@pytest.mark.parametrize('remove', [True, False])
206+
def test_second_remote(tmpdir, local_docs_ghp, run, urls, remove):
207+
"""Test pushing to a non-origin remote without the original remote having the destination branch.
208+
209+
:param tmpdir: pytest fixture.
210+
:param local_docs_ghp: conftest fixture.
211+
:param run: conftest fixture.
212+
:param urls: conftest fixture.
213+
:param bool remove: Remove gh-pages from origin.
214+
"""
215+
if remove:
216+
run(local_docs_ghp, ['git', 'push', 'origin', '--delete', 'gh-pages'])
181217

182218
# Create remote2.
183219
remote2 = tmpdir.ensure_dir('remote2')
184220
run(remote2, ['git', 'init', '--bare'])
221+
local2 = tmpdir.ensure_dir('local2')
222+
run(local2, ['git', 'clone', remote2, '.'])
223+
run(local2, ['git', 'checkout', '-b', 'gh-pages'])
224+
local2.ensure('README')
225+
run(local2, ['git', 'add', 'README'])
226+
run(local2, ['git', 'commit', '-m', 'Initial commit.'])
227+
run(local2, ['git', 'push', 'origin', 'gh-pages'])
185228
run(local_docs_ghp, ['git', 'remote', 'add', 'remote2', remote2])
186-
run(local_docs_ghp, ['git', 'push', 'remote2', 'gh-pages'])
229+
run(local_docs_ghp, ['git', 'fetch', 'remote2'])
230+
231+
# Run.
232+
output = run(local_docs_ghp, ['sphinx-versioning', 'push', '.', 'gh-pages', '.', '-P', 'remote2'])
233+
assert 'Traceback' not in output
234+
assert 'Successfully pushed to remote repository.' in output
235+
236+
# Check files.
237+
run(local_docs_ghp, ['git', 'fetch', 'remote2'])
238+
run(local_docs_ghp, ['git', 'checkout', 'remote2/gh-pages'])
239+
urls(local_docs_ghp.join('contents.html'), ['<li><a href="master/contents.html">master</a></li>'])
240+
urls(local_docs_ghp.join('master', 'contents.html'), ['<li><a href="contents.html">master</a></li>'])
241+
if remove:
242+
with pytest.raises(CalledProcessError) as exc:
243+
run(local_docs_ghp, ['git', 'checkout', 'origin/gh-pages'])
244+
assert "origin/gh-pages' did not match any file(s) known to git." in exc.value.output
245+
else:
246+
run(local_docs_ghp, ['git', 'checkout', 'origin/gh-pages'])
247+
run(local_docs_ghp, ['git', 'pull', 'origin', 'gh-pages'])
248+
assert not local_docs_ghp.join('contents.html').check()
249+
assert not local_docs_ghp.join('master').check()
187250

188251
# Run again.
252+
run(local_docs_ghp, ['git', 'checkout', 'master'])
253+
local_docs_ghp.join('contents.rst').write('\nNew Line Added\n', mode='a')
254+
run(local_docs_ghp, ['git', 'commit', '-am', 'Adding new line.'])
255+
run(local_docs_ghp, ['git', 'push', 'origin', 'master'])
189256
output = run(local_docs_ghp, ['sphinx-versioning', 'push', '.', 'gh-pages', '.', '-P', 'remote2'])
190257
assert 'Traceback' not in output
191258
assert 'Successfully pushed to remote repository.' in output
192259

193260
# Check files.
261+
run(local_docs_ghp, ['git', 'fetch', 'remote2'])
194262
run(local_docs_ghp, ['git', 'checkout', 'remote2/gh-pages'])
195-
run(local_docs_ghp, ['git', 'pull', 'remote2', 'gh-pages'])
196263
urls(local_docs_ghp.join('contents.html'), ['<li><a href="master/contents.html">master</a></li>'])
197264
urls(local_docs_ghp.join('master', 'contents.html'), ['<li><a href="contents.html">master</a></li>'])
198-
run(local_docs_ghp, ['git', 'checkout', 'origin/gh-pages'])
199-
run(local_docs_ghp, ['git', 'pull', 'origin', 'gh-pages'])
200-
assert not local_docs_ghp.join('contents.html').check()
201-
assert not local_docs_ghp.join('master').check()
265+
contents = local_docs_ghp.join('contents.html').read()
266+
assert 'New Line Added' in contents
267+
if remove:
268+
with pytest.raises(CalledProcessError) as exc:
269+
run(local_docs_ghp, ['git', 'checkout', 'origin/gh-pages'])
270+
assert "origin/gh-pages' did not match any file(s) known to git." in exc.value.output
271+
else:
272+
run(local_docs_ghp, ['git', 'checkout', 'origin/gh-pages'])
273+
run(local_docs_ghp, ['git', 'pull', 'origin', 'gh-pages'])
274+
assert not local_docs_ghp.join('contents.html').check()
275+
assert not local_docs_ghp.join('master').check()
202276

203277

204278
def test_error_clone_failure(local_docs, run):

tests/test_git/test_clone.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def test_no_exclude(tmpdir, local_docs, run):
1515
:param run: conftest fixture.
1616
"""
1717
new_root = tmpdir.ensure_dir('new_root')
18-
clone(str(local_docs), str(new_root), 'master', '', None)
18+
clone(str(local_docs), str(new_root), 'origin', 'master', '', None)
1919
assert new_root.join('conf.py').check(file=True)
2020
assert new_root.join('contents.rst').check(file=True)
2121
assert new_root.join('README').check(file=True)
@@ -48,7 +48,7 @@ def test_exclude(tmpdir, local, run):
4848
'README', 'two.txt', 'sub/four.txt', # Only leave these.
4949
]
5050
new_root = tmpdir.ensure_dir('new_root')
51-
clone(str(local), str(new_root), 'feature', '.', exclude)
51+
clone(str(local), str(new_root), 'origin', 'feature', '.', exclude)
5252

5353
# Verify files.
5454
assert new_root.join('.git').check(dir=True)
@@ -86,7 +86,7 @@ def test_exclude_subdir(tmpdir, local, run):
8686
run(local, ['git', 'push', 'origin', 'master'])
8787

8888
new_root = tmpdir.ensure_dir('new_root')
89-
clone(str(local), str(new_root), 'master', 'sub', ['three.txt'])
89+
clone(str(local), str(new_root), 'origin', 'master', 'sub', ['three.txt'])
9090
paths = sorted(f.relto(new_root) for f in new_root.visit() if new_root.join('.git') not in f.parts())
9191
assert paths == ['README', 'sub', 'sub/three.txt']
9292

@@ -112,7 +112,7 @@ def test_exclude_patterns(tmpdir, local, run):
112112
run(local, ['git', 'push', 'origin', 'master'])
113113

114114
new_root = tmpdir.ensure_dir('new_root')
115-
clone(str(local), str(new_root), 'master', '.', ['*.md', '*/*.md'])
115+
clone(str(local), str(new_root), 'origin', 'master', '.', ['*.md', '*/*.md'])
116116
paths = sorted(f.relto(new_root) for f in new_root.visit() if new_root.join('.git') not in f.parts())
117117
assert paths == ['one.md', 'six.md', 'sub', 'sub/five.md', 'sub/four.md']
118118

@@ -129,43 +129,43 @@ def test_bad_branch_rel_dest_exclude(tmpdir, local, run):
129129
"""
130130
# Unknown branch.
131131
with pytest.raises(GitError) as exc:
132-
clone(str(local), str(tmpdir.ensure_dir('new_root')), 'unknown_branch', '.', None)
132+
clone(str(local), str(tmpdir.ensure_dir('new_root')), 'origin', 'unknown_branch', '.', None)
133133
assert 'Remote branch unknown_branch not found in upstream origin' in exc.value.output
134134

135135
# Not a branch.
136136
with pytest.raises(GitError) as exc:
137-
clone(str(local), str(tmpdir.ensure_dir('new_root')), 'light_tag', '.', None)
137+
clone(str(local), str(tmpdir.ensure_dir('new_root')), 'origin', 'light_tag', '.', None)
138138
assert 'fatal: ref HEAD is not a symbolic ref' in exc.value.output
139139

140140
# rel_dest outside of repo.
141141
with pytest.raises(GitError) as exc:
142-
clone(str(local), str(tmpdir.ensure_dir('new_root2')), 'master', '..', ['README'])
142+
clone(str(local), str(tmpdir.ensure_dir('new_root2')), 'origin', 'master', '..', ['README'])
143143
assert "'..' is outside repository" in exc.value.output
144144

145145
# rel_dest invalid.
146146
with pytest.raises(GitError) as exc:
147-
clone(str(local), str(tmpdir.ensure_dir('new_root3')), 'master', 'unknown', ['README'])
147+
clone(str(local), str(tmpdir.ensure_dir('new_root3')), 'origin', 'master', 'unknown', ['README'])
148148
assert "pathspec 'unknown' did not match any files" in exc.value.output
149149

150150
# No origin.
151151
run(local, ['git', 'remote', 'rename', 'origin', 'origin2'])
152152
with pytest.raises(GitError) as exc:
153-
clone(str(local), str(tmpdir.ensure_dir('new_root3')), 'master', '.', None)
153+
clone(str(local), str(tmpdir.ensure_dir('new_root3')), 'origin', 'master', '.', None)
154154
assert 'Git repo missing remote "origin".' in exc.value.message
155155
assert 'origin2\t' in exc.value.output
156156
assert 'origin\t' not in exc.value.output
157157

158158
# No remote.
159159
run(local, ['git', 'remote', 'rm', 'origin2'])
160160
with pytest.raises(GitError) as exc:
161-
clone(str(local), str(tmpdir.ensure_dir('new_root3')), 'master', '.', None)
161+
clone(str(local), str(tmpdir.ensure_dir('new_root3')), 'origin', 'master', '.', None)
162162
assert 'Git repo has no remotes.' in exc.value.message
163163
assert not exc.value.output
164164

165165
# Bad remote.
166166
run(local, ['git', 'remote', 'add', 'origin', local.join('does_not_exist')])
167167
with pytest.raises(GitError) as exc:
168-
clone(str(local), str(tmpdir.ensure_dir('new_root3')), 'master', '.', None)
168+
clone(str(local), str(tmpdir.ensure_dir('new_root3')), 'origin', 'master', '.', None)
169169
assert "repository '{}' does not exist".format(local.join('does_not_exist')) in exc.value.output
170170

171171

@@ -188,7 +188,7 @@ def test_multiple_remotes(tmpdir, local, remote, run):
188188
run(local, ['git', 'remote', 'set-url', '--push', 'origin2', str(origin2_push)])
189189

190190
new_root = tmpdir.ensure_dir('new_root')
191-
clone(str(local), str(new_root), 'master', '', None)
191+
clone(str(local), str(new_root), 'origin', 'master', '', None)
192192

193193
output = run(new_root, ['git', 'remote', '-v'])
194194
actual = output.strip().splitlines()

0 commit comments

Comments
 (0)