Skip to content

Commit 8b883f7

Browse files
committed
🔀 Switched to python-bitbucket from defunct bitbucket-api lib
* 🚧 switch implementation * 🚧 updated tests * 📼 updated cassettes * ⚠️ missing Fork implementation Signed-off-by: Guyzmo <[email protected]>
1 parent 6c0afd9 commit 8b883f7

17 files changed

+69
-913
lines changed

git_repo/repo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env python
1+
#!/usr/bin/env pytho
22

33
'''
44
Usage:

git_repo/services/ext/bitbucket.py

Lines changed: 50 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -6,144 +6,80 @@
66
from ..service import register_target, RepositoryService
77
from ...exceptions import ResourceError, ResourceExistsError, ResourceNotFoundError
88

9-
import bitbucket.bitbucket as bitbucket
9+
from pybitbucket.bitbucket import Client
10+
from pybitbucket.auth import BasicAuthenticator
11+
from pybitbucket.user import User
12+
from pybitbucket.repository import Repository, RepositoryForkPolicy
13+
1014
from requests import Request, Session
15+
from requests.exceptions import HTTPError
1116
import json
1217

13-
'''
14-
Extension of the bitbucket module implementation to add support for the extra
15-
features the original implementation lacked. This is a temporary measure, up
16-
until a PR is crafted for the original code.
17-
'''
18-
19-
bitbucket.URLS.update({
20-
'GET_REPO' : 'repositories/%(username)s/%(repo_slug)s/',
21-
'DELETE_REPO' : 'repositories/%(accountname)s/%(repo_slug)s',
22-
'FORK_REPO' : 'repositories/%(username)s/%(repo_slug)s/fork',
23-
})
24-
25-
class Bitbucket(bitbucket.Bitbucket):
26-
def __init__(self, *args, **kwarg):
27-
super(Bitbucket, self).__init__(self)
28-
self.session = Session()
29-
# XXX monkey patching of requests within bitbucket module
30-
self.requests = self.session
31-
32-
def get(self, user=None, repo_slug=None):
33-
""" Get a single repository on Bitbucket and return it."""
34-
username = user or self.username
35-
repo_slug = repo_slug or self.repo_slug or ''
36-
url = self.url('GET_REPO', username=username, repo_slug=repo_slug)
37-
return self.dispatch('GET', url, auth=self.auth)
38-
39-
def delete(self, user, repo_slug):
40-
url = self.url('DELETE_REPO', username=user, accountname=user, repo_slug=repo_slug)
41-
return self.dispatch('DELETE', url, auth=self.auth)
42-
43-
def fork(self, user, repo_slug, new_name=None):
44-
url = self.url('FORK_REPO', username=user, repo_slug=repo_slug)
45-
new_repo = new_name or repo_slug
46-
return self.dispatch('POST', url, name=new_repo, auth=self.auth)
47-
48-
def dispatch(self, method, url, auth=None, params=None, **kwargs):
49-
""" Send HTTP request, with given method,
50-
credentials and data to the given URL,
51-
and return the success and the result on success.
52-
"""
53-
r = Request(
54-
method=method,
55-
url=url,
56-
auth=auth,
57-
params=params,
58-
data=kwargs)
59-
resp = self.session.send(r.prepare())
60-
status = resp.status_code
61-
text = resp.text
62-
error = resp.reason
63-
if status >= 200 and status < 300:
64-
if text:
65-
try:
66-
return (True, json.loads(text))
67-
except TypeError:
68-
pass
69-
except ValueError:
70-
pass
71-
return (True, text)
72-
elif status >= 300 and status < 400:
73-
return (
74-
False,
75-
'Unauthorized access, '
76-
'please check your credentials.')
77-
elif status == 404:
78-
return (False, dict(message='Service not found', reason=error, code=status))
79-
elif status == 400:
80-
return (False, dict(message='Bad request sent to server.', reason=error, code=status))
81-
elif status == 401:
82-
return (False, dict(message='Not enough privileges.', reason=error, code=status))
83-
elif status == 403:
84-
return (False, dict(message='Not authorized.', reason=error, code=status))
85-
elif status == 402 or status >= 405:
86-
return (False, dict(message='Request error.', reason=error, code=status))
87-
elif status >= 500 and status < 600:
88-
return (False, dict(message='Server error.', reason=error, code=status))
89-
else:
90-
return (False, dict(message='Unidentified error.', reason=error, code=status))
18+
# bitbucket.URLS.update({
19+
# 'GET_REPO' : 'repositories/%(username)s/%(repo_slug)s/',
20+
# 'DELETE_REPO' : 'repositories/%(accountname)s/%(repo_slug)s',
21+
# 'FORK_REPO' : 'repositories/%(username)s/%(repo_slug)s/fork',
22+
# })
9123

9224

9325
@register_target('bb', 'bitbucket')
9426
class BitbucketService(RepositoryService):
9527
fqdn = 'bitbucket.org'
9628

9729
def __init__(self, *args, **kwarg):
98-
self.bb = Bitbucket()
30+
self.bb = Client()
9931
super(BitbucketService, self).__init__(*args, **kwarg)
10032

10133
def connect(self):
10234
if not self._privatekey:
10335
raise ConnectionError('Could not connect to BitBucket. Please configure .gitconfig with your bitbucket credentials.')
10436
if not ':' in self._privatekey:
10537
raise ConnectionError('Could not connect to BitBucket. Please setup your private key with login:password')
106-
self.bb.username, self.bb.password = self._privatekey.split(':')
107-
self.username = self.bb.username
108-
result, _ = self.bb.get_user()
109-
if not result:
110-
raise ConnectionError('Could not connect to BitBucket. Not authorized, wrong credentials.')
38+
self.bb.config = BasicAuthenticator(*self._privatekey.split(':')+['[email protected]'])
39+
self.bb.session = self.bb.config.session
40+
try:
41+
User.find_current_user(client=self.bb)
42+
except HTTPError as err:
43+
raise ConnectionError('Could not connect to BitBucket. Not authorized, wrong credentials.') from err
11144

11245
def create(self, user, repo, add=False):
113-
success, result = self.bb.repository.create(repo, scm='git', public=True)
114-
if not success and result['code'] == 400:
115-
raise ResourceExistsError('Project {} already exists on this account.'.format(repo))
116-
elif not success:
117-
raise ResourceError("Couldn't complete creation: {message} (error #{code}: {reason})".format(**result))
118-
if add:
119-
self.add(user=user, repo=repo, tracking=self.name)
46+
try:
47+
repo = Repository.create(
48+
repo,
49+
fork_policy=RepositoryForkPolicy.ALLOW_FORKS,
50+
is_private=False,
51+
client=self.bb
52+
)
53+
if add:
54+
self.add(user=user, repo=repo, tracking=self.name)
55+
except HTTPError as err:
56+
if err.status_code == 400:
57+
raise ResourceExistsError('Project {} already exists on this account.'.format(repo)) from err
58+
raise ResourceError("Couldn't complete creation: {}".format(err)) from err
12059

12160
def fork(self, user, repo):
122-
success, result = self.bb.fork(user, repo)
123-
if not success:
124-
raise ResourceError("Couldn't complete fork: {message} (error #{code}: {reason})".format(**result))
61+
raise NotImplementedError('No support yet by the underlying library.')
62+
try:
63+
Repository.find_repository_by_name_and_owner(repo, owner=user, client=self.bb).fork()
64+
except HTTPError as err:
65+
raise ResourceError("Couldn't complete creation: {}".format(err)) from err
12566
return '/'.join([result['owner'], result['slug']])
12667

12768
def delete(self, repo, user=None):
12869
if not user:
12970
user = self.user
130-
success, result = self.bb.delete(user, repo)
131-
if not success and result['code'] == 404:
132-
raise ResourceNotFoundError("Cannot delete: repository {}/{} does not exists.".format(user, repo))
133-
elif not success:
134-
raise ResourceError("Couldn't complete deletion: {message} (error #{code}: {reason})".format(**result))
71+
try:
72+
Repository.find_repository_by_name_and_owner(repo, owner=user, client=self.bb).delete()
73+
except HTTPError as err:
74+
if err.status_code == 404:
75+
raise ResourceNotFoundError("Cannot delete: repository {}/{} does not exists.".format(user, repo)) from err
76+
raise ResourceError("Couldn't complete creation: {}".format(err)) from err
13577

13678
def get_repository(self, user, repo):
137-
if user != self.user:
138-
result, repo_list = self.bb.repository.public(user)
139-
else:
140-
result, repo_list = self.bb.repository.all()
141-
if not result:
142-
raise ResourceError("Couldn't list repositories: {message} (error #{code}: {reason})".format(**repo_list))
143-
for r in repo_list:
144-
if r['name'] == repo:
145-
return r
146-
#raise ResourceNotFoundError('Cannot retrieve repository: {}/{} does not exists.'.format(user, repo))
79+
try:
80+
return Repository.find_repository_by_name_and_owner(repo, owner=user, client=self.bb)
81+
except HTTPError as err:
82+
raise ResourceNotFoundError('Cannot retrieve repository: {}/{} does not exists.'.format(user, repo))
14783

14884
@classmethod
14985
def get_auth_token(cls, login, password, prompt=None):
@@ -152,9 +88,9 @@ def get_auth_token(cls, login, password, prompt=None):
15288

15389
@property
15490
def user(self):
155-
ret, user = self.bb.get_user()
156-
if ret:
157-
return user['username']
158-
raise ResourceError("Could not retrieve username: {message} (error #{code}: {reason}".format(**result))
91+
try:
92+
return User.find_current_user(client=self.bb).username
93+
except HTTPError as err:
94+
raise ResourceError("Couldn't complete creation: {}".format(err)) from err
15995

16096

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,4 @@ GitPython>=2.1.0
55
uritemplate.py==2.0.0
66
github3.py==0.9.5
77
python-gitlab>=0.18
8-
bitbucket-api
98
gogs-client>=1.0.3

0 commit comments

Comments
 (0)