Beispiel #1
0
    def billable_users(self) -> int:
        """
        Number of paying/registered users on the organization.
        """
        try:
            # If the org is a user, this'll throw RuntimeError
            users = {
                user['username']
                for user in get(self._token, self._url + '/members')
            }

            for group in get(self._token, '/groups'):
                gname = group['full_path']
                if (gname in self.name or self.name in gname) \
                        and self.name != gname:
                    users |= {
                        user['username']
                        for user in get(
                            self._token, '/groups/{name}/members'.format(
                                name=quote_plus(gname)))
                    }

            return len(users)
        except RuntimeError:
            return 1
Beispiel #2
0
    def diffstat(self):
        """
        Gets additions and deletions of a merge request.

        >>> from os import environ
        >>> pr = GitLabMergeRequest(
        ...     GitLabOAuthToken(environ['GITLAB_TEST_TOKEN']),
        ...     'gitmate-test-user/test', 2
        ... )
        >>> pr.diffstat
        (2, 0)

        :return: An (additions, deletions) tuple.
        """
        changes = get(self._token, self._url + '/changes')['changes']
        results = []
        expr = re.compile(r'@@ [0-9+,-]+ [0-9+,-]+ @@')
        for change in changes:
            diff = change['diff']
            match = expr.search(diff)
            if not match:  # for binary files match is None
                continue
            start_index = match.end()
            results += diff[start_index:].split('\n')

        additions = len([line for line in results if line.startswith('+')])
        deletions = len([line for line in results if line.startswith('-')])

        return additions, deletions
Beispiel #3
0
 def unified_diff(self):
     """
     Retrieves the unified diff for the commit excluding the diff index.
     """
     return '\n'.join(patch['diff']
                      for patch in get(self._token, self._url + '/diff')
                     )
Beispiel #4
0
    def get_patch_for_file(self, filename: str):
        r"""
        Retrieves the unified diff for the commit.

        >>> from os import environ
        >>> commit = GitLabCommit(
        ...     GitLabOAuthToken(environ['GITLAB_TEST_TOKEN']),
        ...     'gitmate-test-user/test', '3fc4b86'
        ... )
        >>> assert (commit.get_patch_for_file('README.md') ==
        ...         '--- a/README.md\n+++ b/README.md\n@@ -1,2 +1,4 @@\n '
        ...         '# test\n a test repo\n+\n+a tst pr\n')

        But only if it exists!

        >>> commit.get_patch_for_file('IDONTEXISTFILE')
        Traceback (most recent call last):
         ...
        IGitt.ElementDoesntExistError: The file does not exist.

        :param filename: The file to retrieve patch for.
        :return: A string containing the patch.
        :raises ElementDoesntExistError: If the given filename does not exist.
        """
        diff = get(self._token, self._url + '/diff')

        for patch in diff:
            if filename in (patch['new_path'], patch['old_path']):
                return patch['diff']

        raise ElementDoesntExistError('The file does not exist.')
Beispiel #5
0
 def _search(self, search_type, state: Union[MergeRequestStates,
                                             IssueStates, None]):
     """
     Retrives a list of all issues or merge requests.
     :param search_type: A string for type of object i.e. issues for issue
                         and merge_requests for merge requests.
     :param state: A string for MR/issue state (opened or closed)
     :return: List of issues/merge requests.
     """
     url = self._url + '/{}'.format(search_type)
     if state is None:
         return get(self._token, url)
     elif isinstance(state, IssueStates):
         state = GL_ISSUE_STATE_TRANSLATION[state]
     elif isinstance(state, MergeRequestStates):
         state = GL_MR_STATE_TRANSLATION[state]
     return get(self._token, url, {'state': state})
Beispiel #6
0
 def suborgs(self) -> Set[Organization]:
     """
     Returns the sub-organizations within this organization, recursively.
     """
     result = set()
     for suborg_data in get(self._token, self._url + '/subgroups'):
         suborg = GitLabOrganization.from_data(suborg_data, self._token,
                                               suborg_data['full_path'])
         result |= {suborg} | suborg.suborgs
     return result
Beispiel #7
0
    def hooks(self) -> Set[str]:
        """
        Retrieves all URLs this repository is hooked to.

        :return: Set of URLs (str).
        """
        hook_url = self._url + '/hooks'
        hooks = get(self._token, hook_url)

        return {hook['url'] for hook in hooks}
Beispiel #8
0
 def reactions(self) -> Set[GitLabReaction]:
     """
     Retrieves the reactions / award emojis applied on the issue.
     """
     url = self._url + '/award_emoji'
     reactions = get(self._token, url)
     return {
         GitLabReaction.from_data(r, self._token, self, r['id'])
         for r in reactions
     }
Beispiel #9
0
 def master_repositories(self):
     """
     Retrieves repositories the user has admin access to.
     """
     repo_list = get(self._token, '/projects', {'membership': True})
     return {
         GitLabRepository.from_data(repo, self._token,
                                    repo['path_with_namespace'])
         for repo in self._get_repos_with_permissions(
             repo_list, AccessLevel.ADMIN)
     }
Beispiel #10
0
    def filter_issues(self, state: str = 'opened') -> set:
        """
        Filters the issues from the repository based on properties.

        :param state: 'opened' or 'closed' or 'all'.
        """
        return {
            GitLabIssue.from_data(res, self._token, self.full_name, res['iid'])
            for res in get(self._token, self._url +
                           '/issues', {'state': state})
        }
Beispiel #11
0
 def get_permission_level(self, user) -> AccessLevel:
     """
     Retrieves the permission level for the specified user on this
     repository.
     """
     members = get(self._token, self._url + '/members')
     if user.username not in map(lambda m: m['username'], members):
         return (AccessLevel.CAN_VIEW if
                 self.data['visibility'] != 'private' else AccessLevel.NONE)
     curr_member_idx = next(i for (i, d) in enumerate(members)
                            if d['username'] == user.username)
     return AccessLevel(members[curr_member_idx]['access_level'])
Beispiel #12
0
    def repositories(self) -> Set[Repository]:
        """
        Returns the list of repositories contained in this organization
        including subgroup repositories, recursively.
        """
        from IGitt.GitLab.GitLabRepository import GitLabRepository

        return {
            GitLabRepository.from_data(repo, self._token, repo['id'])
            for repo in get(self._token, self._url + '/projects')
        }.union({repo
                 for org in self.suborgs for repo in org.repositories})
Beispiel #13
0
    def raw_members(self) -> list:
        """
        Gets all members including the ones of groups around subgroups as a
        list of dicts from the JSON responses.
        """
        members = list(get(self._token, self._url + '/members'))
        if '/' in self.name:
            members.extend(
                GitLabOrganization(self._token,
                                   self.name.rsplit(
                                       '/', maxsplit=1)[0]).raw_members())

        return members
Beispiel #14
0
    def delete_hook(self, url: str):
        """
        Deletes all webhooks to the given URL.

        :param url: The URL to not fire the webhook to anymore.
        :raises RuntimeError: If something goes wrong (network, auth...).
        """
        hook_url = self._url + '/hooks'
        hooks = get(self._token, hook_url)

        # Do not use self.hooks since id of the hook is needed
        for hook in hooks:
            if hook['url'] == url:
                delete(self._token, hook_url + '/' + str(hook['id']))
Beispiel #15
0
    def commits(self):
        """
        Retrieves the set of commits in this repository.

        :return: A set of GitLabCommit objects.
        """
        # Don't move to module, leads to circular imports
        from IGitt.GitLab.GitLabCommit import GitLabCommit

        return {
            GitLabCommit.from_data(commit, self._token, self.full_name,
                                   commit['id'])
            for commit in get(self._token, self._url + '/repository/commits')
        }
Beispiel #16
0
    def mrs_closed_by(self):
        """
        Returns the merge requests that close this issue.
        """
        from IGitt.GitLab.GitLabMergeRequest import GitLabMergeRequest

        url = '{url}/closed_by'.format(url=self._url)
        mrs = get(self._token, url)

        return {
            GitLabMergeRequest.from_data(mr, self._token, self._repository,
                                         mr['iid'])
            for mr in mrs if mr['state'] == MergeRequestStates.MERGED.value
        }
Beispiel #17
0
    def affected_files(self):
        """
        Retrieves affected files from a GitLab merge request.

        >>> from os import environ
        >>> pr = GitLabMergeRequest(
        ...     GitLabOAuthToken(environ['GITLAB_TEST_TOKEN']),
        ...     'gitmate-test-user/test', 2
        ... )
        >>> pr.affected_files
        {'README.md'}

        :return: A set of filenames.
        """
        changes = get(self._token, self._url + '/changes')['changes']
        return {change['old_path'] for change in changes}
Beispiel #18
0
    def owned_repositories(self):
        """
        Retrieves repositories owned by the authenticated user.

        >>> from os import environ
        >>> GitLab = GitLab(GitLabOAuthToken(viron['GITLAB_TEST_TOKEN']))
        >>> sorted(map(lambda x: x.full_name, GitLab.owned_repositories)
        {'gitmate-test-user/test'}

        :return: A set of GitLabRepository objects.
        """
        repo_list = get(self._token, '/projects', {'owned': True})
        return {
            GitLabRepository.from_data(repo, self._token,
                                       repo['path_with_namespace'])
            for repo in repo_list
        }
Beispiel #19
0
    def available_labels(self) -> Set[str]:
        """
        Retrieves a set of captions that are available for labelling bugs.

        >>> from os import environ
        >>> issue = GitLabIssue(GitLabOAuthToken(environ['GITLAB_TEST_TOKEN']),
        ...                     'gitmate-test-user/test', 1)
        >>> sorted(issue.available_labels)
        ['a', 'b', 'c']

        :return: A set of label captions (str).
        """
        return {
            label['name']
            for label in get(
                self._token, '/projects/' + quote_plus(self._repository) +
                '/labels')
        }
Beispiel #20
0
    def merge_requests(self) -> set:
        """
        Retrieves a set of merge request objects.

        >>> from os import environ
        >>> repo = GitLabRepository(
        ...     GitLabOAuthToken(environ['GITLAB_TEST_TOKEN']),
        ...     'gitmate-test-user/test'
        ... )
        >>> len(repo.merge_requests)
        4
        """
        from IGitt.GitLab.GitLabMergeRequest import GitLabMergeRequest
        return {
            GitLabMergeRequest.from_data(res, self._token, self.full_name,
                                         res['iid'])
            for res in get(self._token, self._url + '/merge_requests')
        }
Beispiel #21
0
    def get_labels(self) -> Set[str]:
        """
        Retrieves the labels of the repository.

        >>> from os import environ
        >>> repo = GitLabRepository(
        ...     GitLabOAuthToken(environ['GITLAB_TEST_TOKEN']),
        ...     'gitmate-test-user/test'
        ... )
        >>> sorted(repo.get_labels())
        ['a', 'b', 'c']

        :return: A set of strings containing the label captions.
        """
        return {
            label['name']
            for label in get(self._token, self._url + '/labels')
        }
Beispiel #22
0
    def write_repositories(self):
        """
        Retrieves the full names of repositories this user can write to.

        >>> from os import environ
        >>> GitLab = GitLab(GitLabOAuthToken(viron['GITLAB_TEST_TOKEN']))
        >>> sorted(map(lambda x: x.full_name, GitLab.write_repositories))
        ['gitmate-test-user/test', 'nkprince007/gitmate-test']

        :return: A set of GitLabRepository objects.
        """
        repo_list = get(self._token, '/projects', {'membership': True})
        return {
            GitLabRepository.from_data(repo, self._token,
                                       repo['path_with_namespace'])
            for repo in self._get_repos_with_permissions(
                repo_list, AccessLevel.CAN_WRITE)
        }
Beispiel #23
0
    def commits(self):
        """
        Retrieves a tuple of commit objects that are included in the PR.

        >>> from os import environ
        >>> pr = GitLabMergeRequest(
        ...     GitLabOAuthToken(environ['GITLAB_TEST_TOKEN']),
        ...     'gitmate-test-user/test', 2
        ... )
        >>> assert ([commit.sha for commit in pr.commits] == [
        ...     '99f484ae167dcfcc35008ba3b5b564443d425ee0',
        ...     'bbd11b50412d34072f1889e4cea04a32de183605'])

        :return: A tuple of commit objects.
        """
        commits = get(self._token, self._url + '/commits')
        return tuple(
            GitLabCommit(self._token, self._repository, commit['id'])
            for commit in commits)
Beispiel #24
0
    def comments(self) -> List[GitLabComment]:
        r"""
        Retrieves comments from the issue.

        As of now, the list of comments is not sorted. Related issue on GitLab
        CE here - https://gitlab.com/gitlab-org/gitlab-ce/issues/32057

        >>> from os import environ
        >>> issue = GitLabIssue(GitLabOAuthToken(environ['GITLAB_TEST_TOKEN']),
        ...                     'gitmate-test-user/test', 3)
        >>> comments = issue.comments
        >>> for comment in comments:
        ...     print(comment.body)
        Stop staring at me.
        Go, get your work done.

        :return: A list of Comment objects.
        """
        return [
            GitLabComment.from_data(result, self._token, self._repository,
                                    self.number, CommentType.ISSUE,
                                    result['id'])
            for result in get(self._token, self._url + '/notes')
        ]
Beispiel #25
0
    def get_statuses(self) -> Set[CommitStatus]:
        """
        Retrieves the all commit statuses.

        :return: A (frozen)set of CommitStatus objects.
        :raises RuntimeError: If something goes wrong (network, auth...).
        """
        # rebuild the url with full sha because gitlab doesn't work that way
        url = '/projects/{repo}/repository/commits/{sha}/statuses'.format(
            repo=quote_plus(self._repository), sha=self.sha)
        statuses = get(self._token, url)

        # Only the first of each context is the one we want
        result = set()
        contexts = set()
        for status in statuses:
            if status['name'] not in contexts:
                result.add(CommitStatus(
                    INV_GL_STATE_TRANSLATION[status['status']],
                    status['description'], status['name'],
                    status['target_url']))
                contexts.add(status['name'])

        return result
Beispiel #26
0
 def get_content(self, ref='master'):
     data = {'path': self._url, 'ref': ref}
     self.data = get(token=self._token, url=self._url, params=data)