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)
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('#')} )
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'])
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]})
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 ['*']} )
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'])
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'])
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)
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'])