Skip to content

Commit

Permalink
add support for api keys
Browse files Browse the repository at this point in the history
  • Loading branch information
djmitche authored and ryneeverett committed Apr 1, 2017
1 parent c06280a commit 21f46ea
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 6 deletions.
8 changes: 8 additions & 0 deletions bugwarrior/docs/services/bugzilla.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ make bugwarrior support more robust!
bugzilla.username = rbean@redhat.com
bugzilla.password = OMG_LULZ

Alternately, if you are using a version of python-bugzilla newer than 2.0.0,
you can specify an API key instead of a password. Note that the username is
still required in this case, in order to identify bugs belonging to you.

::

bugzilla.api_key = 4f4d475f4c554c5a4f4d475f4c554c5a

The above example is the minimum required to import issues from
Bugzilla. You can also feel free to use any of the
configuration options described in :ref:`common_configuration_options`.
Expand Down
18 changes: 13 additions & 5 deletions bugwarrior/services/bz.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,17 @@ def __init__(self, *args, **kw):
# to pass that argument or not.
self.advanced = asbool(self.config.get('advanced', 'no'))

self.password = self.get_password('password', self.username)

url = 'https://%s/xmlrpc.cgi' % self.base_uri
self.bz = bugzilla.Bugzilla(url=url)
self.bz.login(self.username, self.password)
api_key = self.config.get('api_key', default=None)
if api_key:
try:
self.bz = bugzilla.Bugzilla(url=url, api_key=api_key)
except TypeError:
raise Exception("Bugzilla API keys require python-bugzilla>=2.1.0")
else:
password = self.get_password('password', self.username)
self.bz = bugzilla.Bugzilla(url=url)
self.bz.login(self.username, password)

@staticmethod
def get_keyring_service(service_config):
Expand All @@ -139,10 +145,12 @@ def get_keyring_service(service_config):

@classmethod
def validate_config(cls, service_config, target):
req = ['username', 'password', 'base_uri']
req = ['username', 'base_uri']
for option in req:
if option not in service_config:
die("[%s] has no 'bugzilla.%s'" % (target, option))
if 'password' not in service_config and 'api_key' not in service_config:
die("[%s] has neither 'bugzilla.password' nor 'bugzilla.api_key'" % (target,))

super(BugzillaService, cls).validate_config(service_config, target)

Expand Down
48 changes: 47 additions & 1 deletion tests/test_bugzilla.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
from builtins import object
import mock
from collections import namedtuple
import configparser

from bugwarrior.services.bz import BugzillaService

from .base import ServiceTest, AbstractServiceTest
from .base import ConfigTest, ServiceTest, AbstractServiceTest
from bugwarrior.config import ServiceConfig


class FakeBugzillaLib(object):
Expand All @@ -17,6 +19,40 @@ def query(self, query):
return [Record(**self.record)]


class TestBugzillaServiceConfig(ConfigTest):

def setUp(self):
super(TestBugzillaServiceConfig, self).setUp()
self.config = configparser.RawConfigParser()
self.config.add_section('general')
self.config.add_section('mybz')
self.service_config = ServiceConfig(
BugzillaService.CONFIG_PREFIX, self.config, 'mybz')

@mock.patch('bugwarrior.services.bz.die')
def test_validate_config_username_password(self, die):
self.config.set('mybz', 'bugzilla.base_uri', 'http://one.com/')
self.config.set('mybz', 'bugzilla.username', 'me')
self.config.set('mybz', 'bugzilla.password', 'mypas')
BugzillaService.validate_config(self.service_config, 'mybz')
die.assert_not_called()

@mock.patch('bugwarrior.services.bz.die')
def test_validate_config_api_key(self, die):
self.config.set('mybz', 'bugzilla.base_uri', 'http://one.com/')
self.config.set('mybz', 'bugzilla.username', 'me')
self.config.set('mybz', 'bugzilla.api_key', '123')
BugzillaService.validate_config(self.service_config, 'mybz')
die.assert_not_called()

@mock.patch('bugwarrior.services.bz.die')
def test_validate_config_api_key_no_username(self, die):
self.config.set('mybz', 'bugzilla.base_uri', 'http://one.com/')
self.config.set('mybz', 'bugzilla.api_key', '123')
BugzillaService.validate_config(self.service_config, 'mybz')
die.assert_called_with("[mybz] has no 'bugzilla.username'")


class TestBugzillaService(AbstractServiceTest, ServiceTest):
SERVICE_CONFIG = {
'bugzilla.base_uri': 'http://one.com/',
Expand Down Expand Up @@ -44,6 +80,16 @@ def get_mock_service(self, *args, **kwargs):
service.bz = FakeBugzillaLib(self.arbitrary_record)
return service

def test_api_key_supplied(self):
with mock.patch('bugzilla.Bugzilla'):
self.service = self.get_mock_service(
BugzillaService,
config_overrides={
'bugzilla.base_uri': 'http://one.com/',
'bugzilla.username': 'me',
'bugzilla.api_key': '123',
})

def test_to_taskwarrior(self):
arbitrary_extra = {
'url': 'http://path/to/issue/',
Expand Down

0 comments on commit 21f46ea

Please sign in to comment.