Skip to content

Commit b366d3f

Browse files
committed
Adding support for git remote set-url/get-url API to Remote
Both commands enable handling of a little known feature of git, which is to support multiple URL for one remote. You can add multiple url using the `set_url` subcommand of `git remote`. As listing them is also handy, there's a nice method to do it, using `get_url`. * adding set_url method that maps to the git remote set-url command¶ * can be used to set an URL, or replace an URL with optional positional arg¶ * can be used to add, delete URL with kwargs (matching set-url options)¶ * adding add_url, delete_url methods that wraps around set_url for conveniency¶ * adding urls property that yields an iterator over the setup urls for a remote¶ * adding a test suite that checks all use case scenarii of this added API.¶ Signed-off-by: Guyzmo <[email protected]>
1 parent 902679c commit b366d3f

File tree

2 files changed

+95
-2
lines changed

2 files changed

+95
-2
lines changed

Diff for: git/remote.py

+48
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,54 @@ def iter_items(cls, repo):
434434
yield Remote(repo, section[lbound + 1:rbound])
435435
# END for each configuration section
436436

437+
def set_url(self, new_url, old_url=None, **kwargs):
438+
"""Configure URLs on current remote (cf command git remote set_url)
439+
440+
This command manages URLs on the remote.
441+
442+
:param new_url: string being the URL to add as an extra remote URL
443+
:param old_url: when set, replaces this URL with new_url for the remote
444+
:return: self
445+
"""
446+
scmd = 'set-url'
447+
kwargs['insert_kwargs_after'] = scmd
448+
if old_url:
449+
self.repo.git.remote(scmd, self.name, old_url, new_url, **kwargs)
450+
else:
451+
self.repo.git.remote(scmd, self.name, new_url, **kwargs)
452+
return self
453+
454+
def add_url(self, url, **kwargs):
455+
"""Adds a new url on current remote (special case of git remote set_url)
456+
457+
This command adds new URLs to a given remote, making it possible to have
458+
multiple URLs for a single remote.
459+
460+
:param url: string being the URL to add as an extra remote URL
461+
:return: self
462+
"""
463+
return self.set_url(url, add=True)
464+
465+
def delete_url(self, url, **kwargs):
466+
"""Deletes a new url on current remote (special case of git remote set_url)
467+
468+
This command deletes new URLs to a given remote, making it possible to have
469+
multiple URLs for a single remote.
470+
471+
:param url: string being the URL to delete from the remote
472+
:return: self
473+
"""
474+
return self.set_url(url, delete=True)
475+
476+
@property
477+
def urls(self):
478+
""":return: Iterator yielding all configured URL targets on a remote
479+
as strings"""
480+
scmd = 'get-url'
481+
kwargs = {'insert_kwargs_after': scmd}
482+
for url in self.repo.git.remote(scmd, self.name, all=True, **kwargs).split('\n'):
483+
yield url
484+
437485
@property
438486
def refs(self):
439487
"""

Diff for: git/test/test_remote.py

+47-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
with_rw_repo,
1010
with_rw_and_rw_remote_repo,
1111
fixture,
12-
GIT_DAEMON_PORT
12+
GIT_DAEMON_PORT,
13+
assert_raises
1314
)
1415
from git import (
1516
RemoteProgress,
@@ -62,7 +63,7 @@ def update(self, op_code, cur_count, max_count=None, message=''):
6263
# check each stage only comes once
6364
op_id = op_code & self.OP_MASK
6465
assert op_id in (self.COUNTING, self.COMPRESSING, self.WRITING)
65-
66+
6667
if op_code & self.WRITING > 0:
6768
if op_code & self.BEGIN > 0:
6869
assert not message, 'should not have message when remote begins writing'
@@ -568,3 +569,47 @@ def test_uncommon_branch_names(self):
568569
assert res[0].remote_ref_path == 'refs/pull/1/head'
569570
assert res[0].ref.path == 'refs/heads/pull/1/head'
570571
assert isinstance(res[0].ref, Head)
572+
573+
@with_rw_repo('HEAD', bare=False)
574+
def test_multiple_urls(self, rw_repo):
575+
# test addresses
576+
test1 = 'https://github.com/gitpython-developers/GitPython'
577+
test2 = 'https://github.com/gitpython-developers/gitdb'
578+
test3 = 'https://github.com/gitpython-developers/smmap'
579+
580+
remote = rw_repo.remotes[0]
581+
# Testing setting a single URL
582+
remote.set_url(test1)
583+
assert list(remote.urls) == [test1]
584+
585+
# Testing replacing that single URL
586+
remote.set_url(test1)
587+
assert list(remote.urls) == [test1]
588+
# Testing adding new URLs
589+
remote.set_url(test2, add=True)
590+
assert list(remote.urls) == [test1, test2]
591+
remote.set_url(test3, add=True)
592+
assert list(remote.urls) == [test1, test2, test3]
593+
# Testing removing an URL
594+
remote.set_url(test2, delete=True)
595+
assert list(remote.urls) == [test1, test3]
596+
# Testing changing an URL
597+
remote.set_url(test3, test2)
598+
assert list(remote.urls) == [test1, test2]
599+
600+
# will raise: fatal: --add --delete doesn't make sense
601+
assert_raises(GitCommandError, remote.set_url, test2, add=True, delete=True)
602+
603+
# Testing on another remote, with the add/delete URL
604+
remote = rw_repo.create_remote('another', url=test1)
605+
remote.add_url(test2)
606+
assert list(remote.urls) == [test1, test2]
607+
remote.add_url(test3)
608+
assert list(remote.urls) == [test1, test2, test3]
609+
# Testing removing all the URLs
610+
remote.delete_url(test2)
611+
assert list(remote.urls) == [test1, test3]
612+
remote.delete_url(test1)
613+
assert list(remote.urls) == [test3]
614+
# will raise fatal: Will not delete all non-push URLs
615+
assert_raises(GitCommandError, remote.delete_url, test3)

0 commit comments

Comments
 (0)