Skip to content

Commit 3b6854d

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 <guyzmo+github@m0g.net>
1 parent 18a3d4f commit 3b6854d

18 files changed

+95
-929
lines changed

git_repo/repo.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@
134134
print('Please use with python version 3')
135135
sys.exit(1)
136136

137-
from .exceptions import ArgumentError
137+
from .exceptions import ArgumentError, ResourceNotFoundError
138138
from .services.service import RepositoryService
139139

140140
from .kwargparse import KeywordArgumentParser, store_parameter, register_action

git_repo/services/ext/bitbucket.py

+63-117
Original file line numberDiff line numberDiff line change
@@ -6,144 +6,90 @@
66
from ..service import register_target, RepositoryService
77
from ...exceptions import ResourceError, ResourceExistsError, ResourceNotFoundError
88

9-
import bitbucket.bitbucket as bitbucket
10-
from requests import Request, Session
11-
import json
9+
from pybitbucket.bitbucket import Client
10+
from pybitbucket.auth import BasicAuthenticator
11+
from pybitbucket.user import User
12+
from pybitbucket.repository import Repository, RepositoryPayload, RepositoryForkPolicy
13+
try:
14+
from pybitbucket.repository import RepositoryForkPayload
15+
except ImportError:
16+
RepositoryForkPayload = None
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))
9118

19+
from requests import Request, Session
20+
from requests.exceptions import HTTPError
21+
import json
9222

9323
@register_target('bb', 'bitbucket')
9424
class BitbucketService(RepositoryService):
9525
fqdn = 'bitbucket.org'
9626

9727
def __init__(self, *args, **kwarg):
98-
self.bb = Bitbucket()
28+
self.bb = Client()
9929
super(BitbucketService, self).__init__(*args, **kwarg)
10030

10131
def connect(self):
10232
if not self._privatekey:
10333
raise ConnectionError('Could not connect to BitBucket. Please configure .gitconfig with your bitbucket credentials.')
10434
if not ':' in self._privatekey:
10535
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.')
36+
self.bb.config = BasicAuthenticator(*self._privatekey.split(':')+['z+git-repo+pub@m0g.net'])
37+
self.bb.session = self.bb.config.session
38+
try:
39+
User.find_current_user(client=self.bb)
40+
except HTTPError as err:
41+
raise ConnectionError('Could not connect to BitBucket. Not authorized, wrong credentials.') from err
11142

11243
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)
44+
try:
45+
repo = Repository.create(
46+
payload=RepositoryPayload(dict(
47+
fork_policy=RepositoryForkPolicy.ALLOW_FORKS,
48+
is_private=False)),
49+
repository_name=repo,
50+
owner=user,
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.response.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))
125-
return '/'.join([result['owner'], result['slug']])
61+
if not RepositoryForkPayload:
62+
raise NotImplementedError('Feature not yet supported by the underlying library.')
63+
try:
64+
result = Repository.find_repository_by_name_and_owner(repo, owner=user, client=self.bb).fork(
65+
payload=RepositoryForkPayload(dict(
66+
name=repo,
67+
fork_policy=RepositoryForkPolicy.ALLOW_FORKS,
68+
is_private=False
69+
)),
70+
repository_name=repo,
71+
owner=user,
72+
client=self.bb
73+
)
74+
except HTTPError as err:
75+
raise ResourceError("Couldn't complete creation: {}".format(err)) from err
76+
return '/'.join([result.owner, result.slug])
12677

12778
def delete(self, repo, user=None):
12879
if not user:
12980
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))
81+
try:
82+
Repository.find_repository_by_name_and_owner(repo, owner=user, client=self.bb).delete()
83+
except HTTPError as err:
84+
if err.response.status_code == 404:
85+
raise ResourceNotFoundError("Cannot delete: repository {}/{} does not exists.".format(user, repo)) from err
86+
raise ResourceError("Couldn't complete creation: {}".format(err)) from err
13587

13688
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))
89+
try:
90+
return Repository.find_repository_by_name_and_owner(repo, owner=user, client=self.bb)
91+
except HTTPError as err:
92+
raise ResourceNotFoundError('Cannot retrieve repository: {}/{} does not exists.'.format(user, repo))
14793

14894
@classmethod
14995
def get_auth_token(cls, login, password, prompt=None):
@@ -152,9 +98,9 @@ def get_auth_token(cls, login, password, prompt=None):
15298

15399
@property
154100
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))
101+
try:
102+
return User.find_current_user(client=self.bb).username
103+
except HTTPError as err:
104+
raise ResourceError("Couldn't complete creation: {}".format(err)) from err
159105

160106

git_repo/services/service.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
from subprocess import call
1313

14-
from ..exceptions import ArgumentError
14+
from ..exceptions import ArgumentError, ResourceError
1515

1616
'''select open command'''
1717

requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ GitPython>=2.1.0
44
uritemplate.py==2.0.0
55
github3.py==0.9.5
66
python-gitlab>=0.13
7-
bitbucket-api
7+
-e git+https://github.com/guyzmo/pybitbucket.git@master#egg=pybitbucket-0.11.2

0 commit comments

Comments
 (0)