def create_file(self, path: str, message: str, content: str, branch: Optional[str] = None, committer: Optional[str] = None, author: Optional[dict] = None, encoding: Optional[str] = None): """ Create a new file in Repository """ url = self._url + '/repository/files/' + path data = { 'file_path': path, 'commit_message': message, 'content': content, 'branch': branch, 'encoding': encoding } if author: data['author_name'] = author['name'] data['author_email'] = author['email'] data = eliminate_none(data) post(token=self._token, url=url, data=data) from IGitt.GitLab.GitLabContent import GitLabContent return GitLabContent(self._token, self.full_name, path=path)
def set_status(self, status: CommitStatus): """ Adds the given status to the commit. >>> from os import environ >>> commit = GitLabCommit( ... GitLabOAuthToken(environ['GITLAB_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()) 1 >>> commit.get_statuses().pop().description 'Theres no problem' :param status: The CommitStatus to set to this commit. :raises RuntimeError: If something goes wrong (network, auth...). """ data = {'state': GL_STATE_TRANSLATION[status.status], 'target_url': status.url, 'description': status.description, 'name': status.context} status_url = '/projects/{repo}/statuses/{sha}'.format( repo=quote_plus(self._repository), sha=self.sha) post(self._token, status_url, data)
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): """ Create a new merge request in Repository """ url = self._url + '/merge_requests' data = { 'title': title, 'target_branch': base, 'source_branch': head, 'id': quote_plus(self.full_name), 'target_project_id': target_project_id } json = post(self._token, url=url, data=data) from IGitt.GitLab.GitLabMergeRequest import GitLabMergeRequest return GitLabMergeRequest.from_data(json, self._token, repository=target_project, number=json['iid'])
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 = GitLabRepository( ... GitLabOAuthToken(environ['GITLAB_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 })
def create(token: Union[GitLabOAuthToken, GitLabPrivateToken], repository: str, title: str, body: str = ''): """ Create a new issue with given title and body. >>> from os import environ >>> issue = GitLabIssue.create( ... GitLabOAuthToken(environ['GITLAB_TEST_TOKEN']), ... 'gitmate-test-user/test', ... 'test issue title', ... 'sample description' ... ) >>> issue.state <IssueStates.OPEN: 'open'> Delete the issue to avoid filling the test repo with issues. >>> issue.delete() :return: GitLabIssue object of the newly created issue. """ url = '/projects/{repo}/issues'.format(repo=quote_plus(repository)) issue = post(token, url, {'title': title, 'description': body}) return GitLabIssue.from_data(issue, token, repository, issue['iid'])
def add_comment(self, body): """ Adds a comment to the issue. >>> from os import environ >>> issue = GitLabIssue(GitLabOAuthToken(environ['GITLAB_TEST_TOKEN']), ... 'gitmate-test-user/test', 1) >>> 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 + '/notes', {'body': body}) return GitLabComment(self._token, self._repository, self.number, CommentType.ISSUE, result['id'])
def create_fork(self, organization: Optional[str] = None, namespace: Optional[str] = None): """ Create a fork of Repository """ url = self._url + '/fork' data = {'id': self.full_name, 'namespace': namespace} res = post(self._token, url=url, data=data) return GitLabRepository(self._token, res['path_with_namespace'])
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 = GitLabRepository(environ['GITLAB_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. :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, 'enable_ssl_verification': False, } if secret: config['token'] = secret if events and len(events): config.update( {GL_WEBHOOK_TRANSLATION[event]: True for event in events}) else: config.update({event: True for event in GL_WEBHOOK_EVENTS}) self.data = post(self._token, self._url + '/hooks', config)
def comment(self, message: str, file: Optional[str]=None, line: Optional[int]=None, mr_number: Optional[int]=None) -> GitLabComment: """ Places a comment on the commit. >>> from os import environ >>> commit = GitLabCommit( ... GitLabOAuthToken(environ['GITLAB_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=7) 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 GitLab 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=7) :param message: The body of the comment. :param file: The file to place the comment, relative to repo root. :param line: The line in the file in the comment or None. :param mr_number: The iid of a merge request if this should end up in the discussions UI of the merge request. """ data = {'note': message, 'line_type': 'new'} 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['line'] = index data['path'] = file except ElementDoesntExistError: pass # Fallback to comment below the file if 'line' not in data: file_str = '' if file is None else ', file ' + file line_str = '' if line is None else ', line ' + str(line) data['note'] = ('Comment on ' + self.sha + file_str + line_str + '.\n\n' + data['note']) # post a comment on commit if 'line' in data and 'path' in data or mr_number is None: url = '/projects/{id}/repository/commits/{sha}/comments'.format( id=quote_plus(self._repository), sha=self.sha) res = post(self._token, url, data) return # fallback to post the comment on relevant merge request if mr_number is not None: data['body'] = data['note'] # because gitlab is stupid res = post(self._token, '/projects/{id}/merge_requests/{mr_iid}/notes'.format( id=quote_plus(self._repository), mr_iid=mr_number), data) return GitLabComment.from_data(res, self._token, self._repository, mr_number, CommentType.MERGE_REQUEST, res['id'])