[Python-modules-commits] [python-bitbucket-api] 01/03: New upstream version 0.5.0
ChangZhuo Chen
czchen at moszumanska.debian.org
Sat Oct 15 08:35:09 UTC 2016
This is an automated email from the git hooks/post-receive script.
czchen pushed a commit to branch master
in repository python-bitbucket-api.
commit 770624d03ca1f01b954a5844f56d9f3c4283c7cc
Author: ChangZhuo Chen (陳昌倬) <czchen at debian.org>
Date: Sat Oct 15 16:24:59 2016 +0800
New upstream version 0.5.0
---
LICENSE | 13 ++
PKG-INFO | 63 ++++++++++
README | 33 +++++
bitbucket/__init__.py | 76 ++++++++++++
bitbucket/bitbucket.py | 292 ++++++++++++++++++++++++++++++++++++++++++++
bitbucket/deploy_key.py | 60 +++++++++
bitbucket/issue.py | 99 +++++++++++++++
bitbucket/issue_comment.py | 81 ++++++++++++
bitbucket/repository.py | 114 +++++++++++++++++
bitbucket/service.py | 75 ++++++++++++
bitbucket/ssh.py | 42 +++++++
bitbucket/tests/__init__.py | 5 +
bitbucket/tests/public.py | 140 +++++++++++++++++++++
setup.py | 30 +++++
14 files changed, 1123 insertions(+)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..5810e5a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) 2012 Millou Baptiste
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..6f505ae
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,63 @@
+Metadata-Version: 1.1
+Name: bitbucket-api
+Version: 0.5.0
+Summary: Bitbucket API
+Home-page: https://github.com/Sheeprider/BitBucket-api
+Author: Baptiste Millou
+Author-email: baptiste at smoothie-creative.com
+License: Copyright (c) 2012 Millou Baptiste
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Description: #BitBucket-API
+
+ [](http://travis-ci.org/Sheeprider/BitBucket-api)
+
+ BitBucket-api is an ISC Licensed library, written in Python.
+
+ Bitbucket has a REST API publicly available, this package provide methods to interact with it.
+ It allows you to access most repositories, services (hooks) and ssh keys related functionalities.
+
+ ##Features
+
+ * Access public user informations
+ * Access public or private repositories, tags or branches
+ * Create, update or delete one of your repository
+ * Access, create, update or delete a service (hook)
+ * Access, create or delete an SSH key
+ * Download a repository as an archive
+ * Access, create, update or delete an issue
+ * Access, create, update or delete an issue comment
+
+ ##Installation
+
+ To install bitbucket-api, simply:
+
+ $ pip install bitbucket-api
+
+
+ ##Requirements
+
+ Bitbucket-api require [requests](https://github.com/kennethreitz/requests), [sh](https://github.com/amoffat/sh) and [requests-oauthlib](https://github.com/requests/requests-oauthlib)to work, but dependencies should be handled by pip.
+
+ ##Documentation
+ Documentation is available on [Read The Docs](https://bitbucket-api.readthedocs.org/en/latest/index.html).
+
+Platform: UNKNOWN
+Classifier: Development Status :: 3 - Alpha
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: ISC License (ISCL)
+Classifier: Programming Language :: Python
+Classifier: Natural Language :: English
+Classifier: Operating System :: OS Independent
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff --git a/README b/README
new file mode 100644
index 0000000..052313a
--- /dev/null
+++ b/README
@@ -0,0 +1,33 @@
+#BitBucket-API
+
+[](http://travis-ci.org/Sheeprider/BitBucket-api)
+
+BitBucket-api is an ISC Licensed library, written in Python.
+
+Bitbucket has a REST API publicly available, this package provide methods to interact with it.
+It allows you to access most repositories, services (hooks) and ssh keys related functionalities.
+
+##Features
+
+* Access public user informations
+* Access public or private repositories, tags or branches
+* Create, update or delete one of your repository
+* Access, create, update or delete a service (hook)
+* Access, create or delete an SSH key
+* Download a repository as an archive
+* Access, create, update or delete an issue
+* Access, create, update or delete an issue comment
+
+##Installation
+
+To install bitbucket-api, simply:
+
+ $ pip install bitbucket-api
+
+
+##Requirements
+
+Bitbucket-api require [requests](https://github.com/kennethreitz/requests), [sh](https://github.com/amoffat/sh) and [requests-oauthlib](https://github.com/requests/requests-oauthlib)to work, but dependencies should be handled by pip.
+
+##Documentation
+Documentation is available on [Read The Docs](https://bitbucket-api.readthedocs.org/en/latest/index.html).
diff --git a/bitbucket/__init__.py b/bitbucket/__init__.py
new file mode 100644
index 0000000..fa8be13
--- /dev/null
+++ b/bitbucket/__init__.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+__version__ = '0.5.0'
+
+__doc__ = """
+Bitbucket has a REST API publicly available, this package provide methods to interact with it.
+It allows you to access repositories and perform various actions on them.
+
+Various usages : ::
+
+ from bitbucket.bitbucket import Bitbucket
+
+ # Access a public repository
+ bb = Bitbucket(USERNAME, repo_name_or_slug="public_repository")
+
+ # Access a private repository
+ bb = Bitbucket(USERNAME, PASSWORD, repo_name_or_slug="private_repository")
+
+ # Access a private repository through oauth
+ bb = Bitbucket(USERNAME, repo_name_or_slug="public_repository")
+ bb.authorize(CONSUMER_KEY, CONSUMER_SECRET, 'http://localhost/')
+
+
+ # Access your working repository
+ success, result = bb.repository.get()
+
+ # Create a repository, and define it as your working repository
+ success, result = bb.repository.create("repository_slug")
+ bb.repo_slug = "repository_slug"
+
+ # Update your working repository
+ success, result = bb.repository.update(description='new description')
+
+ # Delete a repository
+ success, result = bb.repository.delete("repository_slug")
+
+ # Download a repository as an archive
+ success, archive_path = bb.repository.archive()
+
+ # Access user informations
+ success, result = bb.get_user(username=USERNAME)
+
+ # Access tags and branches
+ success, result = bb.get_tags()
+ success, result = bb.get_branches()
+
+ # Access, create, update or delete a service (hook)
+ success, result = bb.service.get(service_id=SERVICE_ID)
+ success, result = bb.service.create(service=u'POST', URL='http://httpbin.org/')
+ success, result = bb.service.update(service_id=SERVICE_ID, URL='http://google.com')
+ success, result = bb.service.delete(service_id=SERVICE_ID)
+
+ # Access, create or delete an SSH key
+ success, result = bb.ssh.get(key_id=SSH_ID)
+ success, result = bb.ssh.create(key=r'ssh-rsa a1b2c3d4e5', label=u'my key')
+ success, result = bb.ssh.delete(key_id=SSH_ID)
+
+ # Access, create, update or delete an issue
+ success, result = bb.issue.get(issue_id=ISSUE_ID)
+ success, result = bb.issue.create(
+ title=u'Issue title',
+ content=u'Issue content',
+ responsible=bb.username,
+ status=u'new',
+ kind=u'bug')
+ success, result = bb.issue.update(issue_id=ISSUE_ID, content='New content')
+ success, result = bb.issue.delete(issue_id=ISSUE_ID)
+
+ # Access, create, update or delete an issue comment
+ success, result = bb.issue.comment.get(comment_id=COMMENT_ID)
+ success, result = bb.issue.comment.create(content='Content')
+ success, result = bb.issue.comment.update(
+ comment_id=COMMENT_ID,
+ content='New content')
+ success, result = bb.issue.comment.delete(comment_id=COMMENT_ID)
+
+"""
diff --git a/bitbucket/bitbucket.py b/bitbucket/bitbucket.py
new file mode 100644
index 0000000..e7d7b2b
--- /dev/null
+++ b/bitbucket/bitbucket.py
@@ -0,0 +1,292 @@
+# -*- coding: utf-8 -*-
+# git+git://github.com/Sheeprider/BitBucket-api.git
+
+__all__ = ['Bitbucket', ]
+
+try:
+ from urlparse import parse_qs
+except ImportError:
+ from urllib.parse import parse_qs
+
+import json
+import re
+
+from requests import Request, Session
+from requests_oauthlib import OAuth1
+import requests
+
+from .issue import Issue
+from .repository import Repository
+from .service import Service
+from .ssh import SSH
+from .deploy_key import DeployKey
+
+
+# ========
+# = URLs =
+# ========
+URLS = {
+ 'BASE': 'https://bitbucket.org/!api/1.0/%s',
+ # Get user profile and repos
+ 'GET_USER': 'users/%(username)s/',
+ 'GET_USER_PRIVILEGES': 'user/privileges',
+ # Search repo
+ # 'SEARCH_REPO': 'repositories/?name=%(search)s',
+ # Get tags & branches
+ 'GET_TAGS': 'repositories/%(username)s/%(repo_slug)s/tags/',
+ 'GET_BRANCHES': 'repositories/%(username)s/%(repo_slug)s/branches/',
+
+ 'REQUEST_TOKEN': 'oauth/request_token/',
+ 'AUTHENTICATE': 'oauth/authenticate?oauth_token=%(token)s',
+ 'ACCESS_TOKEN': 'oauth/access_token/'
+}
+
+
+class Bitbucket(object):
+ """ This class lets you interact with the bitbucket public API. """
+ def __init__(self, username='', password='', repo_name_or_slug=''):
+ self.username = username
+ self.password = password
+ self.repo_slug = repo_name_or_slug
+ self.repo_tree = {}
+ self.URLS = URLS
+
+ self.repository = Repository(self)
+ self.service = Service(self)
+ self.ssh = SSH(self)
+ self.issue = Issue(self)
+ self.deploy_key = DeployKey(self)
+
+ self.access_token = None
+ self.access_token_secret = None
+ self.consumer_key = None
+ self.consumer_secret = None
+ self.oauth = None
+
+ # ===================
+ # = Getters/Setters =
+ # ===================
+
+ @property
+ def auth(self):
+ """ Return credentials for current Bitbucket user. """
+ if self.oauth:
+ return self.oauth
+ return (self.username, self.password)
+
+ @property
+ def username(self):
+ """Return your repository's username."""
+ return self._username
+
+ @username.setter
+ def username(self, value):
+ try:
+ if isinstance(value, basestring):
+ self._username = unicode(value)
+ except NameError:
+ self._username = value
+
+ if value is None:
+ self._username = None
+
+ @username.deleter
+ def username(self):
+ del self._username
+
+ @property
+ def password(self):
+ """Return your repository's password."""
+ return self._password
+
+ @password.setter
+ def password(self, value):
+ try:
+ if isinstance(value, basestring):
+ self._password = unicode(value)
+ except NameError:
+ self._password = value
+
+ if value is None:
+ self._password = None
+
+ @password.deleter
+ def password(self):
+ del self._password
+
+ @property
+ def repo_slug(self):
+ """Return your repository's slug name."""
+ return self._repo_slug
+
+ @repo_slug.setter
+ def repo_slug(self, value):
+ if value is None:
+ self._repo_slug = None
+ else:
+ try:
+ if isinstance(value, basestring):
+ value = unicode(value)
+ except NameError:
+ pass
+ value = value.lower()
+ self._repo_slug = re.sub(r'[^a-z0-9_-]+', '-', value)
+
+ @repo_slug.deleter
+ def repo_slug(self):
+ del self._repo_slug
+
+ # ========================
+ # = Oauth authentication =
+ # ========================
+
+ def authorize(self, consumer_key, consumer_secret, callback_url=None,
+ access_token=None, access_token_secret=None):
+ """
+ Call this with your consumer key, secret and callback URL, to
+ generate a token for verification.
+ """
+ self.consumer_key = consumer_key
+ self.consumer_secret = consumer_secret
+
+ if not access_token and not access_token_secret:
+ if not callback_url:
+ return (False, "Callback URL required")
+ oauth = OAuth1(
+ consumer_key,
+ client_secret=consumer_secret,
+ callback_uri=callback_url)
+ r = requests.post(self.url('REQUEST_TOKEN'), auth=oauth)
+ if r.status_code == 200:
+ creds = parse_qs(r.content)
+
+ self.access_token = creds.get('oauth_token')[0]
+ self.access_token_secret = creds.get('oauth_token_secret')[0]
+ else:
+ return (False, r.content)
+ else:
+ self.finalize_oauth(access_token, access_token_secret)
+
+ return (True, None)
+
+ def verify(self, verifier, consumer_key=None, consumer_secret=None,
+ access_token=None, access_token_secret=None):
+ """
+ After converting the token into verifier, call this to finalize the
+ authorization.
+ """
+ # Stored values can be supplied to verify
+ self.consumer_key = consumer_key or self.consumer_key
+ self.consumer_secret = consumer_secret or self.consumer_secret
+ self.access_token = access_token or self.access_token
+ self.access_token_secret = access_token_secret or self.access_token_secret
+
+ oauth = OAuth1(
+ self.consumer_key,
+ client_secret=self.consumer_secret,
+ resource_owner_key=self.access_token,
+ resource_owner_secret=self.access_token_secret,
+ verifier=verifier)
+ r = requests.post(self.url('ACCESS_TOKEN'), auth=oauth)
+ if r.status_code == 200:
+ creds = parse_qs(r.content)
+ else:
+ return (False, r.content)
+
+ self.finalize_oauth(creds.get('oauth_token')[0],
+ creds.get('oauth_token_secret')[0])
+ return (True, None)
+
+ def finalize_oauth(self, access_token, access_token_secret):
+ """ Called internally once auth process is complete. """
+ self.access_token = access_token
+ self.access_token_secret = access_token_secret
+
+ # Final OAuth object
+ self.oauth = OAuth1(
+ self.consumer_key,
+ client_secret=self.consumer_secret,
+ resource_owner_key=self.access_token,
+ resource_owner_secret=self.access_token_secret)
+
+ # ======================
+ # = High lvl functions =
+ # ======================
+
+ def dispatch(self, method, url, auth=None, params=None, **kwargs):
+ """ Send HTTP request, with given method,
+ credentials and data to the given URL,
+ and return the success and the result on success.
+ """
+ r = Request(
+ method=method,
+ url=url,
+ auth=auth,
+ params=params,
+ data=kwargs)
+ s = Session()
+ resp = s.send(r.prepare())
+ status = resp.status_code
+ text = resp.text
+ error = resp.reason
+ if status >= 200 and status < 300:
+ if text:
+ try:
+ return (True, json.loads(text))
+ except TypeError:
+ pass
+ except ValueError:
+ pass
+ return (True, text)
+ elif status >= 300 and status < 400:
+ return (
+ False,
+ 'Unauthorized access, '
+ 'please check your credentials.')
+ elif status >= 400 and status < 500:
+ return (False, 'Service not found.')
+ elif status >= 500 and status < 600:
+ return (False, 'Server error.')
+ else:
+ return (False, error)
+
+ def url(self, action, **kwargs):
+ """ Construct and return the URL for a specific API service. """
+ # TODO : should be static method ?
+ return self.URLS['BASE'] % self.URLS[action] % kwargs
+
+ # =====================
+ # = General functions =
+ # =====================
+
+ def get_user(self, username=None):
+ """ Returns user informations.
+ If username is not defined, tries to return own informations.
+ """
+ username = username or self.username or ''
+ url = self.url('GET_USER', username=username)
+ response = self.dispatch('GET', url)
+ try:
+ return (response[0], response[1]['user'])
+ except TypeError:
+ pass
+ return response
+
+ def get_tags(self, repo_slug=None):
+ """ Get a single repository on Bitbucket and return its tags."""
+ repo_slug = repo_slug or self.repo_slug or ''
+ url = self.url('GET_TAGS', username=self.username, repo_slug=repo_slug)
+ return self.dispatch('GET', url, auth=self.auth)
+
+ def get_branches(self, repo_slug=None):
+ """ Get a single repository on Bitbucket and return its branches."""
+ repo_slug = repo_slug or self.repo_slug or ''
+ url = self.url('GET_BRANCHES',
+ username=self.username,
+ repo_slug=repo_slug)
+ return self.dispatch('GET', url, auth=self.auth)
+
+ def get_privileges(self):
+ """ Get privledges for this user. """
+ url = self.url('GET_USER_PRIVILEGES')
+ return self.dispatch('GET', url, auth=self.auth)
diff --git a/bitbucket/deploy_key.py b/bitbucket/deploy_key.py
new file mode 100644
index 0000000..285aa17
--- /dev/null
+++ b/bitbucket/deploy_key.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+URLS = {
+ # deploy keys
+ 'GET_DEPLOY_KEYS': 'repositories/%(username)s/%(repo_slug)s/deploy-keys',
+ 'SET_DEPLOY_KEY': 'repositories/%(username)s/%(repo_slug)s/deploy-keys',
+ 'GET_DEPLOY_KEY': 'repositories/%(username)s/%(repo_slug)s/deploy-keys/%(key_id)s',
+ 'DELETE_DEPLOY_KEY': 'repositories/%(username)s/%(repo_slug)s/deploy-keys/%(key_id)s',
+}
+
+
+class DeployKey(object):
+ """ This class provide services-related methods to Bitbucket objects."""
+
+ def __init__(self, bitbucket):
+ self.bitbucket = bitbucket
+ self.bitbucket.URLS.update(URLS)
+
+ def all(self, repo_slug=None):
+ """ Get all ssh keys associated with a repo
+ """
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('GET_DEPLOY_KEYS',
+ username=self.bitbucket.username,
+ repo_slug=repo_slug)
+ return self.bitbucket.dispatch('GET', url, auth=self.bitbucket.auth)
+
+ def get(self, repo_slug=None, key_id=None):
+ """ Get one of the ssh keys associated with this repo
+ """
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('GET_DEPLOY_KEY',
+ key_id=key_id,
+ username=self.bitbucket.username,
+ repo_slug=repo_slug)
+ return self.bitbucket.dispatch('GET', url, auth=self.bitbucket.auth)
+
+ def create(self, repo_slug=None, key=None, label=None):
+ """ Associate an ssh key with your repo and return it.
+ """
+ key = '%s' % key
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('SET_DEPLOY_KEY',
+ username=self.bitbucket.username,
+ repo_slug=repo_slug)
+ return self.bitbucket.dispatch('POST',
+ url,
+ auth=self.bitbucket.auth,
+ key=key,
+ label=label)
+
+ def delete(self, repo_slug=None, key_id=None):
+ """ Delete one of the ssh keys associated with your repo.
+ Please use with caution as there is NO confimation and NO undo.
+ """
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('DELETE_DEPLOY_KEY',
+ key_id=key_id,
+ username=self.bitbucket.username,
+ repo_slug=repo_slug)
+ return self.bitbucket.dispatch('DELETE', url, auth=self.bitbucket.auth)
diff --git a/bitbucket/issue.py b/bitbucket/issue.py
new file mode 100644
index 0000000..40be84b
--- /dev/null
+++ b/bitbucket/issue.py
@@ -0,0 +1,99 @@
+# -*- coding: utf-8 -*-
+from .issue_comment import IssueComment
+
+
+URLS = {
+ # Issues
+ 'GET_ISSUES': 'repositories/%(username)s/%(repo_slug)s/issues/',
+ 'GET_ISSUE': 'repositories/%(username)s/%(repo_slug)s/issues/%(issue_id)s/',
+ 'CREATE_ISSUE': 'repositories/%(username)s/%(repo_slug)s/issues/',
+ 'UPDATE_ISSUE': 'repositories/%(username)s/%(repo_slug)s/issues/%(issue_id)s/',
+ 'DELETE_ISSUE': 'repositories/%(username)s/%(repo_slug)s/issues/%(issue_id)s/',
+}
+
+
+class Issue(object):
+ """ This class provide issue-related methods to Bitbucket objects."""
+
+ def __init__(self, bitbucket, issue_id=None):
+ self.bitbucket = bitbucket
+ self.bitbucket.URLS.update(URLS)
+ self.issue_id = issue_id
+ self.comment = IssueComment(self)
+
+ @property
+ def issue_id(self):
+ """Your repository slug name."""
+ return self._issue_id
+
+ @issue_id.setter
+ def issue_id(self, value):
+ if value:
+ self._issue_id = int(value)
+ elif value is None:
+ self._issue_id = None
+
+ @issue_id.deleter
+ def issue_id(self):
+ del self._issue_id
+
+ def all(self, repo_slug=None, params=None):
+ """ Get issues from one of your repositories.
+ """
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('GET_ISSUES', username=self.bitbucket.username, repo_slug=repo_slug)
+ return self.bitbucket.dispatch('GET', url, auth=self.bitbucket.auth, params=params)
+
+ def get(self, issue_id, repo_slug=None):
+ """ Get an issue from one of your repositories.
+ """
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('GET_ISSUE', username=self.bitbucket.username, repo_slug=repo_slug, issue_id=issue_id)
+ return self.bitbucket.dispatch('GET', url, auth=self.bitbucket.auth)
+
+ def create(self, repo_slug=None, **kwargs):
+ """
+ Add an issue to one of your repositories.
+ Each issue require a different set of attributes,
+ you can pass them as keyword arguments (attributename='attributevalue').
+ Attributes are:
+
+ * title: The title of the new issue.
+ * content: The content of the new issue.
+ * component: The component associated with the issue.
+ * milestone: The milestone associated with the issue.
+ * version: The version associated with the issue.
+ * responsible: The username of the person responsible for the issue.
+ * status: The status of the issue (new, open, resolved, on hold, invalid, duplicate, or wontfix).
+ * kind: The kind of issue (bug, enhancement, or proposal).
+ """
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('CREATE_ISSUE', username=self.bitbucket.username, repo_slug=repo_slug)
+ return self.bitbucket.dispatch('POST', url, auth=self.bitbucket.auth, **kwargs)
+
+ def update(self, issue_id, repo_slug=None, **kwargs):
+ """
+ Update an issue to one of your repositories.
+ Each issue require a different set of attributes,
+ you can pass them as keyword arguments (attributename='attributevalue').
+ Attributes are:
+
+ * title: The title of the new issue.
+ * content: The content of the new issue.
+ * component: The component associated with the issue.
+ * milestone: The milestone associated with the issue.
+ * version: The version associated with the issue.
+ * responsible: The username of the person responsible for the issue.
+ * status: The status of the issue (new, open, resolved, on hold, invalid, duplicate, or wontfix).
+ * kind: The kind of issue (bug, enhancement, or proposal).
+ """
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('UPDATE_ISSUE', username=self.bitbucket.username, repo_slug=repo_slug, issue_id=issue_id)
+ return self.bitbucket.dispatch('PUT', url, auth=self.bitbucket.auth, **kwargs)
+
+ def delete(self, issue_id, repo_slug=None):
+ """ Delete an issue from one of your repositories.
+ """
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('DELETE_ISSUE', username=self.bitbucket.username, repo_slug=repo_slug, issue_id=issue_id)
+ return self.bitbucket.dispatch('DELETE', url, auth=self.bitbucket.auth)
diff --git a/bitbucket/issue_comment.py b/bitbucket/issue_comment.py
new file mode 100644
index 0000000..f7c4661
--- /dev/null
+++ b/bitbucket/issue_comment.py
@@ -0,0 +1,81 @@
+# -*- coding: utf-8 -*-
+URLS = {
+ # Issue comments
+ 'GET_COMMENTS': 'repositories/%(username)s/%(repo_slug)s/issues/%(issue_id)s/comments/',
+ 'GET_COMMENT': 'repositories/%(username)s/%(repo_slug)s/issues/%(issue_id)s/comments/%(comment_id)s/',
+ 'CREATE_COMMENT': 'repositories/%(username)s/%(repo_slug)s/issues/%(issue_id)s/comments/',
+ 'UPDATE_COMMENT': 'repositories/%(username)s/%(repo_slug)s/issues/%(issue_id)s/comments/%(comment_id)s/',
+ 'DELETE_COMMENT': 'repositories/%(username)s/%(repo_slug)s/issues/%(issue_id)s/comments/%(comment_id)s/',
+}
+
+
+class IssueComment(object):
+ """ This class provide issue's comments related methods to Bitbucket objects."""
+
+ def __init__(self, issue):
+ self.issue = issue
+ self.bitbucket = self.issue.bitbucket
+ self.bitbucket.URLS.update(URLS)
+ self.issue_id = issue.issue_id
+
+ def all(self, issue_id=None, repo_slug=None):
+ """ Get issue comments from one of your repositories.
+ """
+ issue_id = issue_id or self.issue_id
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('GET_COMMENTS',
+ username=self.bitbucket.username,
+ repo_slug=repo_slug,
+ issue_id=issue_id)
+ return self.bitbucket.dispatch('GET', url, auth=self.bitbucket.auth)
+
+ def get(self, comment_id, issue_id=None, repo_slug=None):
+ """ Get an issue from one of your repositories.
+ """
+ issue_id = issue_id or self.issue_id
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('GET_COMMENT',
+ username=self.bitbucket.username,
+ repo_slug=repo_slug,
+ issue_id=issue_id,
+ comment_id=comment_id)
+ return self.bitbucket.dispatch('GET', url, auth=self.bitbucket.auth)
+
+ def create(self, issue_id=None, repo_slug=None, **kwargs):
+ """ Add an issue comment to one of your repositories.
+ Each issue comment require only the content data field
+ the system autopopulate the rest.
+ """
+ issue_id = issue_id or self.issue_id
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('CREATE_COMMENT',
+ username=self.bitbucket.username,
+ repo_slug=repo_slug,
+ issue_id=issue_id)
+ return self.bitbucket.dispatch('POST', url, auth=self.bitbucket.auth, **kwargs)
+
+ def update(self, comment_id, issue_id=None, repo_slug=None, **kwargs):
+ """ Update an issue comment in one of your repositories.
+ Each issue comment require only the content data field
+ the system autopopulate the rest.
+ """
+ issue_id = issue_id or self.issue_id
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('UPDATE_COMMENT',
+ username=self.bitbucket.username,
+ repo_slug=repo_slug,
+ issue_id=issue_id,
+ comment_id=comment_id)
+ return self.bitbucket.dispatch('PUT', url, auth=self.bitbucket.auth, **kwargs)
+
+ def delete(self, comment_id, issue_id=None, repo_slug=None):
+ """ Delete an issue from one of your repositories.
+ """
+ issue_id = issue_id or self.issue_id
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('DELETE_COMMENT',
+ username=self.bitbucket.username,
+ repo_slug=repo_slug,
+ issue_id=issue_id,
+ comment_id=comment_id)
+ return self.bitbucket.dispatch('DELETE', url, auth=self.bitbucket.auth)
diff --git a/bitbucket/repository.py b/bitbucket/repository.py
new file mode 100644
index 0000000..b900b9b
--- /dev/null
+++ b/bitbucket/repository.py
@@ -0,0 +1,114 @@
+# -*- coding: utf-8 -*-
+from tempfile import NamedTemporaryFile
+from zipfile import ZipFile
+
+
+URLS = {
+ 'CREATE_REPO': 'repositories/',
+ 'GET_REPO': 'repositories/%(username)s/%(repo_slug)s/',
+ 'UPDATE_REPO': 'repositories/%(username)s/%(repo_slug)s/',
+ 'DELETE_REPO': 'repositories/%(username)s/%(repo_slug)s/',
+ # Get archive
+ 'GET_ARCHIVE': 'repositories/%(username)s/%(repo_slug)s/%(format)s/master/',
+}
+
+
+class Repository(object):
+ """ This class provide repository-related methods to Bitbucket objects."""
+
+ def __init__(self, bitbucket):
+ self.bitbucket = bitbucket
+ self.bitbucket.URLS.update(URLS)
+
+ def _get_files_in_dir(self, repo_slug=None, dir='/'):
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ dir = dir.lstrip('/')
+ url = self.bitbucket.url(
+ 'GET_ARCHIVE',
+ username=self.bitbucket.username,
+ repo_slug=repo_slug,
+ format='src')
+ dir_url = url + dir
+ response = self.bitbucket.dispatch('GET', dir_url, auth=self.bitbucket.auth)
+ if response[0] and isinstance(response[1], dict):
+ repo_tree = response[1]
+ url = self.bitbucket.url(
+ 'GET_ARCHIVE',
+ username=self.bitbucket.username,
+ repo_slug=repo_slug,
+ format='raw')
+ # Download all files in dir
+ for file in repo_tree['files']:
+ file_url = url + '/'.join((file['path'],))
+ response = self.bitbucket.dispatch('GET', file_url, auth=self.bitbucket.auth)
+ self.bitbucket.repo_tree[file['path']] = response[1]
+ # recursively download in dirs
+ for directory in repo_tree['directories']:
+ dir_path = '/'.join((dir, directory))
+ self._get_files_in_dir(repo_slug=repo_slug, dir=dir_path)
+
+ def public(self, username=None):
+ """ Returns all public repositories from an user.
+ If username is not defined, tries to return own public repos.
+ """
+ username = username or self.bitbucket.username or ''
+ url = self.bitbucket.url('GET_USER', username=username)
+ response = self.bitbucket.dispatch('GET', url)
+ try:
+ return (response[0], response[1]['repositories'])
+ except TypeError:
+ pass
+ return response
+
+ def all(self):
+ """ Return own repositories."""
+ url = self.bitbucket.url('GET_USER', username=self.bitbucket.username)
+ response = self.bitbucket.dispatch('GET', url, auth=self.bitbucket.auth)
+ try:
+ return (response[0], response[1]['repositories'])
+ except TypeError:
+ pass
+ return response
+
+ def get(self, repo_slug=None):
+ """ Get a single repository on Bitbucket and return it."""
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('GET_REPO', username=self.bitbucket.username, repo_slug=repo_slug)
+ return self.bitbucket.dispatch('GET', url, auth=self.bitbucket.auth)
+
+ def create(self, repo_name, scm='git', private=True, **kwargs):
+ """ Creates a new repository on own Bitbucket account and return it."""
+ url = self.bitbucket.url('CREATE_REPO')
+ return self.bitbucket.dispatch('POST', url, auth=self.bitbucket.auth, name=repo_name, scm=scm, is_private=private, **kwargs)
+
+ def update(self, repo_slug=None, **kwargs):
+ """ Updates repository on own Bitbucket account and return it."""
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('UPDATE_REPO', username=self.bitbucket.username, repo_slug=repo_slug)
+ return self.bitbucket.dispatch('PUT', url, auth=self.bitbucket.auth, **kwargs)
+
+ def delete(self, repo_slug=None):
+ """ Delete a repository on own Bitbucket account.
+ Please use with caution as there is NO confimation and NO undo.
+ """
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('DELETE_REPO', username=self.bitbucket.username, repo_slug=repo_slug)
+ return self.bitbucket.dispatch('DELETE', url, auth=self.bitbucket.auth)
+
+ def archive(self, repo_slug=None, format='zip', prefix=''):
+ """ Get one of your repositories and compress it as an archive.
+ Return the path of the archive.
+
+ format parameter is curently not supported.
+ """
+ prefix = '%s'.lstrip('/') % prefix
+ self._get_files_in_dir(repo_slug=repo_slug, dir='/')
+ if self.bitbucket.repo_tree:
+ with NamedTemporaryFile(delete=False) as archive:
+ with ZipFile(archive, 'w') as zip_archive:
+ for name, file in self.bitbucket.repo_tree.items():
+ with NamedTemporaryFile(delete=False) as temp_file:
+ temp_file.write(file.encode('utf-8'))
+ zip_archive.write(temp_file.name, prefix + name)
+ return (True, archive.name)
+ return (False, 'Could not archive your project.')
diff --git a/bitbucket/service.py b/bitbucket/service.py
new file mode 100644
index 0000000..843f9ca
--- /dev/null
+++ b/bitbucket/service.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+URLS = {
+ # Get services (hooks)
+ 'GET_SERVICE': 'repositories/%(username)s/%(repo_slug)s/services/%(service_id)s/',
+ 'GET_SERVICES': 'repositories/%(username)s/%(repo_slug)s/services/',
+ # Set services (hooks)
+ 'SET_SERVICE': 'repositories/%(username)s/%(repo_slug)s/services/',
+ 'UPDATE_SERVICE': 'repositories/%(username)s/%(repo_slug)s/services/%(service_id)s/',
+ 'DELETE_SERVICE': 'repositories/%(username)s/%(repo_slug)s/services/%(service_id)s/',
+}
+
+
+class Service(object):
+ """ This class provide services-related methods to Bitbucket objects."""
+
+ def __init__(self, bitbucket):
+ self.bitbucket = bitbucket
+ self.bitbucket.URLS.update(URLS)
+
+ def create(self, service, repo_slug=None, **kwargs):
+ """ Add a service (hook) to one of your repositories.
+ Each type of service require a different set of additionnal fields,
+ you can pass them as keyword arguments (fieldname='fieldvalue').
+ """
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('SET_SERVICE', username=self.bitbucket.username, repo_slug=repo_slug)
+ return self.bitbucket.dispatch('POST', url, auth=self.bitbucket.auth, type=service, **kwargs)
+
+ def get(self, service_id, repo_slug=None):
+ """ Get a service (hook) from one of your repositories.
+ """
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('GET_SERVICE', username=self.bitbucket.username, repo_slug=repo_slug, service_id=service_id)
+ return self.bitbucket.dispatch('GET', url, auth=self.bitbucket.auth)
+
+ def update(self, service_id, repo_slug=None, **kwargs):
+ """ Update a service (hook) from one of your repositories.
+ """
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('UPDATE_SERVICE', username=self.bitbucket.username, repo_slug=repo_slug, service_id=service_id)
+ return self.bitbucket.dispatch('PUT', url, auth=self.bitbucket.auth, **kwargs)
+
+ def delete(self, service_id, repo_slug=None):
+ """ Delete a service (hook) from one of your repositories.
+ Please use with caution as there is NO confimation and NO undo.
+ """
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('DELETE_SERVICE', username=self.bitbucket.username, repo_slug=repo_slug, service_id=service_id)
+ return self.bitbucket.dispatch('DELETE', url, auth=self.bitbucket.auth)
+
+ def all(self, repo_slug=None):
+ """ Get all services (hook) from one of your repositories.
+ """
+ repo_slug = repo_slug or self.bitbucket.repo_slug or ''
+ url = self.bitbucket.url('GET_SERVICES', username=self.bitbucket.username, repo_slug=repo_slug)
+ return self.bitbucket.dispatch('GET', url, auth=self.bitbucket.auth)
+
+# ============
+# = Services =
+# ============
+# SERVICES = {
+# 'Basecamp': ('Username', 'Password', 'Discussion URL',),
+# 'CIA.vc': ('Module', 'Project',),
+# 'Email Diff': ('Email',),
+# 'Email': ('Email',),
+# 'FogBugz': ('Repository ID', 'CVSSubmit URL',),
+# 'FriendFeed': ('Username', 'Remote Key', 'Format',),
+# 'Geocommit': (None,),
+# 'Issues': (None,),
+# 'Lighthouse': ('Project ID', 'API Key', 'Subdomain',),
+# 'Pivotal Tracker': ('Token',),
+# 'POST': ('URL',),
+# 'Rietveld': ('Email', 'Password', 'URL',),
+# 'Superfeedr': (None,),
+# }
diff --git a/bitbucket/ssh.py b/bitbucket/ssh.py
new file mode 100644
index 0000000..7e0ee79
--- /dev/null
+++ b/bitbucket/ssh.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+URLS = {
+ # SSH keys
+ 'GET_SSH_KEYS': 'ssh-keys/',
+ 'GET_SSH_KEY': 'ssh-keys/%(key_id)s',
+ 'SET_SSH_KEY': 'ssh-keys/',
... 229 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-bitbucket-api.git
More information about the Python-modules-commits
mailing list