Merge pull request #1092 from jzelinskie/gitlab

Allow for custom Gitlab host
This commit is contained in:
Jimmy Zelinskie 2016-03-18 15:10:18 -04:00
commit 408ac90346
6 changed files with 62 additions and 38 deletions

View file

@ -1,8 +1,9 @@
import logging
from functools import wraps
from urlparse import urljoin
from app import app
from app import app, gitlab_trigger
from jsonschema import validate
from buildtrigger.triggerutil import (RepositoryReadException, TriggerActivationException,
@ -127,9 +128,8 @@ class GitLabBuildTrigger(BuildTriggerHandler):
return 'gitlab'
def _get_authorized_client(self):
host = app.config.get('GITLAB_TRIGGER_CONFIG', {}).get('GITLAB_ENDPOINT', '')
auth_token = self.auth_token or 'invalid'
return gitlab.Gitlab(host, oauth_token=auth_token, timeout=5)
return gitlab.Gitlab(gitlab_trigger.api_endpoint(), oauth_token=auth_token, timeout=5)
def is_active(self):
return 'hook_id' in self.config
@ -318,7 +318,7 @@ class GitLabBuildTrigger(BuildTriggerHandler):
return None
def get_repository_url(self):
return 'https://gitlab.com/%s' % self.config['build_source']
return gitlab_trigger.get_public_url(self.config['build_source'])
@_catch_timeouts
def lookup_user(self, email):

View file

@ -116,6 +116,9 @@ class DefaultConfig(object):
# Bitbucket Config.
BITBUCKET_TRIGGER_CONFIG = None
# Gitlab Config.
GITLAB_TRIGGER_CONFIG = None
# Requests based HTTP client with a large request pool
HTTPCLIENT = build_requests_session()

View file

@ -6,6 +6,7 @@ from semantic_version import Version, Spec
from util.validation import generate_valid_usernames
from util.registry.generatorfile import GeneratorFile
from util.registry.dockerver import docker_version
from util.string import slash_join
class TestGeneratorFile(unittest.TestCase):
def sample_generator(self):
@ -174,6 +175,21 @@ class TestDockerVersionParsing(unittest.TestCase):
self.assertTrue(spec.match(Version(match_case)),
'Spec: %s Case: %s' % (spec, match_case))
class TestSlashJoining(unittest.TestCase):
def test_joining(self):
test_cases = [
(['https://github.com', '/coreos-inc/' 'quay/pull/1092/files'],
'https://github.com/coreos-inc/quay/pull/1092/files'),
(['https://', 'github.com/', '/coreos-inc', '/quay/pull/1092/files/'],
'https://github.com/coreos-inc/quay/pull/1092/files'),
]
for args, url in test_cases:
joined_url = slash_join(*args)
self.assertEquals(url, joined_url)
if __name__ == '__main__':
unittest.main()

View file

@ -1,3 +1,18 @@
def get_app_url(config):
""" Returns the application's URL, based on the given config. """
return '%s://%s' % (config['PREFERRED_URL_SCHEME'], config['SERVER_HOSTNAME'])
def slash_join(*args):
"""
Joins together strings and guarantees there is only one '/' in between the
each string joined. Double slashes ('//') are assumed to be intentional and
are not deduplicated.
"""
def rmslash(path):
path = path[1:] if path[0] == '/' else path
path = path[:-1] if path[-1] == '/' else path
return path
args = [rmslash(path) for path in args]
return '/'.join(args)

View file

@ -5,6 +5,7 @@ import time
from cachetools import TTLCache
from jwkest.jwk import KEYS
from util import slash_join
logger = logging.getLogger(__name__)
@ -31,12 +32,6 @@ class OAuthConfig(object):
def client_secret(self):
return self.config.get('CLIENT_SECRET')
def _get_url(self, endpoint, *args):
for arg in args:
endpoint = urlparse.urljoin(endpoint, arg)
return endpoint
def get_redirect_uri(self, app_config, redirect_suffix=''):
return '%s://%s/oauth2/%s/callback%s' % (app_config['PREFERRED_URL_SCHEME'],
app_config['SERVER_HOSTNAME'],
@ -95,40 +90,34 @@ class GithubOAuthConfig(OAuthConfig):
return [org.lower() for org in allowed]
def get_public_url(self, suffix):
return '%s%s' % (self._endpoint(), suffix)
return slash_join(self._endpoint(), suffix)
def _endpoint(self):
endpoint = self.config.get('GITHUB_ENDPOINT', 'https://github.com')
if not endpoint.endswith('/'):
endpoint = endpoint + '/'
return endpoint
return self.config.get('GITHUB_ENDPOINT', 'https://github.com')
def is_enterprise(self):
return self._endpoint().find('.github.com') < 0
def authorize_endpoint(self):
return self._get_url(self._endpoint(), '/login/oauth/authorize') + '?'
return slash_join(self._endpoint(), '/login/oauth/authorize') + '?'
def token_endpoint(self):
return self._get_url(self._endpoint(), '/login/oauth/access_token')
return slash_join(self._endpoint(), '/login/oauth/access_token')
def _api_endpoint(self):
return self.config.get('API_ENDPOINT', self._get_url(self._endpoint(), '/api/v3/'))
return self.config.get('API_ENDPOINT', slash_join(self._endpoint(), '/api/v3/'))
def api_endpoint(self):
return self._api_endpoint()[0:-1]
def user_endpoint(self):
api_endpoint = self._api_endpoint()
return self._get_url(api_endpoint, 'user')
return slash_join(self._api_endpoint(), 'user')
def email_endpoint(self):
api_endpoint = self._api_endpoint()
return self._get_url(api_endpoint, 'user/emails')
return slash_join(self._api_endpoint(), 'user/emails')
def orgs_endpoint(self):
api_endpoint = self._api_endpoint()
return self._get_url(api_endpoint, 'user/orgs')
return slash_join(self._api_endpoint(), 'user/orgs')
def validate_client_id_and_secret(self, http_client, app_config):
# First: Verify that the github endpoint is actually Github by checking for the
@ -150,18 +139,17 @@ class GithubOAuthConfig(OAuthConfig):
# password:
# - If the {client_id, client_secret} pair is invalid in some way, we get a 401 error.
# - If the pair is valid, then we get a 404 because the 'foo' token does not exists.
validate_endpoint = self._get_url(api_endpoint, 'applications/%s/tokens/foo' % self.client_id())
validate_endpoint = slash_join(api_endpoint, 'applications/%s/tokens/foo' % self.client_id())
result = http_client.get(validate_endpoint, auth=(self.client_id(), self.client_secret()),
timeout=5)
timeout=5)
return result.status_code == 404
def validate_organization(self, organization_id, http_client):
api_endpoint = self._api_endpoint()
org_endpoint = self._get_url(api_endpoint, 'orgs/%s' % organization_id.lower())
org_endpoint = slash_join(self._api_endpoint(), 'orgs/%s' % organization_id.lower())
result = http_client.get(org_endpoint,
headers={'Accept': 'application/vnd.github.moondragon+json'},
timeout=5)
headers={'Accept': 'application/vnd.github.moondragon+json'},
timeout=5)
return result.status_code == 200
@ -221,19 +209,22 @@ class GitLabOAuthConfig(OAuthConfig):
super(GitLabOAuthConfig, self).__init__(config, key_name)
def _endpoint(self):
endpoint = self.config.get('GITLAB_ENDPOINT', 'https://gitlab.com')
if not endpoint.endswith('/'):
endpoint = endpoint + '/'
return endpoint
return self.config.get('GITLAB_ENDPOINT', 'https://gitlab.com')
def api_endpoint(self):
return self._endpoint()
def get_public_url(self, suffix):
return slash_join(self._endpoint(), suffix)
def service_name(self):
return 'GitLab'
def authorize_endpoint(self):
return self._get_url(self._endpoint(), '/oauth/authorize')
return slash_join(self._endpoint(), '/oauth/authorize')
def token_endpoint(self):
return self._get_url(self._endpoint(), '/oauth/token')
return slash_join(self._endpoint(), '/oauth/token')
def validate_client_id_and_secret(self, http_client, app_config):
url = self.token_endpoint()

View file

@ -1,6 +1,5 @@
import re
import string
import anunidecode
import re
INVALID_PASSWORD_MESSAGE = 'Invalid password, password must be at least ' + \