Skip to content

Commit 3f846a1

Browse files
karajan1001pmrowla
andauthored
Add a new rename command (#3794)
* fixed #3599 1. add new command `dvc remote rename <old> <new>`. 2. add tests for this new command. * Update dvc/command/remote.py Co-authored-by: Peter Rowlands (변기호) <[email protected]> * Change about code review * For deepsource * Update dvc/command/remote.py Co-authored-by: Peter Rowlands (변기호) <[email protected]>
1 parent b52c925 commit 3f846a1

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

dvc/command/remote.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,35 @@ def run(self):
104104
return 0
105105

106106

107+
class CmdRemoteRename(CmdRemote):
108+
def _rename_default(self, conf):
109+
if conf["core"].get("remote") == self.args.name:
110+
conf["core"]["remote"] = self.args.new
111+
112+
def run(self):
113+
all_config = self.config.load_config_to_level(None)
114+
if self.args.new in all_config.get("remote", {}):
115+
raise ConfigError(
116+
"Rename failed. Remote name '{}' already exists.".format(
117+
{self.args.new}
118+
)
119+
)
120+
121+
with self.config.edit(self.args.level) as conf:
122+
self._check_exists(conf)
123+
conf["remote"][self.args.new] = conf["remote"][self.args.name]
124+
del conf["remote"][self.args.name]
125+
self._rename_default(conf)
126+
127+
for level in reversed(self.config.LEVELS):
128+
if level == self.args.level:
129+
break
130+
with self.config.edit(level) as level_conf:
131+
self._rename_default(level_conf)
132+
133+
return 0
134+
135+
107136
def add_parser(subparsers, parent_parser):
108137
from dvc.command.config import parent_config_parser
109138

@@ -220,3 +249,14 @@ def add_parser(subparsers, parent_parser):
220249
"name", help="Name of the remote to remove."
221250
)
222251
remote_remove_parser.set_defaults(func=CmdRemoteRemove)
252+
REMOTE_RENAME_HELP = "Rename a DVC remote"
253+
remote_rename_parser = remote_subparsers.add_parser(
254+
"rename",
255+
parents=[parent_config_parser, parent_parser],
256+
description=append_doc_link(REMOTE_RENAME_HELP, "remote/rename"),
257+
help=REMOTE_RENAME_HELP,
258+
formatter_class=argparse.RawDescriptionHelpFormatter,
259+
)
260+
remote_rename_parser.add_argument("name", help="Remote to be renamed")
261+
remote_rename_parser.add_argument("new", help="New name of the remote")
262+
remote_rename_parser.set_defaults(func=CmdRemoteRename)

tests/func/test_remote.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,74 @@ def test_remote_modify_default(dvc):
284284

285285
assert repo_config["core"]["remote"] == remote_repo
286286
assert local_config["core"]["remote"] == remote_local
287+
288+
289+
def test_remote_rename(dvc):
290+
remote_name = "drive"
291+
remote_url = "gdrive://test/test"
292+
new_name = "new"
293+
other_name = "other"
294+
# prepare
295+
assert main(["remote", "add", remote_name, remote_url]) == 0
296+
config = dvc.config.load_one("repo")
297+
assert config["remote"][remote_name]["url"] == remote_url
298+
assert new_name not in config.get("remote", {})
299+
300+
# rename failed
301+
assert main(["remote", "rename", remote_name]) == 254
302+
assert main(["remote", "rename", new_name, other_name]) == 251
303+
config = dvc.config.load_one("repo")
304+
assert config["remote"][remote_name]["url"] == remote_url
305+
assert new_name not in config.get("remote", {})
306+
307+
# rename success
308+
assert main(["remote", "rename", remote_name, new_name]) == 0
309+
config = dvc.config.load_one("repo")
310+
assert remote_name not in config.get("remote", {})
311+
assert config["remote"][new_name]["url"] == remote_url
312+
313+
314+
def test_remote_duplicated(dvc):
315+
remote_name = "drive"
316+
remote_url = "gdrive://test/test"
317+
used_name = "overlap"
318+
another_url = "gdrive://test/test1"
319+
# prepare
320+
assert main(["remote", "add", remote_name, remote_url]) == 0
321+
assert main(["remote", "add", "--local", used_name, another_url]) == 0
322+
config = dvc.config.load_one("repo")
323+
assert config["remote"][remote_name]["url"] == remote_url
324+
local_config = dvc.config.load_one("local")
325+
assert local_config["remote"][used_name]["url"] == another_url
326+
327+
# rename duplicated
328+
assert main(["remote", "rename", remote_name, used_name]) == 251
329+
config = dvc.config.load_one("repo")
330+
assert config["remote"][remote_name]["url"] == remote_url
331+
local_config = dvc.config.load_one("local")
332+
assert local_config["remote"][used_name]["url"] == another_url
333+
334+
335+
def test_remote_default(dvc):
336+
remote_name = "drive"
337+
remote_url = "gdrive://test/test"
338+
new_name = "new"
339+
# prepare
340+
assert main(["remote", "add", "-d", remote_name, remote_url]) == 0
341+
assert main(["remote", "default", "--local", remote_name]) == 0
342+
config = dvc.config.load_one("repo")
343+
assert config["core"]["remote"] == remote_name
344+
assert config["remote"][remote_name]["url"] == remote_url
345+
assert new_name not in config.get("remote", {})
346+
local_config = dvc.config.load_one("local")
347+
assert local_config["core"]["remote"] == remote_name
348+
349+
# rename success
350+
assert main(["remote", "rename", remote_name, new_name]) == 0
351+
config = dvc.config.load_one("repo")
352+
assert remote_name not in config.get("remote", {})
353+
assert config["core"]["remote"] == new_name
354+
assert config["remote"][new_name]["url"] == remote_url
355+
assert remote_name not in config.get("remote", {})
356+
local_config = dvc.config.load_one("local")
357+
assert local_config["core"]["remote"] == new_name

0 commit comments

Comments
 (0)