Repository: fedora-infra/bodhi

Issue:
Cannot edit an update that doesn't have bugs using the CLI without providing --bugs
While testing the second 3.9.0 beta today, I found that I was unable to edit an existing update using the CLI when ```--bugs``` was not supplied:

```
bodhi updates edit --staging --type bugfix FEDORA-2018-a06c4c8780                                                                                                                                                                                                                   
                                                                                                                                                                                                                                             
Warning: url and staging flags are both set. url will be ignored.
                                                                                                                                                                                                                                             
Unable to create update.  'NoneType' object is not iterable
```

On the server side, I found this traceback:

```
[Tue Jul 31 17:35:26.828765 2018] [wsgi:error] [pid 12:tid 140210130114304] [client 10.130.0.1:35288] 2018-07-31 17:35:26,828 DEBUG [bodhi.server][Dummy-4] validated = {'close_bugs': False, 'stable_karma': 1, 'csrf_token': u'c766bf3474040a2cbce8f48988fac3b9f82e90ae', 'requirements': None, 'builds': [u'python-rpdb-0.1.6-7.fc27'], 'autokarma': False, 'edited': u'python-rpdb-0.1.6-7.fc27', 'suggest': <unspecified>, 'notes': u'Test', 'request': <testing>, 'bugs': None, 'unstable_karma': -3, 'require_bugs': True, 'require_testcases': True, 'type': <bugfix>, 'severity': <unspecified>}
[Tue Jul 31 17:35:27.062162 2018] [wsgi:error] [pid 12:tid 140210130114304] [client 10.130.0.1:35288] 2018-07-31 17:35:27,062 INFO  [bodhi.server][Dummy-4] Editing update: python-rpdb-0.1.6-7.fc27
[Tue Jul 31 17:35:27.533548 2018] [wsgi:error] [pid 12:tid 140210130114304] [client 10.130.0.1:35288] 2018-07-31 17:35:27,533 INFO  [bodhi.server][Dummy-4] Sending mail to rbarlow@redhat.com: [Fedora Update] [comment] python-rpdb-0.1.6-7.fc27
[Tue Jul 31 17:35:27.533921 2018] [wsgi:error] [pid 12:tid 140210130114304] [client 10.130.0.1:35288] 2018-07-31 17:35:27,533 INFO  [bodhi.server][Dummy-4] Not sending email: No smtp_server defined
[Tue Jul 31 17:35:27.535163 2018] [wsgi:error] [pid 12:tid 140210130114304] [client 10.130.0.1:35288] 2018-07-31 17:35:27,534 ERROR [bodhi.server][Dummy-4] Failed to create update
[Tue Jul 31 17:35:27.535243 2018] [wsgi:error] [pid 12:tid 140210130114304] [client 10.130.0.1:35288] Traceback (most recent call last):
[Tue Jul 31 17:35:27.535306 2018] [wsgi:error] [pid 12:tid 140210130114304] [client 10.130.0.1:35288]   File "/usr/lib/python2.7/site-packages/bodhi/server/services/updates.py", line 504, in new_update
[Tue Jul 31 17:35:27.535367 2018] [wsgi:error] [pid 12:tid 140210130114304] [client 10.130.0.1:35288]     result, _caveats = Update.edit(request, data)
[Tue Jul 31 17:35:27.535427 2018] [wsgi:error] [pid 12:tid 140210130114304] [client 10.130.0.1:35288]   File "/usr/lib/python2.7/site-packages/bodhi/server/models.py", line 2193, in edit
[Tue Jul 31 17:35:27.535487 2018] [wsgi:error] [pid 12:tid 140210130114304] [client 10.130.0.1:35288]     new_bugs = up.update_bugs(data['bugs'], db)
[Tue Jul 31 17:35:27.535588 2018] [wsgi:error] [pid 12:tid 140210130114304] [client 10.130.0.1:35288]   File "/usr/lib/python2.7/site-packages/bodhi/server/models.py", line 2911, in update_bugs
[Tue Jul 31 17:35:27.535677 2018] [wsgi:error] [pid 12:tid 140210130114304] [client 10.130.0.1:35288]     for bug_id in bug_ids:
[Tue Jul 31 17:35:27.535744 2018] [wsgi:error] [pid 12:tid 140210130114304] [client 10.130.0.1:35288] TypeError: 'NoneType' object is not iterable
```

I am able to use the web UI to edit the same update without adding bugs to it.


Discussion:

Resolving patch:
diff --git a/bodhi/client/__init__.py b/bodhi/client/__init__.py
--- a/bodhi/client/__init__.py
+++ b/bodhi/client/__init__.py
@@ -384,9 +384,10 @@ def edit(user, password, url, **kwargs):
         kwargs['edited'] = title
 
         # Convert list of 'Bug' instances in DB to comma separated bug_ids for parsing.
-        former_update = resp['updates'][0]
+        former_update = resp['updates'][0].copy()
         if not kwargs['bugs']:
             kwargs['bugs'] = ",".join([str(bug['bug_id']) for bug in former_update['bugs']])
+            former_update.pop('bugs', None)
 
         # Replace empty fields with former values from database.
         for field in kwargs:


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
@@ -1457,6 +1457,46 @@ def test_bodhi_client_exception(self, send_request):
         self.assertEqual(result.exit_code, 0)
         self.assertIn("This is a BodhiClientException message", result.output)
 
+    @mock.patch.dict(client_test_data.EXAMPLE_QUERY_MUNCH['updates'][0], {'bugs': []})
+    @mock.patch('bodhi.client.bindings.BodhiClient.csrf',
+                mock.MagicMock(return_value='a_csrf_token'))
+    @mock.patch('bodhi.client.bindings.BodhiClient.query',
+                return_value=client_test_data.EXAMPLE_QUERY_MUNCH, autospec=True)
+    @mock.patch('bodhi.client.bindings.BodhiClient.send_request',
+                return_value=client_test_data.EXAMPLE_UPDATE_MUNCH, autospec=True)
+    def test_edit_bugless_update_without_bugs_param(self, send_request, query):
+        """Test editing an update with no bugs, without passing '--bugs' to it."""
+        runner = testing.CliRunner()
+
+        result = runner.invoke(
+            client.edit, ['FEDORA-2017-cc8582d738', '--user', 'bowlofeggs',
+                          '--password', 's3kr3t'])
+
+        self.assertEqual(result.exit_code, 0)
+        bindings_client = query.mock_calls[0][1][0]
+        query.assert_called_with(
+            bindings_client, updateid=u'FEDORA-2017-cc8582d738')
+        bindings_client = send_request.mock_calls[0][1][0]
+        calls = [
+            mock.call(
+                bindings_client, 'updates/', auth=True, verb='POST',
+                data={
+                    'close_bugs': False, 'stable_karma': 3, 'csrf_token': 'a_csrf_token',
+                    'staging': False, 'builds': u'nodejs-grunt-wrap-0.3.0-2.fc25',
+                    'autokarma': False, 'edited': u'nodejs-grunt-wrap-0.3.0-2.fc25',
+                    'suggest': u'unspecified', 'notes': u'New package.',
+                    'notes_file': None, 'request': None, 'severity': u'low',
+                    'bugs': '', 'requirements': u'', 'unstable_karma': -3, 'type': 'bugfix'
+                }
+            ),
+            mock.call(
+                bindings_client,
+                u'updates/FEDORA-EPEL-2016-3081a94111/get-test-results',
+                verb='GET'
+            )
+        ]
+        self.assertEqual(send_request.mock_calls, calls)
+
 
 class TestEditBuilrootOverrides(unittest.TestCase):
     """