Repository: fedora-infra/bodhi

Issue:
The CLI should not traceback when trying to save an already active override
I tried to use the CLI to alter the duration on an override I made today, and it crashes:

```
$ bodhi overrides save --duration 3 --notes "This is needed to build Bodhi." --user bowlofeggs python-pyramid-1.8.2-2.fc26
Password:
Traceback (most recent call last):
  File "/usr/bin/bodhi", line 11, in <module>
    load_entry_point('bodhi-client==2.4.0', 'console_scripts', 'bodhi')()
  File "/usr/lib/python2.7/site-packages/click/core.py", line 722, in __call__
    return self.main(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/click/core.py", line 697, in main
    rv = self.invoke(ctx)
  File "/usr/lib/python2.7/site-packages/click/core.py", line 1066, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/lib/python2.7/site-packages/click/core.py", line 1066, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/lib/python2.7/site-packages/click/core.py", line 895, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/lib/python2.7/site-packages/click/core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/bodhi/client/__init__.py", line 229, in save_buildroot_overrides
    resp = client.save_override(nvr=nvr, duration=duration, notes=notes)
  File "/usr/lib/python2.7/site-packages/bodhi/client/bindings.py", line 78, in wrapper
    raise BodhiClientException(problems)
bodhi.client.bindings.BodhiClientException: Buildroot override for python-pyramid-1.8.2-2.fc26 already exists
```

It should be possible to use the CLI to edit active overrides, just like the web UI can do.


Discussion:
+1 for removing the crash.

However, this highlights an issue with the naming of the `bodhi overrides save` command. It is only for *creating* a new override. There is the `bodhi overrides edit` command for editing an existing command. 
On Wed, 2017-06-14 at 18:48 -0700, Ryan Lerch wrote:
> However, this highlights an issue with the naming of the bodhi
> overrides save command. It is only for creating a new override. There
> is the bodhi overrides edit command for editing an existing command.

Good point. I think the edit command was added after I filed this issue
(by @cverna). So yeah, probably we should add a "new" command and make
"save" be a deprecated alias for "new". And of course, we shouldn't
traceback, but maybe should just either do what the user wanted (if
it's just changing the expire date, why not do it for them?), or give a
useful error message.

Resolving patch:
diff --git a/bodhi/client/__init__.py b/bodhi/client/__init__.py
--- a/bodhi/client/__init__.py
+++ b/bodhi/client/__init__.py
@@ -537,7 +537,16 @@ def save_buildroot_overrides(user, password, url, staging, **kwargs):
         staging (bool): Whether to use the staging server or not.
         kwargs (dict): Other keyword arguments passed to us by click.
     """
-    _save_override(url=url, user=user, password=password, staging=staging, **kwargs)
+
+    try:
+        _save_override(url=url, user=user, password=password, staging=staging, **kwargs)
+    except bindings.BodhiClientException as e:
+        if str(e) == "Buildroot override for %s already exists" % (kwargs['nvr']):
+            click.echo(str(e))
+            click.echo("The `overrides save` command is used for creating a new override.")
+            click.echo("Use `overrides edit` to edit an existing override.")
+        else:
+            raise
 
 
 @overrides.command('edit')


Test patch:
diff --git a/bodhi/tests/client/test___init__.py b/bodhi/tests/client/test___init__.py
--- a/bodhi/tests/client/test___init__.py
+++ b/bodhi/tests/client/test___init__.py
@@ -310,6 +310,44 @@ def test_url_flag(self, send_request):
                 'csrf_token': 'a_csrf_token'})
         self.assertEqual(bindings_client.base_url, 'http://localhost:6543/')
 
+    @mock.patch('bodhi.client.bindings.BodhiClient.csrf',
+                mock.MagicMock(return_value='a_csrf_token'))
+    @mock.patch('bodhi.client.bindings.BodhiClient.send_request', autospec=True)
+    def test_existing_override_error_message(self, send_request):
+        """
+        Assert that the error message is provided if we try to save an existing override
+        """
+        exception_message = "Buildroot override for js-tag-it-2.0-1.fc25 already exists"
+        send_request.side_effect = bindings.BodhiClientException(exception_message)
+        runner = testing.CliRunner()
+
+        result = runner.invoke(
+            client.save_buildroot_overrides,
+            ['--user', 'bowlofeggs', '--password', 's3kr3t', 'js-tag-it-2.0-1.fc25'])
+
+        self.assertEqual(result.exit_code, 0)
+        self.assertIn("The `overrides save` command is used for creating a new override",
+                      result.output)
+        self.assertIn("Use `overrides edit` to edit an existing override",
+                      result.output)
+
+    @mock.patch('bodhi.client.bindings.BodhiClient.csrf',
+                mock.MagicMock(return_value='a_csrf_token'))
+    @mock.patch('bodhi.client.bindings.BodhiClient.send_request', autospec=True)
+    def test_other_client_exception(self, send_request):
+        """
+        Assert that any other BodhiClientExceptions are raised as expected
+        """
+        send_request.side_effect = bindings.BodhiClientException("Pants Exception")
+        runner = testing.CliRunner()
+
+        result = runner.invoke(
+            client.save_buildroot_overrides,
+            ['--user', 'bowlofeggs', '--password', 's3kr3t', 'js-tag-it-2.0-1.fc25'])
+
+        self.assertEqual(result.exit_code, -1)
+        self.assertEqual(str(result.exception), "Pants Exception", result.output)
+
 
 class TestWarnIfUrlAndStagingSet(unittest.TestCase):
     """