Repository: broadinstitute/cromshell

Issue:
`update-server` command
Port the `update-server` command over from 1.0

Allows the user to programmatically change the server name in the config file, without having to know how to do this manually.

Comments:

Patch:
diff --git a/src/cromshell/__main__.py b/src/cromshell/__main__.py
index 8060d9a..e48c4a8 100644
--- a/src/cromshell/__main__.py
+++ b/src/cromshell/__main__.py
@@ -13,6 +13,7 @@ from .slim_metadata import command as slim_metadata
 from .status import command as status
 from .submit import command as submit
 from .timing import command as timing
+from .update_server import command as update_server
 
 # Version number is automatically set via bumpversion.
 # DO NOT MODIFY:
@@ -129,6 +130,7 @@ main_entry.add_command(status.main)
 main_entry.add_command(submit.main)
 main_entry.add_command(slim_metadata.main)
 main_entry.add_command(metadata.main)
+main_entry.add_command(update_server.main)
 main_entry.add_command(timing.main)
 
 
diff --git a/src/cromshell/update_server/__init__.py b/src/cromshell/update_server/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/cromshell/update_server/command.py b/src/cromshell/update_server/command.py
new file mode 100644
index 0000000..ffaa7a2
--- /dev/null
+++ b/src/cromshell/update_server/command.py
@@ -0,0 +1,44 @@
+import json
+import logging
+import os
+from pathlib import Path
+from typing import Dict
+
+import click
+
+LOGGER = logging.getLogger(__name__)
+CROMWELL_SERVER_KEY = "cromwell_server"
+
+
+@click.command(name="update-server")
+@click.argument("cromwell_server_url", required=True, nargs=1)
+@click.pass_obj
+def main(config, cromwell_server_url):
+    """Update the default Cromwell server in the config file"""
+
+    LOGGER.info("update-server")
+
+    # location of the config file
+    cromshell_config_path = os.path.join(
+        config.config_dir, config.CROMSHELL_CONFIG_FILE_NAME
+    )
+    assert os.access(
+        cromshell_config_path, mode=os.W_OK
+    ), f"Cannot write to Cromshell config file {cromshell_config_path}"
+
+    # the contents of the config file as a dict
+    cromshell_config: Dict = config.cromshell_config_options
+
+    # update the cromwell server
+    if CROMWELL_SERVER_KEY not in cromshell_config.keys():
+        cromshell_config.update({CROMWELL_SERVER_KEY: cromwell_server_url})
+    else:
+        cromshell_config[CROMWELL_SERVER_KEY] = cromwell_server_url
+
+    # write the modified config file
+    config_contents = json.dumps(cromshell_config, indent=2)
+    with Path(cromshell_config_path).open("w") as crom_config_file:
+        crom_config_file.write(config_contents)
+
+    LOGGER.info(f"Cromshell config file at {cromshell_config_path}")
+    LOGGER.info(f"Default Cromwell server updated to {cromwell_server_url}")
diff --git a/src/cromshell/utilities/cromshellconfig.py b/src/cromshell/utilities/cromshellconfig.py
index 35d6127..10e9d76 100644
--- a/src/cromshell/utilities/cromshellconfig.py
+++ b/src/cromshell/utilities/cromshellconfig.py
@@ -197,7 +197,7 @@ def __load_cromshell_config_file(
 
 
 def __get_cromwell_server(config_options: dict):
-    """Get Cromshell Server URL from configuration options"""
+    """Get Cromwell Server URL from configuration options"""
 
     if not config_options["cromwell_server"]:
         raise FileNotFoundError('Cromshell config file is missing "cromwell_server"')


Test patch:
diff --git a/tests/integration/test_update_server.py b/tests/integration/test_update_server.py
new file mode 100644
index 0000000..f7874d9
--- /dev/null
+++ b/tests/integration/test_update_server.py
@@ -0,0 +1,66 @@
+import os
+from traceback import print_exception
+
+from click.testing import CliRunner
+
+from cromshell.__main__ import main_entry as cromshell
+from cromshell.utilities import cromshellconfig
+
+
+def get_current_cromwell_server():
+    cromshell_config_dict = cromshellconfig.__load_cromshell_config_file(
+        config_directory=cromshellconfig.config_dir,
+        config_file_name=cromshellconfig.CROMSHELL_CONFIG_FILE_NAME,
+        config_file_template=None,
+    )
+    print(
+        os.path.join(
+            cromshellconfig.config_dir, cromshellconfig.CROMSHELL_CONFIG_FILE_NAME
+        )
+    )
+    print(cromshell_config_dict)
+    return cromshell_config_dict["cromwell_server"]
+
+
+def run_update_server(runner, new_cromwell_server):
+    """Run cromshell update-server in a specific CliRunner context"""
+
+    result = runner.invoke(
+        cromshell,
+        [
+            "update-server",
+            new_cromwell_server,
+        ],
+    )
+
+    # print any exceptions so pytest will show them
+    print_exception(*result.exc_info)
+
+
+def test_update_server():
+    """Run cromshell update-server using CliRunner and ensure server changes"""
+
+    print("Running a test of cromshell update-server...")
+
+    test_server_name = "http://test.server"
+
+    runner = CliRunner(mix_stderr=False)
+    # The test is being run in temp directory created by CliRunner, and
+    # so its modification of the default server only happens in this context
+    with runner.isolated_filesystem():
+
+        # the current default server
+        current_cromwell_server = get_current_cromwell_server()
+        print(f"Initial Cromwell server: {current_cromwell_server}")
+
+        # update the server and check that it worked
+        run_update_server(
+            runner=runner,
+            new_cromwell_server=test_server_name,
+        )
+        tmp_cromwell_server = get_current_cromwell_server()
+        print(
+            f"After attempting to update to '{test_server_name}', "
+            f"the config file has '{tmp_cromwell_server}'"
+        )
+        assert tmp_cromwell_server == test_server_name, "cromshell update-server failed"