#!/usr/bin/python3 # INTEL CONFIDENTIAL # Copyright 2018-2020 Intel Corporation # The source code contained or described herein and all documents related to the # source code ("Material") are owned by Intel Corporation or its suppliers or # licensors. Title to the Material remains with Intel Corporation or its # suppliers and licensors. The Material may contain trade secrets and proprietary # and confidential information of Intel Corporation and its suppliers and # licensors, and is protected by worldwide copyright and trade secret laws and # treaty provisions. No part of the Material may be used, copied, reproduced, # modified, published, uploaded, posted, transmitted, distributed, or disclosed # in any way without Intel's prior express written permission. # No license under any patent, copyright, trade secret or other intellectual # property right is granted to or conferred upon you by disclosure or delivery of # the Materials, either expressly, by implication, inducement, estoppel or # otherwise. Any license under such intellectual property rights must be express # and approved by Intel in writing. # Include any supplier copyright notices as supplier requires Intel to use. # Include supplier trademarks or logos as supplier requires Intel to use, # preceded by an asterisk. An asterisked footnote can be added as follows: # *Third Party trademarks are the property of their respective owners. # Unless otherwise agreed by Intel in writing, you may not remove or alter # this notice or any other notice embedded in Materials by Intel or Intel's # suppliers or licensors in any way. import logging import timeout_decorator from datetime import datetime from retrying import retry from github import Github, GithubException # Logging logging.basicConfig(format='%(name)s - %(levelname)s - %(message)s') log = logging.getLogger(__name__) log.setLevel(logging.INFO) _RETRY_LIMIT = 3 _RETRY_COOLDOWN_MS = 2000 _REQUEST_TIMEOUT_S = 10 class GitWrapper: """Class wrapping PyGithub API. The purpose of this class is to wrap methods from PyGithub API used in Watchdog, for less error-prone and more convenient use. Docs for used API, including wrapped methods can be found at: https://pygithub.readthedocs.io/en/latest/introduction.html :param git_token: Token used for GitHub :param repository: GitHub repository name :param project: GitHub project name :type git_token: String :type repository: String :type project: String """ def __init__(self, git_token, repository, project): self.git = Github(git_token) self.repository = repository self.project = project @retry(stop_max_attempt_number=_RETRY_LIMIT, wait_fixed=_RETRY_COOLDOWN_MS) def get_git_time(self): """Retrieve time from GitHub. Used to reliably determine time during Watchdog run. :return: Datetime object describing current time :rtype: datetime """ try: datetime_object = self._get_git_time() except ValueError as e: raise GitWrapperError(str(e)) except GithubException as e: message = 'GitHub Exception during API status retrieval. Exception: {}'.format(str(e)) raise GitWrapperError(message) except timeout_decorator.TimeoutError: message = 'GitHub Exception during API status retrieval. Timeout during API request.' raise GitWrapperError(message) return datetime_object @retry(stop_max_attempt_number=_RETRY_LIMIT, wait_fixed=_RETRY_COOLDOWN_MS) def get_pull_requests(self): """Retrieve paginated list of pull requests from GitHub. :return: Paginated list of Pull Requests in GitHub repo :rtype: github.PaginatedList.PaginatedList of github.PullRequest.PullRequest """ try: prs = self._get_pull_requests() except GithubException as e: message = 'GitHub Exception during API status retrieval. Exception: {}'.format(str(e)) raise GitWrapperError(message) return prs @timeout_decorator.timeout(_REQUEST_TIMEOUT_S) def _get_git_time(self): """Private method retrieving time from GitHub. :return: Datetime object describing current time :rtype: datetime """ datetime_string = self.git.get_api_status().raw_headers.get('date', '') datetime_format = '%a, %d %b %Y %H:%M:%S %Z' datetime_object = datetime.strptime(datetime_string, datetime_format) return datetime_object @timeout_decorator.timeout(_REQUEST_TIMEOUT_S) def _get_pull_requests(self): """Private method retrieving pull requests from GitHub. :return: Paginated list of Pull Requests in GitHub repo :rtype: github.PaginatedList.PaginatedList of github.PullRequest.PullRequest """ return self.git.get_organization(self.repository).get_repo(self.project).get_pulls() class GitWrapperError(Exception): """Base class for exceptions raised in GitWrapper. :param message Explanation of the error """ def __init__(self, message): self.message = message log.exception(message)