Conduit: bugzilla.py module for accessing BMO's API to add attachments (bug 1347930) r?mars draft
authorDavid Lawrence <dkl@mozilla.com>
Tue, 21 Mar 2017 10:42:34 -0400
changeset 5532 2e59a5f9a1aa54a9356cc50c6ed1f15559fe6995
parent 5531 33c3a1ca22d8076c901e3d86e0bb260e6b35f74c
push id173
push userdlawrence@mozilla.com
push dateTue, 21 Mar 2017 14:42:45 +0000
reviewersmars
bugs1347930
Conduit: bugzilla.py module for accessing BMO's API to add attachments (bug 1347930) r?mars - Converted GET requests to use requests module style of passing URL parmas (forgot to do that from first review) - Updated error exception handling according to last review. MozReview-Commit-ID: 8sZIJ9QhZGJ
commitindex/commitindex/reviews/bugzilla.py
--- a/commitindex/commitindex/reviews/bugzilla.py
+++ b/commitindex/commitindex/reviews/bugzilla.py
@@ -23,17 +23,17 @@ class Bugzilla(object):
     2. New content_type for conduit attachments?
     3. Add comment_tags for conduit attachments?
     """
 
     def __init__(self, rest_url=None):
         self.rest_url = rest_url
         self.session = requests.Session()
 
-    def call(self, method, path, data=None):
+    def call(self, method, path, api_key=None, data=None):
         """Perform REST API call and decode JSON.i
 
         Generic call function that performs a REST API call to the
         Bugzilla system and turns the JSON data returned into a
         Python data object.
 
         Args:
             method: Request method such as GET/POST/PUT...
@@ -50,29 +50,35 @@ class Bugzilla(object):
             pertain to the specific error code generated by Bugzilla.
         """
 
         headers = {
             'Accept': 'application/json',
             'Content-Type': 'application/json'
         }
 
+        if api_key:
+            headers['X-Bugzilla-API-Key'] = str(api_key)
+
         if method == 'GET':
-            response = self.session.get(self.rest_url + path, headers=headers)
+            response = self.session.get(
+                self.rest_url + path, params=data, headers=headers
+            )
 
         if method == 'POST':
-            response = self.session.post(self.rest_url + path, json=data,
-                                         headers=headers)
+            response = self.session.post(
+                self.rest_url + path, json=data, headers=headers
+            )
 
         try:
             data = json.loads(response.content.decode('utf-8'))
         except:
             raise BugzillaError(400, "Error decoding JSON data")
 
-        if 'error' in data:
+        if isinstance(data, dict) and 'error' in data:
             raise BugzillaError(data['message'], data['code'])
 
         return data
 
     def is_bug_confidential(self, bug_id):
         """Check if bug is confidential
 
         Simple REST call checking if a given bug id is private or not.
@@ -88,17 +94,17 @@ class Bugzilla(object):
             pertain to the specific error code generated by Bugzilla.
         """
 
         try:
             self.call('GET', '/bug/' + quote(str(bug_id)))
         except BugzillaError as error:
             if error.fault_code == 102:
                 return True
-            raise BugzillaError(error.fault_string, error.fault_code)
+            raise
 
         return False
 
     def valid_api_key(self, username, api_key):
         """Check if API key is valid for specific username
 
         Simple REST call to check if a given API key for a specified user
         is a valid login.
@@ -112,23 +118,27 @@ class Bugzilla(object):
             True if the api_key and username pair are a valid login,
             False if nota
 
         Raises:
             BugzillaError: General error where the fault code and string will
             pertain to the specific error code generated by Bugzilla.
         """
 
+        params = {
+            'login': quote(username)
+        }
+
         try:
-            self.call('GET', '/valid_login?login=' + quote(username) +
-                      '&api_key=' + quote(api_key))
+            self.call('GET', '/valid_login', data=params,
+                      api_key=quote(api_key))
         except BugzillaError as error:
             if error.fault_code == 306:
                 return False
-            raise BugzillaError(error.fault_string, error.fault_code)
+            raise
 
         return True
 
     def create_attachment(self, bug_id, attach_data, api_key=None):
         """Create the attachment using the provided flags.
 
         Create a single attachment in Bugzilla using the REST API.
 
@@ -139,29 +149,30 @@ class Bugzilla(object):
             Integer ID for new Bugzilla attachment.
 
         Raises:
             BugzillaError: General error where the fault code and string will
             pertain to the specific error code generated by Bugzilla.
         """
 
         try:
-            result = self.call('POST', '/bug/' + quote(str(bug_id)) +
-                               '/attachment?api_key=' + quote(str(api_key)),
-                               attach_data)
+            result = self.call(
+                'POST', '/bug/' + quote(str(bug_id)) + '/attachment',
+                api_key=api_key, data=attach_data
+            )
         except BugzillaError as error:
             logger.warning(
                 {
                     'msg': error.fault_string,
                     'code': error.fault_code
                 }, 'app.warning'
             )
-            raise BugzillaError(error.fault_string, error.fault_code)
+            raise
 
         return int(list(result['attachments'].keys())[0])
 
 
 class BugzillaError(Exception):
     """Generic Bugzilla Exception"""
     def __init__(self, msg, code=None):
         super(BugzillaError, self).__init__(msg)
-        self.fault_code = code
-        self.fault_string = msg
+        self.fault_code = int(code)
+        self.fault_string = str(msg)