예제 #1
0
class GitHubRepository:
    """Wrapper around GitHub API. Used to access public data."""
    def __init__(self, owner, repo_name, token=""):
        """Build the GitHub API URL which points to the definition of the repository.

        Args:
            owner (str): the owner's GitHub username
            repo_name (str): the name of the repository
            token (str): the GitHub API token

        Returns:
            dict: a representation of the repo definition

        """
        self._github_repository = GitHub(token=token).repository(
            owner, repo_name)

    @property
    def definition(self):
        """Fetch the definition of the repository, exposed by the GitHub API.

        Returns:
            dict: a representation of the repo definition

        """
        return self._github_repository.as_dict()

    @retry_async_decorator(retry_exceptions=GitHubException)
    async def get_commit(self, commit_hash):
        """Fetch the definition of the commit, exposed by the GitHub API.

        Args:
            commit_hash (str): the hash of the git commit

        Returns:
            dict: a representation of the commit

        """
        return self._github_repository.commit(commit_hash).as_dict()

    @retry_async_decorator(retry_exceptions=GitHubException)
    async def get_pull_request(self, pull_request_number):
        """Fetch the definition of the pull request, exposed by the GitHub API.

        Args:
            pull_request_number (int): the ID of the pull request

        Returns:
            dict: a representation of the pull request

        """
        return self._github_repository.pull_request(
            pull_request_number).as_dict()

    @retry_async_decorator(retry_exceptions=GitHubException)
    async def get_release(self, tag_name):
        """Fetch the definition of the release matching the tag name.

        Args:
            tag_name (str): the tag linked to the release

        Returns:
            dict: a representation of the tag

        """
        return self._github_repository.release_from_tag(tag_name).as_dict()

    @retry_async_decorator(retry_exceptions=GitHubException)
    async def get_tag_hash(self, tag_name):
        """Fetch the commit hash that was tagged with ``tag_name``.

        Args:
            tag_name (str): the name of the tag

        Returns:
            str: the commit hash linked by the tag

        """
        tag_object = get_single_item_from_sequence(
            sequence=self._github_repository.tags(),
            condition=lambda tag: tag.name == tag_name,
            no_item_error_message='No tag "{}" exist'.format(tag_name),
            too_many_item_error_message='Too many tags "{}" found'.format(
                tag_name),
        )

        return tag_object.commit.sha

    async def has_commit_landed_on_repository(self, context, revision):
        """Tell if a commit was landed on the repository or if it just comes from a pull request.

        Args:
            context (scriptworker.context.Context): the scriptworker context.
            revision (str): the commit hash or the tag name.

        Returns:
            bool: True if the commit is present in one of the branches of the main repository

        """
        if any(
                vcs_rule.get("require_secret")
                for vcs_rule in context.config["trusted_vcs_rules"]):
            # This check uses unofficial API on github, which we can't easily
            # check for private repos, assume its true in the private case.
            log.info(
                "has_commit_landed_on_repository() not implemented for private"
                "repositories, assume True")
            return True

        # Revision may be a tag name. `branch_commits` doesn't work on tags
        if not _is_git_full_hash(revision):
            revision = await self.get_tag_hash(tag_name=revision)

        html_text = await _fetch_github_branch_commits_data(
            context, self._github_repository.html_url, revision)

        # https://github.com/{repo_owner}/{repo_name}/branch_commits/{revision} just returns some \n
        # when the commit hasn't landed on the origin repo. Otherwise, some HTML data is returned - it
        # represents the branches on which the given revision is present.
        return html_text != ""
예제 #2
0
class GitHubRepository():
    """Wrapper around GitHub API. Used to access public data."""

    def __init__(self, owner, repo_name, token=''):
        """Build the GitHub API URL which points to the definition of the repository.

        Args:
            owner (str): the owner's GitHub username
            repo_name (str): the name of the repository
            token (str): the GitHub API token

        Returns:
            dict: a representation of the repo definition

        """
        self._github_repository = GitHub(token=token).repository(owner, repo_name)

    @property
    def definition(self):
        """Fetch the definition of the repository, exposed by the GitHub API.

        Returns:
            dict: a representation of the repo definition

        """
        return self._github_repository.as_dict()

    def get_commit(self, commit_hash):
        """Fetch the definition of the commit, exposed by the GitHub API.

        Args:
            commit_hash (str): the hash of the git commit

        Returns:
            dict: a representation of the commit

        """
        return self._github_repository.commit(commit_hash).as_dict()

    def get_pull_request(self, pull_request_number):
        """Fetch the definition of the pull request, exposed by the GitHub API.

        Args:
            pull_request_number (int): the ID of the pull request

        Returns:
            dict: a representation of the pull request

        """
        return self._github_repository.pull_request(pull_request_number).as_dict()

    def get_release(self, tag_name):
        """Fetch the definition of the release matching the tag name.

        Args:
            tag_name (str): the tag linked to the release

        Returns:
            dict: a representation of the tag

        """
        return self._github_repository.release_from_tag(tag_name).as_dict()

    def get_tag_hash(self, tag_name):
        """Fetch the commit hash that was tagged with ``tag_name``.

        Args:
            tag_name (str): the name of the tag

        Returns:
            str: the commit hash linked by the tag

        """
        tag_object = get_single_item_from_sequence(
            sequence=self._github_repository.tags(),
            condition=lambda tag: tag.name == tag_name,
            no_item_error_message='No tag "{}" exist'.format(tag_name),
            too_many_item_error_message='Too many tags "{}" found'.format(tag_name),
        )

        return tag_object.commit.sha

    async def has_commit_landed_on_repository(self, context, revision):
        """Tell if a commit was landed on the repository or if it just comes from a pull request.

        Args:
            context (scriptworker.context.Context): the scriptworker context.
            revision (str): the commit hash or the tag name.

        Returns:
            bool: True if the commit is present in one of the branches of the main repository

        """
        # Revision may be a tag name. `branch_commits` doesn't work on tags
        if not _is_git_full_hash(revision):
            revision = self.get_tag_hash(tag_name=revision)

        repo = self._github_repository.html_url

        url = '/'.join([repo.rstrip('/'), 'branch_commits', revision])
        html_data = await retry_request(context, url)
        html_text = html_data.strip()
        # https://github.com/{repo_owner}/{repo_name}/branch_commits/{revision} just returns some \n
        # when the commit hasn't landed on the origin repo. Otherwise, some HTML data is returned - it
        # represents the branches on which the given revision is present.
        return html_text != ''
예제 #3
0
class GitHubRepository():
    """Wrapper around GitHub API. Used to access public data."""
    def __init__(self, owner, repo_name, token=''):
        """Build the GitHub API URL which points to the definition of the repository.

        Args:
            owner (str): the owner's GitHub username
            repo_name (str): the name of the repository
            token (str): the GitHub API token

        Returns:
            dict: a representation of the repo definition

        """
        self._github_repository = GitHub(token=token).repository(
            owner, repo_name)

    @property
    def definition(self):
        """Fetch the definition of the repository, exposed by the GitHub API.

        Returns:
            dict: a representation of the repo definition

        """
        return self._github_repository.as_dict()

    def get_commit(self, commit_hash):
        """Fetch the definition of the commit, exposed by the GitHub API.

        Args:
            commit_hash (str): the hash of the git commit

        Returns:
            dict: a representation of the commit

        """
        return self._github_repository.commit(commit_hash).as_dict()

    def get_pull_request(self, pull_request_number):
        """Fetch the definition of the pull request, exposed by the GitHub API.

        Args:
            pull_request_number (int): the ID of the pull request

        Returns:
            dict: a representation of the pull request

        """
        return self._github_repository.pull_request(
            pull_request_number).as_dict()

    def get_release(self, tag_name):
        """Fetch the definition of the release matching the tag name.

        Args:
            tag_name (str): the tag linked to the release

        Returns:
            dict: a representation of the tag

        """
        return self._github_repository.release_from_tag(tag_name).as_dict()

    def get_tag_hash(self, tag_name):
        """Fetch the commit hash that was tagged with ``tag_name``.

        Args:
            tag_name (str): the name of the tag

        Returns:
            str: the commit hash linked by the tag

        """
        tag_object = get_single_item_from_sequence(
            sequence=self._github_repository.tags(),
            condition=lambda tag: tag.name == tag_name,
            no_item_error_message='No tag "{}" exist'.format(tag_name),
            too_many_item_error_message='Too many tags "{}" found'.format(
                tag_name),
        )

        return tag_object.commit.sha

    async def has_commit_landed_on_repository(self, context, revision):
        """Tell if a commit was landed on the repository or if it just comes from a pull request.

        Args:
            context (scriptworker.context.Context): the scriptworker context.
            revision (str): the commit hash or the tag name.

        Returns:
            bool: True if the commit is present in one of the branches of the main repository

        """
        # Revision may be a tag name. `branch_commits` doesn't work on tags
        if not _is_git_full_hash(revision):
            revision = self.get_tag_hash(tag_name=revision)

        repo = self._github_repository.html_url

        url = '/'.join([repo.rstrip('/'), 'branch_commits', revision])
        from scriptworker.task import get_decision_task_id
        cache_key = '{}-{}'.format(get_decision_task_id(context.task), url)
        async with _branch_commits_cache_lock:
            if cache_key in _branch_commits_cache:
                html_text = _branch_commits_cache[cache_key]
            else:
                html_data = await retry_request(context, url)
                html_text = html_data.strip()
                _branch_commits_cache[cache_key] = html_text
        # https://github.com/{repo_owner}/{repo_name}/branch_commits/{revision} just returns some \n
        # when the commit hasn't landed on the origin repo. Otherwise, some HTML data is returned - it
        # represents the branches on which the given revision is present.
        return html_text != ''