Skip to content

Commit

Permalink
Bitbucket OAuth. Resolve #201.
Browse files Browse the repository at this point in the history
- Implement OAuth2. Thanks to @ibuchanan for helping me navigate
  bitbucket's idiosyncratic implementation.
- Add a bugwarrior.data file to the ~/.task directory, per [taskwarrior's
  third-party guidelines](https://taskwarrior.org/docs/3rd-party.html#guidelines).
  • Loading branch information
ryneeverett committed Mar 9, 2016
1 parent af5d3a5 commit a6fa41d
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 5 deletions.
26 changes: 26 additions & 0 deletions bugwarrior/data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import os
import json


DATAFILE = os.path.expanduser(
os.path.join(os.getenv('TASKDATA', '~/.task'), 'bugwarrior.data'))


def get(key):
try:
with open(DATAFILE, 'r') as jsondata:
data = json.load(jsondata)
return data[key]
except IOError: # File does not exist.
return None


def set(key, value):
try:
with open(DATAFILE, 'rw') as jsondata:
data = json.load(jsondata)
data[key] = value
json.dump(data, jsondata)
except IOError: # File does not exist.
with open(DATAFILE, 'w+') as jsondata:
json.dump({key: value}, jsondata)
8 changes: 8 additions & 0 deletions bugwarrior/docs/services/bitbucket.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ set to ralphbean (my account). But I have some targets with
``bitbucket.username`` pointed at organizations or other users to watch issues
there.

As an alternative to password authentication, there is OAuth. To get a key and secret,
go to the "OAuth" section of your profile settings and click "Add consumer". Set the
"Callback URL" to ``https://localhost/`` and set the appropriate permissions. Then
assign your consumer's credentials to ``bitbucket.key`` and ``bitbucket.secret``. Note
that you will have to provide a password (only) the first time you pull, so you may
want to set ``bitbucket.password = @oracle:ask_password`` and run
``bugwarrior-pull --interactive`` on your next pull.

Service Features
----------------

Expand Down
44 changes: 39 additions & 5 deletions bugwarrior/services/bitbucket.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import requests
from twiggy import log

from bugwarrior import data
from bugwarrior.services import IssueService, Issue
from bugwarrior.config import asbool, die

Expand Down Expand Up @@ -65,11 +66,36 @@ class BitbucketService(IssueService):
def __init__(self, *args, **kw):
super(BitbucketService, self).__init__(*args, **kw)

self.auth = None
login = self.config_get('login')
password = self.config_get_password('password', login)

self.auth = (login, password)
key = self.config_get_default('key')
secret = self.config_get_default('secret')
self.auth = {'oauth': (key, secret)}

refresh_token = data.get('bitbucket_refresh_token')

if not refresh_token:
login = self.config_get('login')
password = self.config_get_password('password', login)
self.auth['basic'] = (login, password)

if key and secret:
if refresh_token:
response = requests.post(
self.BASE_URL + 'site/oauth2/access_token',
data={'grant_type': 'refresh_token',
'refresh_token': refresh_token},
auth=self.auth['oauth']).json()
else:
response = requests.post(
self.BASE_URL + 'site/oauth2/access_token',
data={'grant_type': 'password',
'username': login,
'password': password},
auth=self.auth['oauth']).json()

data.set('bitbucket_refresh_token', response['refresh_token'])

self.auth['token'] = response['access_token']

self.exclude_repos = []
if self.config_get_default('exclude_repos', None):
Expand Down Expand Up @@ -112,7 +138,15 @@ def filter_repos(self, repo_tag):

def get_data(self, url, **kwargs):
api = kwargs.get('api', self.BASE_API2)
response = requests.get(api + url, auth=self.auth)

kwargs = {}
if 'token' in self.auth:
kwargs['headers'] = {
'Authorization': 'Bearer ' + self.auth['token']}
elif 'basic' in self.auth:
kwargs['auth'] = self.auth['basic']

response = requests.get(api + url, **kwargs)

# And.. if we didn't get good results, just bail.
if response.status_code != 200:
Expand Down

0 comments on commit a6fa41d

Please sign in to comment.