Repository: fedora-infra/bodhi

Issue:
bodhi --mine gives KeyError
Running "bodhi --mine --username=puiterwijk" results in a KeyError: 'title'.

Also, not all update information is displayed:
....
 python-openid-cla-1.2-1.fc22                 enhancement  stable    2016-03-02 
 python-fedora-0.7.1-4.fc22
 python-openid-cla-1.2-1.el6                  enhancement  stable    2016-03-10 
 python-openid-cla-1.2-1.el7                  enhancement  stable    2016-03-10 
 python-fedora-0.7.1-4.fc23                   enhancement  stable    2016-02-22 
 python-openid-cla-1.2-1.fc23
 devtodo2-2.1-14.20120711git8dee6.fc23        bugfix       stable    2016-02-21 
.....



Discussion:
The Bodhi CLI has changed since this issue was filed, but the --mine is not implemented in the new CLI for updates. There is an open issue for --mine on overrides too ( #1382  )

Resolving patch:
diff --git a/bodhi/client/__init__.py b/bodhi/client/__init__.py
--- a/bodhi/client/__init__.py
+++ b/bodhi/client/__init__.py
@@ -285,10 +285,11 @@ def edit(user, password, url, **kwargs):
 @click.option('--type', default=None, help='Filter by update type',
               type=click.Choice(['newpackage', 'security', 'bugfix', 'enhancement']))
 @click.option('--user', help='Updates submitted by a specific user')
+@click.option('--mine', is_flag=True, help='Show only your updates')
 @click.option('--staging', help='Use the staging bodhi instance',
               is_flag=True, default=False)
 @url_option
-def query(url, **kwargs):
+def query(url, mine=False, **kwargs):
     # User Docs that show in the --help
     """
     Query updates on Bodhi
@@ -301,9 +302,16 @@ def query(url, **kwargs):
     Args:
         url (unicode): The URL of a Bodhi server to create the update on. Ignored if staging is
                        True.
+        mine (Boolean): If the --mine flag was set
         kwargs (dict): Other keyword arguments passed to us by click.
     """
     client = bindings.BodhiClient(base_url=url, staging=kwargs['staging'])
+    if mine:
+        if 'USERNAME' in os.environ:
+            kwargs['user'] = os.environ['USERNAME']
+        else:
+            client.init_username()
+            kwargs['user'] = client.username
     resp = client.query(**kwargs)
     print_resp(resp, client)
 
@@ -494,8 +502,10 @@ def overrides():
               help='Updates submitted by a specific user')
 @click.option('--staging', help='Use the staging bodhi instance',
               is_flag=True, default=False)
+@click.option('--mine', is_flag=True,
+              help='Show only your overrides.')
 @url_option
-def query_buildroot_overrides(url, user=None, **kwargs):
+def query_buildroot_overrides(url, user=None, mine=False, **kwargs):
     # Docs that show in the --help
     """
     Query the buildroot overrides.
@@ -508,11 +518,18 @@ def query_buildroot_overrides(url, user=None, **kwargs):
     Args:
         user (unicode): If supplied, overrides for this user will be queried.
         staging (bool): Whether to use the staging server or not.
+        mine (bool): Whether to use the --mine flag was given.
         url (unicode): The URL of a Bodhi server to create the update on. Ignored if staging is
                        True.
         kwargs (dict): Other keyword arguments passed to us by click.
     """
     client = bindings.BodhiClient(base_url=url, staging=kwargs['staging'])
+    if mine:
+        if 'USERNAME' in os.environ:
+            user = os.environ['USERNAME']
+        else:
+            client.init_username()
+            user = client.username
     resp = client.list_overrides(user=user)
     print_resp(resp, client)
 
diff --git a/bodhi/client/bindings.py b/bodhi/client/bindings.py
--- a/bodhi/client/bindings.py
+++ b/bodhi/client/bindings.py
@@ -333,7 +333,7 @@ def list_overrides(self, user=None):
             params['user'] = user
         return self.send_request('overrides/', verb='GET', params=params)
 
-    def _init_username(self):
+    def init_username(self):
         """
         Check to see if the username attribute on self is set, and set if if it is not.
 
@@ -374,7 +374,7 @@ def csrf(self):
         logged in aquires and caches a CSRF token, and returns it.
         """
         if not self.csrf_token:
-            self._init_username()
+            self.init_username()
             if not self.has_cookies():
                 self.login(self.username, self.password)
             self.csrf_token = self.send_request(


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
@@ -163,6 +163,57 @@ def test_url_flag(self, send_request):
                 'cves': None})
         self.assertEqual(bindings_client.base_url, 'http://localhost:6543/')
 
+    @mock.patch.dict('os.environ', {'USERNAME': 'dudemcpants'})
+    @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_query_mine_flag_username_set(self, send_request):
+        """
+        Assert that we use the USERNAME variable if it is set
+        """
+        runner = testing.CliRunner()
+
+        runner.invoke(client.query, ['--mine'])
+
+        bindings_client = send_request.mock_calls[0][1][0]
+        send_request.assert_called_once_with(
+            bindings_client, 'updates/', verb='GET',
+            params={
+                'approved_since': None, 'status': None, 'locked': None,
+                'builds': None, 'releases': None,
+                'content_type': None,
+                'submitted_since': None, 'suggest': None, 'request': None, 'bugs': None,
+                'staging': False, 'modified_since': None, 'pushed': None, 'pushed_since': None,
+                'user': 'dudemcpants', 'critpath': None, 'updateid': None, 'packages': None,
+                'type': None, 'cves': None})
+
+    @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)
+    @mock.patch('__builtin__.raw_input', create=True)
+    def test_query_mine_flag_username_unset(self, mock_raw_input, send_request):
+        """
+        Assert that we use init_username if USERNAME is not set
+        """
+        mock_raw_input.return_value = 'dudemcpants'
+        runner = testing.CliRunner()
+
+        runner.invoke(client.query, ['--mine'])
+
+        bindings_client = send_request.mock_calls[0][1][0]
+        send_request.assert_called_once_with(
+            bindings_client, 'updates/', verb='GET',
+            params={
+                'approved_since': None, 'status': None, 'locked': None,
+                'builds': None, 'releases': None,
+                'content_type': None,
+                'submitted_since': None, 'suggest': None, 'request': None, 'bugs': None,
+                'staging': False, 'modified_since': None, 'pushed': None, 'pushed_since': None,
+                'user': 'dudemcpants', 'critpath': None, 'updateid': None, 'packages': None,
+                'type': None, 'cves': None})
+
 
 class TestQueryBuildrootOverrides(unittest.TestCase):
     """
@@ -190,6 +241,40 @@ def test_url_flag(self, send_request):
             params={'user': u'bowlofeggs'})
         self.assertEqual(bindings_client.base_url, 'http://localhost:6543/')
 
+    @mock.patch.dict('os.environ', {'USERNAME': 'dudemcpants'})
+    @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_queryoverrides_mine_flag_username_set(self, send_request):
+        """
+        Assert that we use the USERNAME variable if it is set
+        """
+        runner = testing.CliRunner()
+
+        runner.invoke(client.query_buildroot_overrides, ['--mine'])
+        bindings_client = send_request.mock_calls[0][1][0]
+        send_request.assert_called_once_with(
+            bindings_client, 'overrides/', verb='GET', params={'user': 'dudemcpants'})
+
+    @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)
+    @mock.patch('__builtin__.raw_input', create=True)
+    def test_queryoverrides_mine_flag_username_unset(self, mock_raw_input, send_request):
+        """
+        Assert that we use init_username if USERNAME is not set
+        """
+        mock_raw_input.return_value = 'dudemcpants'
+        runner = testing.CliRunner()
+
+        runner.invoke(client.query_buildroot_overrides, ['--mine'])
+
+        bindings_client = send_request.mock_calls[0][1][0]
+        send_request.assert_called_once_with(
+            bindings_client, 'overrides/', verb='GET', params={'user': 'dudemcpants'})
+
 
 class TestRequest(unittest.TestCase):
     """
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
@@ -88,8 +88,8 @@ def test_comment(self):
                   'email': True, 'csrf_token': 'a token'})
 
 
-class TestBodhiClient__init_username(unittest.TestCase):
-    """Test the BodhiClient._init_username() method."""
+class TestBodhiClient_init_username(unittest.TestCase):
+    """Test the BodhiClient.init_username() method."""
     TEST_EMPTY_OBJECT_SESSION_CACHE = '{}'
     TEST_FAILED_SESSION_CACHE = '{"https://bodhi.fedoraproject.org/:bowlofeggs": []}'
     TEST_HOT_SESSION_CACHE = '{"https://bodhi.fedoraproject.org/:bowlofeggs": [["stuff", "login"]]}'
@@ -109,7 +109,7 @@ def test_auth_cache_empty(self, exists, _load_cookies, mock_raw_input, mock_open
         mock_raw_input.return_value = 'pongou'
         client = bindings.BodhiClient()
 
-        client._init_username()
+        client.init_username()
 
         exists.assert_called_once_with(fedora.client.openidbaseclient.b_SESSION_FILE)
         self.assertEqual(_load_cookies.mock_calls, [mock.call(), mock.call()])
@@ -131,7 +131,7 @@ def test_auth_cache_empty_object(self, exists, _load_cookies, mock_raw_input, mo
         mock_raw_input.return_value = 'pongou'
         client = bindings.BodhiClient()
 
-        client._init_username()
+        client.init_username()
 
         exists.assert_called_once_with(fedora.client.openidbaseclient.b_SESSION_FILE)
         self.assertEqual(_load_cookies.mock_calls, [mock.call(), mock.call()])
@@ -153,7 +153,7 @@ def test_auth_cache_failed(self, exists, _load_cookies, mock_raw_input, mock_ope
         mock_raw_input.return_value = 'pongou'
         client = bindings.BodhiClient()
 
-        client._init_username()
+        client.init_username()
 
         exists.assert_called_once_with(fedora.client.openidbaseclient.b_SESSION_FILE)
         self.assertEqual(_load_cookies.mock_calls, [mock.call(), mock.call()])
@@ -174,7 +174,7 @@ def test_auth_cache_hot(self, exists, _load_cookies, mock_raw_input, mock_open):
         mock_open.side_effect = mock.mock_open(read_data=self.TEST_HOT_SESSION_CACHE)
         client = bindings.BodhiClient()
 
-        client._init_username()
+        client.init_username()
 
         exists.assert_called_once_with(fedora.client.openidbaseclient.b_SESSION_FILE)
         self.assertEqual(_load_cookies.mock_calls, [mock.call(), mock.call()])
@@ -203,7 +203,7 @@ def fake_keys():
         mock_open.side_effect = mock.mock_open(read_data=self.TEST_HOT_SESSION_CACHE)
         client = bindings.BodhiClient()
 
-        client._init_username()
+        client.init_username()
 
         exists.assert_called_once_with(fedora.client.openidbaseclient.b_SESSION_FILE)
         loads.assert_called_once_with(self.TEST_HOT_SESSION_CACHE)
@@ -224,7 +224,7 @@ def test_auth_cache_missing(self, exists, _load_cookies, mock_raw_input, mock_op
         mock_raw_input.return_value = 'pongou'
         client = bindings.BodhiClient()
 
-        client._init_username()
+        client.init_username()
 
         exists.assert_called_once_with(fedora.client.openidbaseclient.b_SESSION_FILE)
         self.assertEqual(_load_cookies.mock_calls, [mock.call(), mock.call()])
@@ -246,7 +246,7 @@ def test_auth_cache_other_domain(self, exists, _load_cookies, mock_raw_input, mo
         mock_raw_input.return_value = 'pongou'
         client = bindings.BodhiClient()
 
-        client._init_username()
+        client.init_username()
 
         exists.assert_called_once_with(fedora.client.openidbaseclient.b_SESSION_FILE)
         self.assertEqual(_load_cookies.mock_calls, [mock.call(), mock.call()])
@@ -264,7 +264,7 @@ def test_username_set(self, exists, _load_cookies, mock_raw_input, mock_open):
         """
         client = bindings.BodhiClient(username='coolbeans')
 
-        client._init_username()
+        client.init_username()
 
         self.assertEqual(exists.call_count, 0)
         self.assertEqual(_load_cookies.mock_calls, [mock.call()])
@@ -277,8 +277,8 @@ class TestBodhiClient_csrf(unittest.TestCase):
     """
     Test the BodhiClient.csrf() method.
     """
-    @mock.patch('bodhi.client.bindings.BodhiClient._init_username')
-    def test_with_csrf_token(self, _init_username):
+    @mock.patch('bodhi.client.bindings.BodhiClient.init_username')
+    def test_with_csrf_token(self, init_username):
         """
         Test the method when csrf_token is set.
         """
@@ -291,7 +291,7 @@ def test_with_csrf_token(self, _init_username):
         self.assertEqual(csrf, 'a token')
         self.assertEqual(client.send_request.call_count, 0)
         # No need to init the username since we already have a token.
-        self.assertEqual(_init_username.call_count, 0)
+        self.assertEqual(init_username.call_count, 0)
 
     @mock.patch('__builtin__.open', create=True)
     @mock.patch('__builtin__.raw_input', create=True)
@@ -304,7 +304,7 @@ def test_without_csrf_token_with_cookies(self, exists, _load_cookies, mock_raw_i
         """
         exists.return_value = True
         mock_open.side_effect = mock.mock_open(
-            read_data=TestBodhiClient__init_username.TEST_HOT_SESSION_CACHE)
+            read_data=TestBodhiClient_init_username.TEST_HOT_SESSION_CACHE)
         client = bindings.BodhiClient()
         client.has_cookies = mock.MagicMock(return_value=True)
         client.login = mock.MagicMock(return_value='login successful')
@@ -317,7 +317,7 @@ def test_without_csrf_token_with_cookies(self, exists, _load_cookies, mock_raw_i
         client.has_cookies.assert_called_once_with()
         self.assertEqual(client.login.call_count, 0)
         client.send_request.assert_called_once_with('csrf', verb='GET', auth=True)
-        # Ensure that _init_username() was called and did its thing.
+        # Ensure that init_username() was called and did its thing.
         exists.assert_called_once_with(fedora.client.openidbaseclient.b_SESSION_FILE)
         self.assertEqual(_load_cookies.mock_calls, [mock.call(), mock.call()])
         self.assertEqual(mock_raw_input.call_count, 0)
@@ -345,7 +345,7 @@ def test_without_csrf_token_without_cookies(self, exists, _load_cookies, mock_ra
         client.has_cookies.assert_called_once_with()
         client.login.assert_called_once_with('pongou', 'illnevertell')
         client.send_request.assert_called_once_with('csrf', verb='GET', auth=True)
-        # Ensure that _init_username() didn't do anything since a username was given.
+        # Ensure that init_username() didn't do anything since a username was given.
         self.assertEqual(exists.call_count, 0)
         self.assertEqual(_load_cookies.mock_calls, [mock.call()])
         self.assertEqual(mock_raw_input.call_count, 0)