Source code for bugsy.bugsy

import requests
from .bug import Bug
from .errors import (BugsyException, LoginException)
from .search import Search


[docs]class Bugsy(object): """ Bugsy allows easy getting and putting of Bugzilla bugs """ DEFAULT_SEARCH = ['version', 'id', 'summary', 'status', 'op_sys', 'resolution', 'product', 'component', 'platform', 'whiteboard']
[docs] def __init__( self, username=None, password=None, userid=None, cookie=None, api_key=None, bugzilla_url='https://bugzilla.mozilla.org/rest' ): """ Initialises a new instance of Bugsy :param username: Username to login with. Defaults to None :param password: Password to login with. Defaults to None :param userid: User ID to login with. Defaults to None :param cookie: Cookie to login with. Defaults to None :param apikey: API key to use. Defaults to None. :param bugzilla_url: URL endpoint to interact with. Defaults to https://bugzilla.mozilla.org/rest If a api_key is passed in, Bugsy will use this for authenticating requests. While not required to perform requests, if a username is passed in along with api_key, we will validate that the api key is valid for this username. Otherwise the api key is blindly used later. If a username AND password are passed in Bugsy will try get a login token from Bugzilla. If we can't login then a LoginException will be raised. If a userid AND cookie are passed in Bugsy will create a login token from them. If no username was passed in it will then try to get the username from Bugzilla. """ self.api_key = api_key self.username = username self.password = password self.userid = userid self.cookie = cookie self.bugzilla_url = bugzilla_url self.token = None self.session = requests.Session() self._have_auth = False # Prefer API keys over all other auth methods. if self.api_key: if self.username: result = self.request( 'valid_login', headers={'X-Bugzilla-API-Key': self.api_key}, params={'login': self.username} ) if result is not True: raise LoginException(result['message']) self.session.headers['X-Bugzilla-API-Key'] = self.api_key self._have_auth = True elif self.username and self.password: result = self.request( 'login', headers={ 'X-Bugzilla-Login': username, 'X-Bugzilla-Password': password } ) if 'token' in result: self.session.headers['X-Bugzilla-Token'] = result['token'] self.token = result['token'] else: raise LoginException(result['message']) self._have_auth = True elif self.userid and self.cookie: # The token is crafted from the userid and cookie. self.token = '%s-%s' % (self.userid, self.cookie) self.session.headers['X-Bugzilla-Token'] = self.token if not self.username: result = self.request('user/%s' % self.userid) if result.get('users', []): self.username = result['users'][0]['name'] else: raise LoginException(result['message']) self._have_auth = True
@property def authenticated(self): """ True if this instance is authenticated against the server. >>> bugzilla = Bugsy() >>> assert not bugzilla.authenticated """ return self._have_auth
[docs] def get(self, bug_number): """ Get a bug from Bugzilla. If there is a login token created during object initialisation it will be part of the query string passed to Bugzilla :param bug_number: Bug Number that will be searched. If found will return a Bug object. >>> bugzilla = Bugsy() >>> bug = bugzilla.get(123456) """ bug = self.request( 'bug/%s' % bug_number, params={"include_fields": self. DEFAULT_SEARCH} ) return Bug(self, **bug['bugs'][0])
[docs] def put(self, bug): """ This method allows you to create or update a bug on Bugzilla. You will have had to pass in a valid username and password to the object initialisation and recieved back a token. :param bug: A Bug object either created by hand or by using get() If there is no valid token then a BugsyException will be raised. If the object passed in is not a Bug then a BugsyException will be raised. >>> bugzilla = Bugsy() >>> bug = bugzilla.get(123456) >>> bug.summary = "I like cheese and sausages" >>> bugzilla.put(bug) """ if not self._have_auth: raise BugsyException("Unfortunately you can't put bugs in Bugzilla" " without credentials") if not isinstance(bug, Bug): raise BugsyException("Please pass in a Bug object when posting" " to Bugzilla") if not bug.id: result = self.request('bug', 'POST', json=bug.to_dict()) if 'error' not in result: bug._bug['id'] = result['id'] bug._bugsy = self try: bug._bug.pop('comment') except Exception: # If we don't have a `comment` we will error so let's just # swallow it. pass else: raise BugsyException(result['message']) else: result = self.request('bug/%s' % bug.id, 'PUT', json=bug.to_dict()) updated_bug = self.get(bug.id) return updated_bug
@property def search_for(self): return Search(self)
[docs] def request(self, path, method='GET', headers=None, **kwargs): """Perform a HTTP request. Given a relative Bugzilla URL path, an optional request method, and arguments suitable for requests.Request(), perform a HTTP request. """ headers = {} if headers is None else headers.copy() headers["User-Agent"] = "Bugsy" kwargs['headers'] = headers url = '%s/%s' % (self.bugzilla_url, path) return self._handle_errors(self.session.request(method, url, **kwargs))
def _handle_errors(self, response): if response.status_code >= 500: raise BugsyException("We received a {0} error with the following: {1}" .format(response.status_code, response.text)) result = response.json() if (response.status_code > 399 and response.status_code < 500) \ or (isinstance(result, dict) and 'error' in result and result.get('error', False) is True): if "API key" in result['message'] or "username or password" in result['message']: raise LoginException(result['message'], result.get("code")) else: raise BugsyException(result["message"], result.get("code")) return result