def add_user(self, user: str, access_level: AccessLevel) -> None: """ AccessLevel.pull => Guest access AccessLevel.triage => Reporter access AccessLevel.push => Developer access AccessLevel.admin => Maintainer access AccessLevel.maintain => Owner access # Only valid for groups """ access_dict = { AccessLevel.pull: gitlab.GUEST_ACCESS, AccessLevel.triage: gitlab.REPORTER_ACCESS, AccessLevel.push: gitlab.DEVELOPER_ACCESS, AccessLevel.admin: gitlab.MAINTAINER_ACCESS, AccessLevel.maintain: gitlab.OWNER_ACCESS, } try: user_id = self.service.gitlab_instance.users.list( username=user)[0].id except Exception as e: raise GitlabAPIException(f"User {user} not found", e) try: self.gitlab_repo.members.create({ "user_id": user_id, "access_level": access_dict[access_level] }) except Exception as e: raise GitlabAPIException(f"User {user} already exists", e)
def __get_fork( fork_username: str, project: "ogr_gitlab.GitlabProject") -> "ogr_gitlab.GitlabProject": """ Returns forked project of a requested user. Internal method, in case the fork doesn't exist, raises GitlabAPIException. Args: fork_username: Username of a user that owns requested fork. project: Project to search forks of. Returns: Requested fork. Raises: GitlabAPIException, in case the fork doesn't exist. """ forks = list( filter( lambda fork: fork.gitlab_repo.namespace["full_path"] == fork_username, project.get_forks(), )) if not forks: raise GitlabAPIException("Requested fork doesn't exist") return forks[0]
def get_issue_labels(self, issue_id: int) -> List[str]: try: issue = self.gitlab_repo.issues.get(issue_id) except gitlab.exceptions.GitlabGetError as ex: logger.error(f"Issue {issue_id} was not found.") raise GitlabAPIException(f"Issue {issue_id} was not found. ", ex) return issue.labels
def set( project: "ogr_gitlab.GitlabProject", commit: str, state: Union[CommitStatus, str], target_url: str, description: str, context: str, trim: bool = False, ) -> "CommitFlag": state = GitlabCommitFlag._validate_state(state) if trim: description = description[:140] try: commit_object = project.gitlab_repo.commits.get(commit) except gitlab.exceptions.GitlabGetError: logger.error(f"Commit {commit} was not found.") raise GitlabAPIException(f"Commit {commit} was not found.") data_dict = { "state": GitlabCommitFlag._state_from_enum(state), "target_url": target_url, "context": context, "description": description, } raw_status = commit_object.statuses.create(data_dict) return GitlabCommitFlag(raw_commit_flag=raw_status, project=project)
def get(project: "ogr_gitlab.GitlabProject", issue_id: int) -> "Issue": try: return GitlabIssue(project.gitlab_repo.issues.get(issue_id), project) except gitlab.exceptions.GitlabGetError as ex: raise GitlabAPIException( f"Issue {issue_id} was not found. ") from ex
def get_sha_from_tag(self, tag_name: str) -> str: try: tag = self.gitlab_repo.tags.get(tag_name) return tag.attributes["commit"]["id"] except gitlab.exceptions.GitlabGetError as ex: logger.error(f"Tag {tag_name} was not found.") raise GitlabAPIException(f"Tag {tag_name} was not found.", ex)
def set( project: "ogr_gitlab.GitlabProject", commit: str, state: Union[CommitStatus, str], target_url: str, description: str, context: str, trim: bool = False, ) -> "CommitFlag": if trim: description = description[:140] if isinstance(state, str): warnings.warn( "Using the string representation of commit states, that will be removed in 0.14.0" " (or 1.0.0 if it comes sooner). Please use CommitStatus enum instead. " ) state = GitlabCommitFlag._states[state] try: commit_object = project.gitlab_repo.commits.get(commit) except gitlab.exceptions.GitlabGetError: logger.error(f"Commit {commit} was not found.") raise GitlabAPIException(f"Commit {commit} was not found.") data_dict = { "state": GitlabCommitFlag._state_from_enum(state), "target_url": target_url, "context": context, "description": description, } raw_status = commit_object.statuses.create(data_dict) return GitlabCommitFlag(raw_commit_flag=raw_status, project=project)
def create_issue( self, title: str, body: str, private: Optional[bool] = None, labels: Optional[List[str]] = None, assignees: Optional[List[str]] = None, ) -> Issue: ids = [] for user in assignees or []: users_list = self.service.gitlab_instance.users.list(username=user) if not users_list: raise GitlabAPIException(f"Unable to find '{user}' username") ids.append(str(users_list[0].id)) return GitlabIssue.create( project=self, title=title, body=body, private=private, labels=labels, assignees=ids, )
def commit_comment(self, commit: str, body: str, filename: str = None, row: int = None) -> "CommitComment": """ Create comment on a commit. :param commit: str The SHA of the commit needing a comment. :param body: str The text of the comment :param filename: str The relative path to the file that necessitates a comment :param row: int Line index in the diff to comment on. :return: CommitComment """ try: commit_object = self.gitlab_repo.commits.get(commit) except gitlab.exceptions.GitlabGetError: logger.error(f"Commit {commit} was not found.") raise GitlabAPIException(f"Commit {commit} was not found.") if filename and row: raw_comment = commit_object.comments.create({ "note": body, "path": filename, "line": row, "line_type": "new" }) else: raw_comment = commit_object.comments.create({"note": body}) return self._commit_comment_from_gitlab_object(raw_comment, commit)
def set_commit_status(self, commit: str, state: str, target_url: str, description: str, context: str) -> "CommitFlag": """ Create a status on a commit :param commit: The SHA of the commit. :param state: The state of the status. :param target_url: The target URL to associate with this status. :param description: A short description of the status :param context: A label to differentiate this status from the status of other systems. :return: CommitFlag """ try: commit_object = self.gitlab_repo.commits.get(commit) except gitlab.exceptions.GitlabGetError: logger.error(f"Commit {commit} was not found.") raise GitlabAPIException(f"Commit {commit} was not found.") data_dict = { "state": state, "target_url": target_url, "context": context, "description": description, } raw_status = commit_object.statuses.create(data_dict) return self._commit_status_from_gitlab_object(raw_status)
def get_pr_labels(self, pr_id: int) -> List[str]: try: pr = self.gitlab_repo.mergerequests.get(pr_id) except gitlab.exceptions.GitlabGetError as ex: logger.error(f"PR {pr_id} was not found.") raise GitlabAPIException(f"PR {pr_id} was not found. ", ex) return pr.labels
def create( project: "ogr_gitlab.GitlabProject", title: str, body: str, private: Optional[bool] = None, labels: Optional[List[str]] = None, assignees: Optional[List[str]] = None, ) -> "Issue": if not project.has_issues: raise IssueTrackerDisabled() assignee_ids = [] for user in assignees or []: users_list = project.service.gitlab_instance.users.list( username=user) if not users_list: raise GitlabAPIException(f"Unable to find '{user}' username") assignee_ids.append(str(users_list[0].id)) data = {"title": title, "description": body} if labels: data["labels"] = ",".join(labels) if assignees: data["assignee_ids"] = ",".join(assignee_ids) issue = project.gitlab_repo.issues.create(data, confidential=private) return GitlabIssue(issue, project)
def add_issue_labels(self, issue_id, labels) -> None: try: issue = self.gitlab_repo.issues.get(issue_id) except gitlab.exceptions.GitlabGetError as ex: logger.error(f"Issue {issue_id} was not found.") raise GitlabAPIException(f"Issue {issue_id} was not found. ", ex) for label in labels: issue.labels.append(label) issue.save()
def get_file_content(self, path, ref=None) -> str: ref = ref or self.default_branch try: file = self.gitlab_repo.files.get(file_path=path, ref=ref) return file.decode().decode() except gitlab.exceptions.GitlabGetError as ex: if ex.response_code == 404: raise FileNotFoundError(f"File '{path}' on {ref} not found") from ex raise GitlabAPIException() from ex
def add_user(self, user: str, access_level: AccessLevel) -> None: access_dict = { AccessLevel.pull: gitlab.GUEST_ACCESS, AccessLevel.triage: gitlab.REPORTER_ACCESS, AccessLevel.push: gitlab.DEVELOPER_ACCESS, AccessLevel.admin: gitlab.MAINTAINER_ACCESS, AccessLevel.maintain: gitlab.OWNER_ACCESS, } try: user_id = self.service.gitlab_instance.users.list(username=user)[0].id except Exception as e: raise GitlabAPIException(f"User {user} not found") from e try: self.gitlab_repo.members.create( {"user_id": user_id, "access_level": access_dict[access_level]} ) except Exception as e: raise GitlabAPIException(f"User {user} already exists") from e
def add_pr_labels(self, pr_id, labels) -> None: try: pr = self.gitlab_repo.mergerequests.get(pr_id) except gitlab.exceptions.GitlabGetError as ex: logger.error(f"PR {pr_id} was not found.") raise GitlabAPIException(f"PR {pr_id} was not found. ", ex) for label in labels: pr.labels.append(label) pr.save()
def wrapper(*args, **kwargs): try: return function(*args, **kwargs) except github.BadCredentialsException as ex: raise GithubAPIException("Invalid Github credentials") from ex except gitlab.GitlabAuthenticationError as ex: raise GitlabAPIException("Invalid Gitlab credentials") from ex except requests.exceptions.ConnectionError as ex: raise OgrNetworkError( "Could not perform the request due to a network error") from ex
def get_commit_comments(self, commit: str) -> List[CommitComment]: try: commit_object: ProjectCommit = self.gitlab_repo.commits.get(commit) except gitlab.exceptions.GitlabGetError as ex: logger.error(f"Commit {commit} was not found.") raise GitlabAPIException(f"Commit {commit} was not found.") from ex return [ self._commit_comment_from_gitlab_object(comment, commit) for comment in commit_object.comments.list() ]
def project_create(self, repo: str, namespace: str = None) -> "GitlabProject": data = {"name": repo} if namespace: try: group = self.gitlab_instance.groups.get(namespace) except gitlab.GitlabGetError: raise GitlabAPIException(f"Group {namespace} not found.") data["namespace_id"] = group.id new_project = self.gitlab_instance.projects.create(data) return GitlabProject( repo=repo, namespace=namespace, service=self, gitlab_repo=new_project )
def fork_create(self) -> "GitlabProject": try: fork = self.gitlab_repo.forks.create({}) except gitlab.GitlabCreateError as ex: logger.error(f"Repo {self.gitlab_repo} cannot be forked") raise GitlabAPIException( f"Repo {self.gitlab_repo} cannot be forked" ) from ex logger.debug(f"Forked to {fork.namespace['full_path']}/{fork.path}") return GitlabProject( namespace=fork.namespace["full_path"], service=self.service, repo=fork.path )
def get(project: "ogr_gitlab.GitlabProject", commit: str) -> List["CommitFlag"]: try: commit_object = project.gitlab_repo.commits.get(commit) except gitlab.exceptions.GitlabGetError: logger.error(f"Commit {commit} was not found.") raise GitlabAPIException(f"Commit {commit} was not found.") raw_statuses = commit_object.statuses.list() return [ GitlabCommitFlag(raw_commit_flag=raw_status, project=project) for raw_status in raw_statuses ]
def project_create( self, repo: str, namespace: Optional[str] = None, description: Optional[str] = None, ) -> "GitlabProject": data = {"name": repo} if namespace: try: group = self.gitlab_instance.groups.get(namespace) except gitlab.GitlabGetError as ex: raise GitlabAPIException(f"Group {namespace} not found.") from ex data["namespace_id"] = group.id if description: data["description"] = description try: new_project = self.gitlab_instance.projects.create(data) except gitlab.GitlabCreateError as ex: raise GitlabAPIException("Project already exists") from ex return GitlabProject( repo=repo, namespace=namespace, service=self, gitlab_repo=new_project )
def add_assignee(self, *assignees: str) -> None: assignee_ids = self._raw_issue.__dict__.get("assignee_ids") or [] for assignee in assignees: users = self.project.service.gitlab_instance.users.list( # type: ignore username=assignee) if not users: raise GitlabAPIException( f"Unable to find '{assignee}' username") uid = str(users[0].id) if uid not in assignee_ids: assignee_ids.append(str(users[0].id)) self._raw_issue.assignee_ids = assignee_ids self._raw_issue.save()
def fork_create(self, namespace: Optional[str] = None) -> "GitlabProject": data = {} if namespace: data["namespace_path"] = namespace try: fork = self.gitlab_repo.forks.create(data=data) except gitlab.GitlabCreateError as ex: logger.error(f"Repo {self.gitlab_repo} cannot be forked") raise GitlabAPIException( f"Repo {self.gitlab_repo} cannot be forked") from ex logger.debug(f"Forked to {fork.namespace['full_path']}/{fork.path}") return GitlabProject(namespace=fork.namespace["full_path"], service=self.service, repo=fork.path)
def fork_create(self) -> "GitlabProject": """ Fork this project using the authenticated user. This may raise an exception if the fork already exists. :return: fork GitlabProject instance """ try: fork = self.gitlab_repo.forks.create({}) except gitlab.GitlabCreateError: logger.error(f"Repo {self.gitlab_repo} cannot be forked") raise GitlabAPIException(f"Repo {self.gitlab_repo} cannot be forked") return GitlabProject( namespace=fork.namespace["full_path"], service=self.service, repo=fork.path )
def commit_comment( self, commit: str, body: str, filename: str = None, row: int = None ) -> "CommitComment": try: commit_object = self.gitlab_repo.commits.get(commit) except gitlab.exceptions.GitlabGetError as ex: logger.error(f"Commit {commit} was not found.") raise GitlabAPIException(f"Commit {commit} was not found.") from ex if filename and row: raw_comment = commit_object.comments.create( {"note": body, "path": filename, "line": row, "line_type": "new"} ) else: raw_comment = commit_object.comments.create({"note": body}) return self._commit_comment_from_gitlab_object(raw_comment, commit)
def get_commit_statuses(self, commit: str) -> List[CommitFlag]: """ Get the statuses of a commit in a project. :param commit: The SHA of the commit. :return: [CommitFlag] """ try: commit_object = self.gitlab_repo.commits.get(commit) except gitlab.exceptions.GitlabGetError: logger.error(f"Commit {commit} was not found.") raise GitlabAPIException(f"Commit {commit} was not found.") raw_statuses = commit_object.statuses.list() return [ self._commit_status_from_gitlab_object(raw_status) for raw_status in raw_statuses ]
def add_reaction(self, reaction: str) -> GitlabReaction: try: reaction_obj = self._raw_comment.awardemojis.create( {"name": reaction}) except gitlab.exceptions.GitlabCreateError as ex: if "404 Award Emoji Name has already been taken" not in str(ex): raise GitlabAPIException() from ex # this happens only when the reaction was already added logger.info(f"The emoji {reaction} has already been taken.") (reaction_obj, ) = filter( ( # we want to return that already given reaction lambda item: item.attributes[ "name"] == reaction and item.attributes["user"]["name"] == item.awardemojis.gitlab.user.name), self._raw_comment.awardemojis.list(), ) return GitlabReaction(reaction_obj)
def get(project: "ogr_gitlab.GitlabProject", pr_id: int) -> "PullRequest": try: mr = project.gitlab_repo.mergerequests.get(pr_id) except gitlab.GitlabGetError as ex: raise GitlabAPIException(f"No PR with id {pr_id} found") from ex return GitlabPullRequest(mr, project)
def merge_commit_status(self) -> MergeCommitStatus: status = self._raw_pr.merge_status if status in self._merge_commit_status: return self._merge_commit_status[status] else: raise GitlabAPIException(f"Invalid merge_status {status}")