Repository: nosarthur/gita

Issue:
Add some additional options for group subcommand
Few different ideas, all related to groups: 
 1. For `group add`, would it be possible to add a `--to <group>` flag, so it is easier to script the tool. Currently it requires the user to stop and enter the group name
 1. Would a `group rename` be hard? 
 1. Would an `ls` alias on `ll` be hard e.g. `gita group ls`. This would mirror the main gita API

Thanks for a useful tool!

Discussion:

Patch:
diff --git a/README.md b/README.md
index 997b5a6..8644f43 100644
--- a/README.md
+++ b/README.md
@@ -58,7 +58,7 @@ The bookkeeping sub-commands are
     - `gita group add <repo-name(s)> -n <group-name>`: add repo(s) to a new group or existing group
     - `gita group [ll]`: display existing groups with repos
     - `gita group ls`: display existing group names
-    - `gita group rename <group-name> <new-name>: change group name
+    - `gita group rename <group-name> <new-name>`: change group name
     - `gita group rm <group-name(s)>`: delete group(s)
 - `gita info`: display the used and unused information items
 - `gita ll`: display the status of all repos
diff --git a/doc/README_CN.md b/doc/README_CN.md
index 0cb9cd0..051bbe8 100644
--- a/doc/README_CN.md
+++ b/doc/README_CN.md
@@ -54,7 +54,7 @@
     - `gita group add <repo-name(s)>`: 把库加入新的或者已经存在的组
     - `gita group [ll]`: 显示已有的组和它们的库
     - `gita group ls`: 显示已有的组名
-    - `gita group rename <group-name> <new-name>: 改组名
+    - `gita group rename <group-name> <new-name>`: 改组名
     - `gita group rm group(s): 删除组
 - `gita info`: 显示已用的和未用的信息项
 - `gita ll`: 显示所有库的状态信息
diff --git a/gita/__main__.py b/gita/__main__.py
index 5900d27..e00f20d 100644
--- a/gita/__main__.py
+++ b/gita/__main__.py
@@ -15,6 +15,7 @@ https://github.com/nosarthur/gita/blob/master/.gita-completion.bash
 '''
 
 import os
+import sys
 import argparse
 import subprocess
 import pkg_resources
@@ -76,6 +77,14 @@ def f_group(args: argparse.Namespace):
             print(f"{group}: {' '.join(repos)}")
     elif cmd == 'ls':
         print(' '.join(groups))
+    elif cmd == 'rename':
+        new_name = args.new_name
+        if new_name in groups:
+            sys.exit(f'{new_name} already exists.')
+        gname = args.gname
+        groups[new_name] = groups[gname]
+        del groups[gname]
+        utils.write_to_groups_file(groups, 'w')
     elif cmd == 'rm':
         for name in args.to_ungroup:
             del groups[name]
@@ -273,6 +282,12 @@ def main(argv=None):
                     metavar='group-name',
                     required=True,
                     help="group name")
+    pg_rename = group_cmds.add_parser('rename', description='Change group name.')
+    pg_rename.add_argument('gname', metavar='group-name',
+                    choices=utils.get_groups(),
+                    help="existing group to be renamed")
+    pg_rename.add_argument('new_name', metavar='new-name',
+                    help="new group name")
     group_cmds.add_parser('rm',
             description='Remove group(s).').add_argument('to_ungroup',
                     nargs='+',
diff --git a/setup.py b/setup.py
index 79821f1..0cdd33f 100644
--- a/setup.py
+++ b/setup.py
@@ -7,7 +7,7 @@ with open('README.md', encoding='utf-8') as f:
 setup(
     name='gita',
     packages=['gita'],
-    version='0.11.5',
+    version='0.11.6',
     license='MIT',
     description='Manage multiple git repos with sanity',
     long_description=long_description,


Test patch:
diff --git a/tests/test_main.py b/tests/test_main.py
index 1d05e2f..1b23bee 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -196,6 +196,28 @@ class TestGroupCmd:
         assert err == ''
         assert 'xx: a b\nyy: a c d\n' == out
 
+    @patch('gita.utils.get_config_fname', return_value=GROUP_FNAME)
+    @patch('gita.utils.write_to_groups_file')
+    def testRename(self, mock_write, _):
+        args = argparse.Namespace()
+        args.gname = 'xx'
+        args.new_name = 'zz'
+        args.group_cmd = 'rename'
+        utils.get_groups.cache_clear()
+        __main__.f_group(args)
+        expected = {'yy': ['a', 'c', 'd'], 'zz': ['a', 'b']}
+        mock_write.assert_called_once_with(expected, 'w')
+
+    @patch('gita.utils.get_config_fname', return_value=GROUP_FNAME)
+    def testRenameError(self, *_):
+        args = argparse.Namespace()
+        args.gname = 'xx'
+        args.new_name = 'yy'
+        args.group_cmd = 'rename'
+        utils.get_groups.cache_clear()
+        with pytest.raises(SystemExit, match='yy already exists.'):
+            __main__.f_group(args)
+
     @pytest.mark.parametrize('input, expected', [
         ('xx', {'yy': ['a', 'c', 'd']}),
         ("xx yy", {}),