Repository: fedora-infra/bodhi

Issue:
The CLI cannot set or view an update's severity
I noticed today when creating an update that I could not use the CLI to set or view my update's severity, which is a feature gap with the web UI.


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
@@ -63,6 +63,8 @@ def _warn_if_url_and_staging_set(ctx, param, value):
     click.option('--password', hide_input=True),
     click.option('--type', default='bugfix', help='Update type', required=True,
                  type=click.Choice(['security', 'bugfix', 'enhancement', 'newpackage'])),
+    click.option('--severity', help='Update severity',
+                 type=click.Choice(['unspecified', 'low', 'medium', 'high', 'urgent'])),
     click.option('--notes', help='Update description'),
     click.option('--notes-file', help='Update description from a file'),
     click.option('--bugs', help='Comma-separated list of bug numbers', default=''),
diff --git a/bodhi/client/bindings.py b/bodhi/client/bindings.py
--- a/bodhi/client/bindings.py
+++ b/bodhi/client/bindings.py
@@ -630,6 +630,7 @@ def update_str(self, update, minimal=False):
             line_formatter.format('Release', update['release']['long_name']),
             line_formatter.format('Status', update['status']),
             line_formatter.format('Type', update['type']),
+            line_formatter.format('Severity', update['severity']),
             line_formatter.format('Karma', update['karma']),
             line_formatter.format('Autokarma', '{0}  [{1}, {2}]'.format(
                 update['autokarma'], update['unstable_karma'], update['stable_karma']))


Test patch:
diff --git a/bodhi/tests/client/__init__.py b/bodhi/tests/client/__init__.py
--- a/bodhi/tests/client/__init__.py
+++ b/bodhi/tests/client/__init__.py
@@ -235,6 +235,7 @@
      Release: Fedora 25
       Status: testing
         Type: newpackage
+    Severity: low
        Karma: 0
    Autokarma: True  [-3, 3]
         Bugs: 1420605 - Review Request: nodejs-grunt-wrap - A Grunt plugin for
@@ -784,6 +785,7 @@
      Release: Fedora EPEL 7
       Status: stable
         Type: bugfix
+    Severity: unspecified
        Karma: 0
    Autokarma: True  [-3, 3]
        Notes: Update to 2.2.4. Release notes available at https://github.com
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
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Copyright © 2016-2017 Red Hat, Inc. and others.
+# Copyright © 2016-2018 Red Hat, Inc. and others.
 #
 # This file is part of Bodhi.
 #
@@ -228,6 +228,35 @@ class TestNew(unittest.TestCase):
     """
     Test the new() function.
     """
+
+    @mock.patch.dict(client_test_data.EXAMPLE_UPDATE_MUNCH, {'severity': 'urgent'})
+    @mock.patch.dict(os.environ, {'BODHI_URL': 'http://example.com/tests/'})
+    @mock.patch('bodhi.client.bindings.BodhiClient.csrf',
+                mock.MagicMock(return_value='a_csrf_token'))
+    @mock.patch('bodhi.client.bindings.BodhiClient.send_request',
+                return_value=client_test_data.EXAMPLE_UPDATE_MUNCH, autospec=True)
+    def test_severity_flag(self, send_request):
+        """Assert correct behavior with the --severity flag."""
+        runner = testing.CliRunner()
+
+        result = runner.invoke(
+            client.new,
+            ['--user', 'bowlofeggs', '--password', 's3kr3t', '--autokarma', 'bodhi-2.2.4-1.el7',
+             '--severity', 'urgent'])
+
+        self.assertEqual(result.exit_code, 0)
+        expected_output = client_test_data.EXPECTED_UPDATE_OUTPUT.replace('unspecified', 'urgent')
+        self.assertEqual(result.output, expected_output + '\n')
+        bindings_client = send_request.mock_calls[0][1][0]
+        send_request.assert_called_once_with(
+            bindings_client, 'updates/', auth=True, verb='POST',
+            data={
+                'close_bugs': False, 'stable_karma': None, 'csrf_token': 'a_csrf_token',
+                'staging': False, 'builds': u'bodhi-2.2.4-1.el7', 'autokarma': True,
+                'suggest': None, 'notes': None, 'request': None, 'bugs': u'', 'requirements': None,
+                'unstable_karma': None, 'file': None, 'notes_file': None, 'type': 'bugfix',
+                'severity': 'urgent'})
+
     @mock.patch('bodhi.client.bindings.BodhiClient.csrf',
                 mock.MagicMock(return_value='a_csrf_token'))
     @mock.patch('bodhi.client.bindings.BodhiClient.send_request',
@@ -254,7 +283,8 @@ def test_url_flag(self, send_request):
                 'close_bugs': False, 'stable_karma': None, 'csrf_token': 'a_csrf_token',
                 'staging': False, 'builds': u'bodhi-2.2.4-1.el7', 'autokarma': True,
                 'suggest': None, 'notes': None, 'request': None, 'bugs': u'', 'requirements': None,
-                'unstable_karma': None, 'file': None, 'notes_file': None, 'type': 'bugfix'})
+                'unstable_karma': None, 'file': None, 'notes_file': None, 'type': 'bugfix',
+                'severity': None})
         self.assertEqual(bindings_client.base_url, 'http://localhost:6543/')
 
     @mock.patch('bodhi.client.bindings.BodhiClient.csrf',
@@ -339,7 +369,7 @@ def test_close_bugs_flag(self, send_request):
                 'staging': False, 'builds': u'bodhi-2.2.4-1.el7', 'autokarma': True,
                 'suggest': None, 'notes': None, 'request': None, 'bugs': u'1234567',
                 'requirements': None, 'unstable_karma': None, 'file': None,
-                'notes_file': None, 'type': 'bugfix'})
+                'notes_file': None, 'type': 'bugfix', 'severity': None})
         self.assertEqual(bindings_client.base_url, 'http://localhost:6543/')
 
 
@@ -803,6 +833,36 @@ class TestEdit(unittest.TestCase):
     """
     This class tests the edit() function.
     """
+
+    @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_severity_flag(self, send_request, query):
+        """Assert that the --severity flag is handled properly."""
+        runner = testing.CliRunner()
+
+        result = runner.invoke(
+            client.edit, ['FEDORA-2017-cc8582d738', '--user', 'bowlofeggs',
+                          '--password', 's3kr3t', '--severity', 'low'])
+
+        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]
+        expected_data = {
+            'close_bugs': False, 'stable_karma': None, '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': None,
+            'notes': None, 'notes_file': None, 'requirements': None,
+            'request': None, 'bugs': u'', 'unstable_karma': None, 'type': 'bugfix',
+            'severity': 'low'}
+        send_request.assert_called_with(
+            bindings_client, 'updates/', auth=True, verb='POST', data=expected_data)
+
     @mock.patch('bodhi.client.bindings.BodhiClient.csrf',
                 mock.MagicMock(return_value='a_csrf_token'))
     @mock.patch('bodhi.client.bindings.BodhiClient.query',
@@ -832,7 +892,8 @@ def test_url_flag(self, send_request, query):
                 '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': None,
                 'notes': u'this is an edited note', 'notes_file': None, 'requirements': None,
-                'request': None, 'bugs': u'', 'unstable_karma': None, 'type': 'bugfix'})
+                'request': None, 'bugs': u'', 'unstable_karma': None, 'type': 'bugfix',
+                'severity': None})
         self.assertEqual(bindings_client.base_url, 'http://localhost:6543/')
 
     @mock.patch('bodhi.client.bindings.BodhiClient.csrf',
@@ -869,7 +930,8 @@ def test_notes_file(self, send_request, query):
                     'autokarma': False, 'edited': u'nodejs-grunt-wrap-0.3.0-2.fc25',
                     'suggest': None, 'notes': 'This is a --notes-file note!',
                     'notes_file': 'notefile.txt', 'request': None, 'bugs': u'',
-                    'requirements': None, 'unstable_karma': None, 'type': 'bugfix'})
+                    'requirements': None, 'unstable_karma': None, 'type': 'bugfix',
+                    'severity': None})
             self.assertEqual(bindings_client.base_url, 'http://localhost:6543/')
 
     def test_notes_and_notes_file(self):
@@ -914,7 +976,8 @@ def test_update_title(self, send_request):
                 'staging': False, 'builds': u'drupal7-i18n-1.17-1.fc26', 'autokarma': False,
                 'edited': u'drupal7-i18n-1.17-1.fc26', 'suggest': None, 'requirements': None,
                 'notes': u'this is an edited note', 'notes_file': None,
-                'request': None, 'bugs': u'', 'unstable_karma': None, 'type': 'bugfix'})
+                'request': None, 'bugs': u'', 'unstable_karma': None, 'type': 'bugfix',
+                'severity': None})
 
     def test_wrong_update_title_argument(self):
         """
@@ -984,7 +1047,7 @@ def test_required_tasks(self, send_request, query):
                 'autokarma': False, 'edited': u'nodejs-grunt-wrap-0.3.0-2.fc25',
                 'suggest': None, 'notes': u'testing required tasks', 'notes_file': None,
                 'requirements': u'dist.depcheck dist.rpmdeplint', 'request': None,
-                'bugs': u'', 'unstable_karma': None, 'type': 'bugfix'})
+                'bugs': u'', 'unstable_karma': None, 'type': 'bugfix', 'severity': None})
         self.assertEqual(bindings_client.base_url, 'http://localhost:6543/')
 
     @mock.patch('bodhi.client.bindings.BodhiClient.csrf',
diff --git a/bodhi/tests/client/test_bindings.py b/bodhi/tests/client/test_bindings.py
--- a/bodhi/tests/client/test_bindings.py
+++ b/bodhi/tests/client/test_bindings.py
@@ -958,6 +958,15 @@ def test_request_stable(self):
             client_test_data.EXPECTED_UPDATE_OUTPUT.replace(
                 '[-3, 3]', '[-3, 3]\n     Request: stable'))
 
+    def test_severity(self):
+        """Test that severity is rendered."""
+        client = bindings.BodhiClient()
+        client.base_url = 'http://example.com/tests/'
+
+        text = client.update_str(client_test_data.EXAMPLE_UPDATE_MUNCH)
+
+        self.assertTrue('Severity: unspecified' in text)
+
     def test_with_autokarma_set(self):
         """
         Ensure correct operation when autokarma is True, and stable/unstable karmas are set.