Start refactoring of the trigger system:
- Move each trigger handler into its own file - Add dictionary helper classes for easier reading and writing of dict-based data - Extract the web hook payload -> internal representation building for each trigger system - Add tests for this transformation - Remove support for Github archived-based building
This commit is contained in:
parent
2ff77df946
commit
49b575afb6
25 changed files with 2449 additions and 1602 deletions
222
buildtrigger/basehandler.py
Normal file
222
buildtrigger/basehandler.py
Normal file
|
@ -0,0 +1,222 @@
|
|||
from endpoints.building import PreparedBuild
|
||||
from data import model
|
||||
from buildtrigger.triggerutil import get_trigger_config, InvalidServiceException
|
||||
from jsonschema import validate
|
||||
|
||||
METADATA_SCHEMA = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'commit': {
|
||||
'type': 'string',
|
||||
'description': 'first 7 characters of the SHA-1 identifier for a git commit',
|
||||
'pattern': '^([A-Fa-f0-9]{7,})$',
|
||||
},
|
||||
'git_url': {
|
||||
'type': 'string',
|
||||
'description': 'The GIT url to use for the checkout',
|
||||
},
|
||||
'ref': {
|
||||
'type': 'string',
|
||||
'description': 'git reference for a git commit',
|
||||
'pattern': '^refs\/(heads|tags|remotes)\/(.+)$',
|
||||
},
|
||||
'default_branch': {
|
||||
'type': 'string',
|
||||
'description': 'default branch of the git repository',
|
||||
},
|
||||
'commit_info': {
|
||||
'type': 'object',
|
||||
'description': 'metadata about a git commit',
|
||||
'properties': {
|
||||
'url': {
|
||||
'type': 'string',
|
||||
'description': 'URL to view a git commit',
|
||||
},
|
||||
'message': {
|
||||
'type': 'string',
|
||||
'description': 'git commit message',
|
||||
},
|
||||
'date': {
|
||||
'type': 'string',
|
||||
'description': 'timestamp for a git commit'
|
||||
},
|
||||
'author': {
|
||||
'type': 'object',
|
||||
'description': 'metadata about the author of a git commit',
|
||||
'properties': {
|
||||
'username': {
|
||||
'type': 'string',
|
||||
'description': 'username of the author',
|
||||
},
|
||||
'url': {
|
||||
'type': 'string',
|
||||
'description': 'URL to view the profile of the author',
|
||||
},
|
||||
'avatar_url': {
|
||||
'type': 'string',
|
||||
'description': 'URL to view the avatar of the author',
|
||||
},
|
||||
},
|
||||
'required': ['username'],
|
||||
},
|
||||
'committer': {
|
||||
'type': 'object',
|
||||
'description': 'metadata about the committer of a git commit',
|
||||
'properties': {
|
||||
'username': {
|
||||
'type': 'string',
|
||||
'description': 'username of the committer',
|
||||
},
|
||||
'url': {
|
||||
'type': 'string',
|
||||
'description': 'URL to view the profile of the committer',
|
||||
},
|
||||
'avatar_url': {
|
||||
'type': 'string',
|
||||
'description': 'URL to view the avatar of the committer',
|
||||
},
|
||||
},
|
||||
'required': ['username'],
|
||||
},
|
||||
},
|
||||
'required': ['url', 'message', 'date'],
|
||||
},
|
||||
},
|
||||
'required': ['commit', 'git_url'],
|
||||
}
|
||||
|
||||
|
||||
class BuildTriggerHandler(object):
|
||||
def __init__(self, trigger, override_config=None):
|
||||
self.trigger = trigger
|
||||
self.config = override_config or get_trigger_config(trigger)
|
||||
|
||||
@property
|
||||
def auth_token(self):
|
||||
""" Returns the auth token for the trigger. """
|
||||
return self.trigger.auth_token
|
||||
|
||||
def load_dockerfile_contents(self):
|
||||
"""
|
||||
Loads the Dockerfile found for the trigger's config and returns them or None if none could
|
||||
be found/loaded.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def list_build_sources(self):
|
||||
"""
|
||||
Take the auth information for the specific trigger type and load the
|
||||
list of build sources(repositories).
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def list_build_subdirs(self):
|
||||
"""
|
||||
Take the auth information and the specified config so far and list all of
|
||||
the possible subdirs containing dockerfiles.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def handle_trigger_request(self):
|
||||
"""
|
||||
Transform the incoming request data into a set of actions. Returns a PreparedBuild.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def is_active(self):
|
||||
"""
|
||||
Returns True if the current build trigger is active. Inactive means further
|
||||
setup is needed.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def activate(self, standard_webhook_url):
|
||||
"""
|
||||
Activates the trigger for the service, with the given new configuration.
|
||||
Returns new public and private config that should be stored if successful.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def deactivate(self):
|
||||
"""
|
||||
Deactivates the trigger for the service, removing any hooks installed in
|
||||
the remote service. Returns the new config that should be stored if this
|
||||
trigger is going to be re-activated.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def manual_start(self, run_parameters=None):
|
||||
"""
|
||||
Manually creates a repository build for this trigger. Returns a PreparedBuild.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def list_field_values(self, field_name, limit=None):
|
||||
"""
|
||||
Lists all values for the given custom trigger field. For example, a trigger might have a
|
||||
field named "branches", and this method would return all branches.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_repository_url(self):
|
||||
""" Returns the URL of the current trigger's repository. Note that this operation
|
||||
can be called in a loop, so it should be as fast as possible. """
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def service_name(cls):
|
||||
"""
|
||||
Particular service implemented by subclasses.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def get_handler(cls, trigger, override_config=None):
|
||||
for subc in cls.__subclasses__():
|
||||
if subc.service_name() == trigger.service.name:
|
||||
return subc(trigger, override_config)
|
||||
|
||||
raise InvalidServiceException('Unable to find service: %s' % trigger.service.name)
|
||||
|
||||
def put_config_key(self, key, value):
|
||||
""" Updates a config key in the trigger, saving it to the DB. """
|
||||
self.config[key] = value
|
||||
model.build.update_build_trigger(self.trigger, self.config)
|
||||
|
||||
def set_auth_token(self, auth_token):
|
||||
""" Sets the auth token for the trigger, saving it to the DB. """
|
||||
model.build.update_build_trigger(self.trigger, self.config, auth_token=auth_token)
|
||||
|
||||
def get_dockerfile_path(self):
|
||||
""" Returns the normalized path to the Dockerfile found in the subdirectory
|
||||
in the config. """
|
||||
subdirectory = self.config.get('subdir', '')
|
||||
if subdirectory == '/':
|
||||
subdirectory = ''
|
||||
else:
|
||||
if not subdirectory.endswith('/'):
|
||||
subdirectory = subdirectory + '/'
|
||||
|
||||
return subdirectory + 'Dockerfile'
|
||||
|
||||
def prepare_build(self, metadata, is_manual=False):
|
||||
# Ensure that the metadata meets the scheme.
|
||||
validate(metadata, METADATA_SCHEMA)
|
||||
|
||||
config = self.config
|
||||
ref = metadata.get('ref', None)
|
||||
commit_sha = metadata['commit']
|
||||
default_branch = metadata.get('default_branch', None)
|
||||
|
||||
prepared = PreparedBuild(self.trigger)
|
||||
prepared.name_from_sha(commit_sha)
|
||||
prepared.subdirectory = config.get('subdir', None)
|
||||
prepared.is_manual = is_manual
|
||||
prepared.metadata = metadata
|
||||
|
||||
if ref is not None:
|
||||
prepared.tags_from_ref(ref, default_branch)
|
||||
else:
|
||||
prepared.tags = [commit_sha[:7]]
|
||||
|
||||
return prepared
|
Reference in a new issue