Work In Progress!

Get the full activation and deactivation cycle working for bitbucket.
This commit is contained in:
Joseph Schorr 2015-04-28 18:15:12 -04:00
parent 5cc91ed202
commit 6479f8ddc9
8 changed files with 204 additions and 65 deletions

View file

@ -7,7 +7,7 @@ import re
import json
from github import Github, UnknownObjectException, GithubException
from bitbucket.bitbucket import Bitbucket
from bitbucket import BitBucket
from tempfile import SpooledTemporaryFile
from jsonschema import validate
from data import model
@ -186,75 +186,123 @@ class BitbucketBuildTrigger(BuildTriggerHandler):
def service_name(cls):
return 'bitbucket'
def _get_authorized_client(self, namespace=None):
def _get_client(self):
key = app.config.get('BITBUCKET_TRIGGER_CONFIG', {}).get('CONSUMER_KEY', '')
secret = app.config.get('BITBUCKET_TRIGGER_CONFIG', {}).get('CONSUMER_SECRET', '')
trigger_uuid = self.trigger.uuid
callback_url = '%s/oauth1/bitbucket/callback/trigger/%s' % (get_app_url(), trigger_uuid)
bitbucket_client = Bitbucket(username=namespace or self.config.get('username', ''))
return BitBucket(key, secret, callback_url)
(result, err_message) = bitbucket_client.authorize(key, secret, callback_url,
access_token=self.config.get('access_token'),
access_token_secret=self.auth_token)
if not result:
raise TriggerProviderException(err_message)
def _get_authorized_client(self):
base_client = self._get_client()
auth_token = self.auth_token or 'invalid:invalid'
(access_token, access_token_secret) = auth_token.split(':')
return base_client.get_authorized_client(access_token, access_token_secret)
return bitbucket_client
def _get_repository_client(self):
source = self.config['build_source']
(namespace, name) = source.split('/')
bitbucket_client = self._get_authorized_client()
return bitbucket_client.for_namespace(namespace).repositories().get(name)
def get_oauth_url(self):
bitbucket_client = self._get_authorized_client()
url = bitbucket_client.url('AUTHENTICATE', token=bitbucket_client.access_token)
return {
'access_token': bitbucket_client.access_token,
'access_token_secret': bitbucket_client.access_token_secret,
'url': url
}
bitbucket_client = self._get_client()
(result, data, err_msg) = bitbucket_client.get_authorization_url()
if not result:
raise RepositoryReadException(err_msg)
return data
def exchange_verifier(self, verifier):
bitbucket_client = self._get_authorized_client()
(result, data) = bitbucket_client.verify(verifier,
access_token=self.config.get('access_token', ''),
access_token_secret=self.auth_token)
bitbucket_client = self._get_client()
access_token = self.config.get('access_token', '')
access_token_secret = self.auth_token
# Exchange the verifier for a new access token.
(result, data, _) = bitbucket_client.verify_token(access_token, access_token_secret, verifier)
if not result:
return False
# Request the user's information and save it and the access token to the config.
user_url = bitbucket_client.URLS['BASE'] % 'user'
(result, data) = bitbucket_client.dispatch('GET', user_url, auth=bitbucket_client.auth)
# Save the updated access token and secret.
self.set_auth_token(data[0] + ':' + data[1])
# Retrieve the current authorized user's information and store the username in the config.
authorized_client = self._get_authorized_client()
(result, data, _) = authorized_client.get_current_user()
if not result:
return False
username = data['user']['username']
new_access_token = bitbucket_client.access_token
self.put_config_key('username', username)
self.put_config_key('access_token', new_access_token)
self.set_auth_token(bitbucket_client.access_token_secret)
return True
def is_active(self):
return False
return 'hook_id' in self.config
def activate(self, standard_webhook_url):
return {}
config = self.config
# Add a deploy key to the repository.
public_key, private_key = generate_ssh_keypair()
config['credentials'] = [
{
'name': 'SSH Public Key',
'value': public_key,
},
]
repository = self._get_repository_client()
(result, data, err_msg) = repository.deploykeys().create(
app.config['REGISTRY_TITLE'] + ' webhook key', public_key)
if not result:
msg = 'Unable to add deploy key to repository: %s' % err_msg
raise TriggerActivationException(msg)
config['deploy_key_id'] = data['pk']
# Add a webhook callback.
(result, data, err_msg) = repository.services().create('POST', URL=standard_webhook_url)
if not result:
msg = 'Unable to add webhook to repository: %s' % err_msg
raise TriggerActivationException(msg)
config['hook_id'] = data['id']
return config, {'private_key': private_key}
def deactivate(self):
return self.config
config = self.config
repository = self._get_repository_client()
# Remove the webhook link.
(result, _, err_msg) = repository.services().delete(config['hook_id'])
if not result:
msg = 'Unable to remove webhook from repository: %s' % err_msg
raise TriggerDeactivationException(msg)
# Remove the public key.
(result, _, err_msg) = repository.deploykeys().delete(config['deploy_key_id'])
if not result:
msg = 'Unable to remove deploy key from repository: %s' % err_msg
raise TriggerDeactivationException(msg)
config.pop('hook_id', None)
config.pop('deploy_key_id', None)
return config
def list_build_sources(self):
bitbucket_client = self._get_authorized_client()
success, repositories = bitbucket_client.repository.all()
if not success:
raise RepositoryReadException('Could not read repository list')
(result, data, err_msg) = bitbucket_client.get_visible_repositories()
if not result:
raise RepositoryReadException('Could not read repository list: ' + err_msg)
namespaces = {}
for repo in repositories:
for repo in data:
if not repo['scm'] == 'git':
continue
@ -272,36 +320,101 @@ class BitbucketBuildTrigger(BuildTriggerHandler):
return namespaces.values()
def list_build_subdirs(self):
source = self.config['build_source']
(namespace, name) = source.split('/')
(result, data) = self._get_authorized_client(namespace=namespace).repository.get(name)
repository = self._get_repository_client()
(result, data, err_msg) = repository.get_path_contents('', revision='master')
if not result:
raise RepositoryReadException(err_msg)
files = set([f['path'] for f in data['files']])
if 'Dockerfile' in files:
return ['/']
print result
print data
return []
def dockerfile_url(self):
return None
repository = self._get_repository_client()
subdirectory = self.config.get('subdir', '')
path = subdirectory + '/Dockerfile' if subdirectory else 'Dockerfile'
master_branch = 'master'
(result, data, _) = repository.get_main_branch()
if result:
master_branch = data['name']
return 'https://bitbucket.org/%s/%s/src/%s/%s' % (repository.namespace,
repository.repository_name,
master_branch, path)
def load_dockerfile_contents(self):
raise RepositoryReadException('Not supported')
repository = self._get_repository_client()
subdirectory = self.config.get('subdir', '/')[1:]
path = subdirectory + '/Dockerfile' if subdirectory else 'Dockerfile'
def handle_trigger_request(self, request):
return
(result, data, err_msg) = repository.get_raw_path_contents(path, revision='master')
if not result:
raise RepositoryReadException(err_msg)
def manual_start(self, run_parameters=None):
return None
return data
def list_field_values(self, field_name):
source = self.config['build_source']
(namespace, name) = source.split('/')
(result, data) = self._get_authorized_client(namespace=namespace).repository.get(name)
print result
print data
return []
bitbucket_client = self._get_authorized_client()
repository = bitbucket_client.for_namespace(namespace).repositories().get(name)
if field_name == 'refs':
(result, data, _) = repository.get_branches_and_tags()
if not result:
return None
branches = [b['name'] for b in data['branches']]
tags = [t['name'] for t in data['tags']]
return ([{'kind': 'branch', 'name': b} for b in branches] +
[{'kind': 'tag', 'name': tag} for tag in tags])
if field_name == 'tag_name':
(result, data, _) = repository.get_tags()
if not result:
return None
return data.keys()
if field_name == 'branch_name':
(result, data, _) = repository.get_branches()
if not result:
return None
return data.keys()
return None
def handle_trigger_request(self, request):
return
def manual_start(self, run_parameters=None):
config = self.config
repository = self._get_repository_client()
source = config['build_source']
run_parameters = run_parameters or {}
# Lookup the branch to build.
master_branch = 'master'
(result, data, _) = repository.get_main_branch()
if result:
master_branch = data['name']
branch_name = run_parameters.get('branch_name') or master_branch
# Find the SHA for the branch.
# TODO
return None
class GithubBuildTrigger(BuildTriggerHandler):