Esempio n. 1
0
    def set_status(self, status: CommitStatus):
        """
        Adds the given status to the commit.

        >>> from os import environ
        >>> commit = GitHubCommit(GithubToken(environ['GITHUB_TEST_TOKEN']),
        ...                       'gitmate-test-user/test', '3fc4b86')
        >>> status = CommitStatus(Status.FAILED, 'Theres a problem',
        ...                       'gitmate/test')
        >>> commit.set_status(status)
        >>> commit.get_statuses().pop().description
        'Theres a problem'

        If a status with the same context already exists, it will be bluntly
        overridden:

        >>> status.status = Status.SUCCESS
        >>> status.description = "Theres no problem"
        >>> commit.set_status(status)
        >>> len(commit.get_statuses())
        2
        >>> commit.get_statuses().pop().description
        'This commit needs work.'

        :param status: The CommitStatus to set to this commit.
        :raises RuntimeError: If something goes wrong (network, auth...).
        """
        data = {
            'state': GH_STATE_TRANSLATION[status.status],
            'target_url': status.url,
            'description': status.description,
            'context': status.context
        }
        status_url = '/repos/' + self._repository + '/statuses/' + self.sha
        post(self._token, status_url, data)
Esempio n. 2
0
    def create_label(self, name: str, color: str):
        """
        Creates a new label with the given color. For an example,
        see delete_label.

        If a label that already exists is attempted to be created, that throws
        an exception:

        >>> from os import environ
        >>> repo = GitHubRepository(GitHubToken(environ['GITHUB_TEST_TOKEN']),
        ...                         'gitmate-test-user/test')
        >>> sorted(repo.get_labels())
        ['a', 'b', 'c']
        >>> repo.create_label('c', '#555555')
        Traceback (most recent call last):
         ...
        IGitt.ElementAlreadyExistsError: c already exists.

        :param name: The name of the label to create.
        :param color: A HTML color value with a leading #.
        :raises ElementAlreadyExistsError: If the label name already exists.
        :raises RuntimeError: If something goes wrong (network, auth...).
        """
        if name in self.get_labels():
            raise ElementAlreadyExistsError(name + ' already exists.')

        self.data = post(
            self._token,
            self._url + '/labels',
            {'name': name, 'color': color.lstrip('#')}
        )
Esempio n. 3
0
    def add_comment(self, body):
        """
        Adds a comment to the issue:

        >>> from os import environ
        >>> issue = GitHubIssue(GitHubToken(environ['GITHUB_TEST_TOKEN']),
        ...                     'gitmate-test-user/test', 3)
        >>> comment = issue.add_comment("Doh!")

        You can use the comment right after:

        >>> comment.body
        'Doh!'
        >>> comment.delete()

        The comment will be created by the user authenticated via the oauth
        token.

        :param body: The body of the new comment to create.
        :return: The newly created comment.
        """
        result = post(self._token, self._url + '/comments', {'body': body})

        return GitHubComment.from_data(result, self._token, self._repository,
                                       CommentType.ISSUE, result['id'])
Esempio n. 4
0
 def assign(self, *users: Set[GitHubUser]):
     """
     Adds the user as one of the assignees of the issue.
     :param username: Username of the user to be added as an assignee.
     """
     url = self._url + '/assignees'
     self.data = post(self._token, url,
                      {'assignees': [user.username for user in users]})
Esempio n. 5
0
    def register_hook(self,
                      url: str,
                      secret: Optional[str]=None,
                      events: Optional[Set[WebhookEvents]]=None):
        """
        Registers a webhook to the given URL. Use it as simple as:

        >>> from os import environ
        >>> repo = GitHubRepository(environ['GITHUB_TEST_TOKEN'],
        ...                         'gitmate-test-user/test')
        >>> repo.register_hook("http://some.url/in/the/world")

        It does nothing if the hook is already there:

        >>> repo.register_hook("http://some.url/in/the/world")

        To register a secret token with the webhook, simply add
        the secret param:

        >>> repo.register_hook("http://some.url/i/have/a/secret",
        ...     "mylittlesecret")

        To delete it simply run:

        >>> repo.delete_hook("http://some.url/in/the/world")
        >>> repo.delete_hook("http://some.url/i/have/a/secret")

        :param url: The URL to fire the webhook to.
        :param secret:
            An optional secret token to be registered with the webhook. An
        `X-Hub-Signature` value, in the response header, computed as a HMAC
        hex digest of the body, using the `secret` as the key would be
        returned when the webhook is fired.
        :param events:
            The events for which the webhook is to be registered against.
            Defaults to all possible events.
        :raises RuntimeError: If something goes wrong (network, auth...).
        """
        if url in self.hooks:
            return

        config = {'url': url, 'content_type': 'json'}
        reg_events = []

        if secret:
            config['secret'] = secret

        if events:
            reg_events = [GH_WEBHOOK_TRANSLATION[event] for event in events]

        self.data = post(
            self._token,
            self._url + '/hooks',
            {'name': 'web', 'active': True, 'config': config,
             'events': reg_events if len(reg_events) else ['*']}
        )
Esempio n. 6
0
    def create_fork(self, organization: Optional[str]=None,
                    namespace: Optional[str]=None):
        """
        Creates a fork of repository.
        """
        url = self._url + '/forks'
        data = {
            'organization': organization
        }
        data = eliminate_none(data)
        response = post(self._token, url, data=data)

        return GitHubRepository(self._token, response['full_name'])
Esempio n. 7
0
    def create_merge_request(self, title:str, base:str, head:str,
                             body: Optional[str]=None,
                             target_project_id: Optional[int]=None,
                             target_project: Optional[str]= None):
        """
        Creates a merge request to that repository
        """
        data = {'title': title, 'body': body, 'base': base,
                'head': head}
        url = self._url + '/pulls'
        json = post(self._token, url, data=data)

        from IGitt.GitHub.GitHubMergeRequest import GitHubMergeRequest
        return GitHubMergeRequest(self._token,
                                  json['base']['repo']['full_name'],
                                  json['number'])
Esempio n. 8
0
    def create(token: str, repository: str,
               title: str, body: str=''):
        """
        Create a new issue with given title and body.

        >>> from os import environ
        >>> issue = GitHubIssue.create(
        ...     GitHubToken(environ['GITHUB_TEST_TOKEN']),
        ...     'gitmate-test-user/test',
        ...     'test issue title',
        ...     'sample description'
        ... )
        >>> issue.state
        <IssueStates.OPEN: 'open'>
        >>> str(issue.state)
        'open'

        Let's delete the newly created one, because it's useless.

        >>> issue.delete()
        ... # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
         ...
        NotImplementedError

        Because GitHub is stupid, they don't allow deleting issues. So, let's
        atleast close this for now.

        >>> issue.close()

        :return: GitHubIssue object of the newly created issue.
        """

        post_url = '/repos/' + repository + '/issues'
        data = {
            'title': title,
            'body': body,
        }

        resp = post(token, post_url, data)
        issue_number = resp['number']

        return GitHubIssue.from_data(resp, token, repository, issue_number)
Esempio n. 9
0
    def comment(self,
                message: str,
                file: Optional[str] = None,
                line: Optional[int] = None,
                mr_number: Optional[int] = None) -> GitHubComment:
        """
        Places a comment on the commit.

        >>> from os import environ
        >>> commit = GitHubCommit(GithubToken(environ['GITHUB_TEST_TOKEN']),
        ...                       'gitmate-test-user/test', '3fc4b86')

        So this line places a comment on the bottom of the commit,
        not associated to any particular piece of code:

        >>> commit.comment("An issue is here!")

        However, we can also comment on a particular file and line, if that is
        included in the diff:

        >>> commit.comment("Here in line 4, there's a spelling mistake!",
        ...                'README.md', 4)

        If you supply the ``pr_number`` argument, the comment will appear in the
        review UI of that pull request:

        >>> commit.comment("Here in line 4, there's a spelling mistake!",
        ...                'README.md', 4, mr_number=6)

        Beat that! Of course, there's a lot of error handling. If you give the
        wrong file, the comment will appear below the commit with a note about
        the commit, file and line:

        >>> commit.comment("Oh, this'll end up below!!", 'READMENOT.md', 4)

        Also if the line isn't contained in the diff GitHub won't accept that
        and it'll also end up below - sorry!

        >>> commit.comment("Oh, this'll too end up below!!", 'README.md', 8)

        If you give a pull request, the comment will appear on the PR instead:

        >>> commit.comment("Oh, this'll too end up on the PR.",
        ...                'README.md', 8, mr_number=6)

        :param message: The body of the comment.
        :param file: The file to place the comment, relative to repository root.
        :param line: The line in the file in the comment or None.
        :param mr_number: The number of a merge request if this should end up in
                          the review UI of the merge request.
        """
        data = {'body': message}

        if file is not None and line is not None:
            try:
                patch = self.get_patch_for_file(file)
                index = get_diff_index(patch, line)
                if index:  # Else, fallback to comment below file
                    data['position'] = index
                    data['path'] = file
            except ElementDoesntExistError:
                pass  # Fallback to comment below the file

        if 'position' not in data:
            file_str = '' if file is None else ', file ' + file
            line_str = '' if line is None else ', line ' + str(line)
            data['body'] = ('Comment on ' + self.sha + file_str + line_str +
                            '.\n\n' + data['body'])

        comment_type = None

        if mr_number is None:
            comment_type = CommentType.COMMIT
            res = post(self._token, self._url + '/comments', data)
        elif 'position' in data:
            comment_type = CommentType.REVIEW
            data['commit_id'] = self.sha
            res = post(
                self._token, '/repos/' + self._repository + '/pulls/' +
                str(mr_number) + '/comments', data)
        else:  # Position not available, pr number available, comment on PR
            comment_type = CommentType.ISSUE
            res = post(
                self._token, '/repos/' + self._repository + '/issues/' +
                str(mr_number) + '/comments', data)

        return GitHubComment.from_data(res, self._token, self._repository,
                                       comment_type, res['id'])