diff options
author | Oliver Poignant <oliver@poignant.se> | 2017-01-08 17:15:58 +0100 |
---|---|---|
committer | Oliver Poignant <oliver@poignant.se> | 2017-01-08 17:15:58 +0100 |
commit | 465cb9263fb1ffc9ba2d4a912847322920180caa (patch) | |
tree | 59932075b5f6426088704abac7c53f8c476da2a4 /gitautodeploy/webhook.py | |
parent | 324c3518d4b98da5bb660c62fa1503c47139c088 (diff) | |
download | Git-Auto-Deploy-master.zip Git-Auto-Deploy-master.tar.gz Git-Auto-Deploy-master.tar.bz2 |
RefactoringHEADorigin/masterorigin/HEADmaster
Diffstat (limited to 'gitautodeploy/webhook.py')
-rw-r--r-- | gitautodeploy/webhook.py | 248 |
1 files changed, 0 insertions, 248 deletions
diff --git a/gitautodeploy/webhook.py b/gitautodeploy/webhook.py deleted file mode 100644 index 752717e..0000000 --- a/gitautodeploy/webhook.py +++ /dev/null @@ -1,248 +0,0 @@ -from .parsers import CodingRequestParser, GitLabCIRequestParser -from .parsers import GitLabRequestParser, GitHubRequestParser -from .parsers import BitBucketRequestParser, GenericRequestParser - - -class WebbhookRequestProcessor(object): - - def get_service_handler(self, request_headers, request_body, action): - """Parses the incoming request and attempts to determine whether - it originates from GitHub, GitLab or any other known service.""" - import json - - payload = json.loads(request_body) - - if not isinstance(payload, dict): - raise ValueError("Invalid JSON object") - - user_agent = 'user-agent' in request_headers and request_headers['user-agent'] - content_type = 'content-type' in request_headers and request_headers['content-type'] - - # Assume Coding if the X-Coding-Event HTTP header is set - if 'x-coding-event' in request_headers: - return CodingRequestParser - - # Assume GitLab if the X-Gitlab-Event HTTP header is set - elif 'x-gitlab-event' in request_headers: - - # Special Case for Gitlab CI - if content_type == "application/json" and "build_status" in payload: - return GitLabCIRequestParser - else: - return GitLabRequestParser - - # Assume GitHub if the X-GitHub-Event HTTP header is set - elif 'x-github-event' in request_headers: - - return GitHubRequestParser - - # Assume BitBucket if the User-Agent HTTP header is set to - # 'Bitbucket-Webhooks/2.0' (or something similar) - elif user_agent and user_agent.lower().find('bitbucket') != -1: - - return BitBucketRequestParser - - # This handles old GitLab requests and Gogs requests for example. - elif content_type == "application/json": - - action.log_info("Received event from unknown origin.") - return GenericRequestParser - - action.log_error("Unable to recognize request origin. Don't know how to handle the request.") - return - - def execute_webhook(self, repo_config, event_store): - """Verify that the suggested repositories has matching settings and - issue git pull and/or deploy commands.""" - import os - import time - from .wrappers import GitWrapper - from .events import DeployEvent - from .lock import Lock - import json - - event = DeployEvent(repo_config) - event_store.register_action(event) - event.set_waiting(True) - event.log_info("Running deploy commands") - - # In case there is no path configured for the repository, no pull will - # be made. - if 'path' not in repo_config: - res = GitWrapper.deploy(repo_config) - event.log_info("%s" % res) - event.set_waiting(False) - event.set_success(True) - return - - # If the path does not exist, a warning will be raised and no pull or - # deploy will be made. - if not os.path.isdir(repo_config['path']): - event.log_error("The repository '%s' does not exist locally. Make sure it was pulled properly without errors by reviewing the log." % repo_config['path']) - event.set_waiting(False) - event.set_success(False) - return - - # If the path is not writable, a warning will be raised and no pull or - # deploy will be made. - if not os.access(repo_config['path'], os.W_OK): - event.log_error("The path '%s' is not writable. Make sure that GAD has write access to that path." % repo_config['path']) - event.set_waiting(False) - event.set_success(False) - return - - running_lock = Lock(os.path.join(repo_config['path'], 'status_running')) - waiting_lock = Lock(os.path.join(repo_config['path'], 'status_waiting')) - try: - - # Attempt to obtain the status_running lock - while not running_lock.obtain(): - - # If we're unable, try once to obtain the status_waiting lock - if not waiting_lock.has_lock() and not waiting_lock.obtain(): - event.log_error("Unable to obtain the status_running lock nor the status_waiting lock. Another process is already waiting, so we'll ignore the request.") - - # If we're unable to obtain the waiting lock, ignore the request - break - - # Keep on attempting to obtain the status_running lock until we succeed - time.sleep(5) - - n = 4 - res = None - while n > 0: - - # Attempt to pull up a maximum of 4 times - res = GitWrapper.pull(repo_config) - - # Return code indicating success? - if res == 0: - break - - n -= 1 - - if 0 < n: - res = GitWrapper.deploy(repo_config) - - #except Exception as e: - # logger.error('Error during \'pull\' or \'deploy\' operation on path: %s' % repo_config['path']) - # logger.error(e) - # raise e - - finally: - - # Release the lock if it's ours - if running_lock.has_lock(): - running_lock.release() - - # Release the lock if it's ours - if waiting_lock.has_lock(): - waiting_lock.release() - - event.log_info("Deploy commands were executed") - event.set_waiting(False) - event.set_success(True) - - -class WebhookRequestFilter(object): - - def passes_payload_filter(self, payload_filters, payload, action): - import logging - - logger = logging.getLogger() - - # At least one filter must match - for filter in payload_filters: - - # All options specified in the filter must match - for filter_key, filter_value in filter.items(): - - # Ignore filters with value None (let them pass) - if filter_value == None: - continue - - # Interpret dots in filter name as path notations - node_value = payload - for node_key in filter_key.split('.'): - - # If the path is not valid the filter does not match - if not node_key in node_value: - action.log_info("Filter '%s' does not match since the path is invalid" % (filter_key)) - - # Filter does not match, do not process this repo config - return False - - node_value = node_value[node_key] - - if filter_value == node_value: - continue - - # If the filter value is set to True. the filter - # will pass regardless of the actual value - if filter_value == True: - continue - - action.log_debug("Filter '%s' does not match ('%s' != '%s')" % (filter_key, filter_value, (str(node_value)[:75] + '..') if len(str(node_value)) > 75 else str(node_value))) - - # Filter does not match, do not process this repo config - return False - - # Filter does match, proceed - return True - - def passes_header_filter(self, header_filter, request_headers): - import logging - - logger = logging.getLogger() - - # At least one filter must match - for key in header_filter: - - # Verify that the request has the required header attribute - if key.lower() not in request_headers: - return False - - # "True" indicates that any header value is accepted - if header_filter[key] is True: - continue - - # Verify that the request has the required header value - if header_filter[key] != request_headers[key.lower()]: - return False - - # Filter does match, proceed - return True - - def apply_filters(self, repo_configs, request_headers, request_body, action): - """Verify that the suggested repositories has matching settings and - issue git pull and/or deploy commands.""" - import os - import time - import logging - from .wrappers import GitWrapper - from .lock import Lock - import json - - logger = logging.getLogger() - payload = json.loads(request_body) - - matches = [] - - # Process each matching repository - for repo_config in repo_configs: - - # Verify that all payload filters matches the request (if any payload filters are specified) - if 'payload-filter' in repo_config and not self.passes_payload_filter(repo_config['payload-filter'], payload, action): - - # Filter does not match, do not process this repo config - continue - - # Verify that all header filters matches the request (if any header filters are specified) - if 'header-filter' in repo_config and not self.passes_header_filter(repo_config['header-filter'], request_headers): - - # Filter does not match, do not process this repo config - continue - - matches.append(repo_config) - - return matches
\ No newline at end of file |