diff --git a/api/course.py b/api/course.py index fd77bdfa7a0e999c58510fc107354d19d4bdb06c..5a907ff767a779cd184bb06c2c411b0b2ffc9460 100644 --- a/api/course.py +++ b/api/course.py @@ -3,5 +3,6 @@ class Course: gitlab_namespace = 'csce_361/sandbox' # Canvas course information - canvas_course_id = None + # canvas_course_id = '73696' # Software Engineering Sandbox + canvas_course_id = '66898' # CSCE 361-1198 diff --git a/api/gitlab_functions.py b/api/gitlab_functions.py index c43f72eb1514a62abfc12b8b116e633fe2bbd1e7..797e859b47f64022a88ede98ca2fdc35c113e57f 100644 --- a/api/gitlab_functions.py +++ b/api/gitlab_functions.py @@ -156,6 +156,9 @@ def create_issue(project, title, description): if __name__ == '__main__': git = gitlab.Gitlab(Config.gitlab_url, private_token=Config.gitlab_api_key) + project = get_project_by_id(git, '5484') + student = get_user_by_id(git, project.creator_id) + print(f'{student.name} forked repo at {project.created_at}') print('getting a user, by name') print(get_user_by_name(git, 'bohn')) print('getting a user by user ID and printing only the user\'s name') diff --git a/gitlab_classes.py b/gitlab_classes.py new file mode 100644 index 0000000000000000000000000000000000000000..87328fd0afe1e4b1a20785d025acc8658dbae4e9 --- /dev/null +++ b/gitlab_classes.py @@ -0,0 +1,325 @@ +from datetime import datetime +import gitlab +from config import Config + + +def gitlab_timestamp_to_datetime(timestamp): + return datetime.fromisoformat(timestamp) + + +class Session: + __instance = None + + @staticmethod + def get_session(): + if Session.__instance is None: + Session.__instance = gitlab.Gitlab(Config.gitlab_url, private_token=Config.gitlab_api_key) + return Session.__instance + + +class User: + def __init__(self, user): + """ + Creates a User object, populating the backing git_user instance with the appropriate gitlab.User object + :param user: must be either a gitlab.User object, an integer representing the user ID, or a string containing + the username + """ + super().__init__() + if isinstance(user, int): # by user id + self.git_user = Session.get_session().users.get(user) + elif isinstance(user, str): # by username + self.git_user = Session.get_session().users.list(username=user)[0] + else: + self.git_user = user + + def get_user_id(self): + return self.git_user.id + + def get_name(self): + return self.git_user.name + + def get_username(self): + return self.git_user.username + + def get_site(self): + return self.git_user.web_url + + +class Issue: + def __init__(self, issue): + """ + Creates an Issue object, populating the backing git_issue instance with the appropriate gitlab.Issue object + :param issue: must be a gitlab.Issue object + """ + super().__init__() + self.git_issue = issue + + def get_universal_issue_id(self): + """ + :return: universally-unique identifier + """ + return self.git_issue.id + + def get_project_issue_id(self): + """ + :return: project-unique identifier + """ + return self.git_issue.iid + + def get_state(self): + """ + :return: opened or closed + """ + return self.git_issue.state + + def get_created_at(self): + """ + :return: an "aware" datetime object representing the creation date/time + """ + created_at = self.git_issue.created_at + if created_at[-1] in ('z', 'Z'): # Didn't encounter this problem with created_at + created_at = created_at[:-1] + '+00:00' + return datetime.fromisoformat(created_at) + + def get_updated_at(self): + """ + :return: an "aware" datetime object representing the last date/time the issue was updated + """ + updated_at = self.git_issue.updated_at + if updated_at[-1] in ('z', 'Z'): # Didn't encounter this problem with updated_at + updated_at = updated_at[:-1] + '+00:00' + return datetime.fromisoformat(updated_at) + + def get_closed_at(self): + """ + :return: an "aware" datetime object representing the last date/time the issue was closed, or None if the issue + is open + """ + closed_at = self.git_issue.closed_at + if closed_at is None: + return None + else: + if closed_at[-1] in ('z', 'Z'): # Did encounter this problem with closed_at + closed_at = closed_at[:-1] + '+00:00' + return datetime.fromisoformat(closed_at) + + def get_labels(self): + """ + :return: list of labels + """ + return self.git_issue.labels.list(all=True) + + def get_page(self): + """ + :return: HTTPS URL to issue's page + """ + return self.git_issue.web_url + + # other git_issue fields: + # project_id + # title + # description + # closed_by user + # milestone + # assignees list of users + # author user + # assignee user + # user_notes_count + # merge_requests_count + # upvotes + # downvotes + # due_date same date format, or None + # confidential + # discussion_locked + # time_stats + # task_completion_status + # has_tasks + # _links + # notes + # award_emoji + # project + # subscribed + + +class Project: + def __init__(self, project): + """ + Creates a Project object, populating the backing git_project instance with the appropriate gitlab.Project object + :param project: must be either a gitlab.Project object, an integer representing the project ID, or a string + containing the project's path (namespace and name, such as 'csce_361/sandbox/HelloWorld') + """ + super().__init__() + if isinstance(project, int): # by project id + self.git_project = Session.get_session().projects.get(project) + elif isinstance(project, str): # by path + self.git_project = Session.get_session().projects.get(project) + else: + self.git_project = project + + @staticmethod + def get_projects_by_group(group_id): + gitlab_projects = Session.get_session().groups.get(group_id).projects.list(all=True) + projects = [] + for project in gitlab_projects: + projects.append(Project(project)) + return projects + + @staticmethod + def get_projects_by_keyword(search_term): + gitlab_projects = Session.get_session().projects.list(search=search_term, all=True) + projects = [] + for project in gitlab_projects: + projects.append(Project(project)) + return projects + + @staticmethod + def create_project(project_name): + return Session.get_session().projects.create({'name': project_name}) + + @staticmethod + def create_project_in_group(group_name, project_name): + group_id = Session.get_session().groups.get(group_name).id + return Session.get_session().projects.create({'name': project_name, 'namespace_id': group_id}) + + def get_project_id(self): + return self.git_project.id + + def get_name(self): + """ + :return: project name without namespace + """ + return self.git_project.name + + def get_name_with_namespace(self): + """ + :return: project name with namespace, spaces around slashes + """ + return self.git_project.name_with_namespace + + def get_path(self): + """ + :return: path without namespace (may differ from name if name has spaces) + """ + return self.git_project.path + + def get_path_with_namespace(self): + """ + :return: path with namespace, no spaces around slashes + """ + return self.git_project.path_with_namespace + + def get_cloning_url(self): + """ + :return: SSH URL to clone repository + """ + return self.git_project.ssh_url_to_repo + + def get_site(self): + """ + :return: HTTPS URL to git site + """ + return self.git_project.web_url + + def get_readme_url(self): + """ + :return: HTTPS URL to README.md + """ + return self.git_project.readme_url + + def get_visibility(self): + """ + :return: 'private', etc. + """ + return self.git_project.visibility + + def get_creator(self): + """ + :return: User object backed by the gitlab.User object representing the user who created the repo + """ + return User(self.git_project.creator_id) + + def get_users(self): + """ + :return: List of User objects representing the project's members (not including inherited members) + """ + gitlab_users = self.git_project.members.list(all=True) + users = [] + for user in gitlab_users: + users.append(User(user)) + return users + + def get_all_users(self): + """ + :return: List of User objects representing all of the project's members (including inherited members) + """ + gitlab_users = self.git_project.members.all(all=True) + users = [] + for user in gitlab_users: + users.append(User(user)) + return users + + def add_user_as_maintainer(self, user): + self.git_project.members.create({'user_id': user.get_user_id(), 'access_level': gitlab.MAINTAINER_ACCESS}) + + def get_issues(self): + """ + :return: List of Issue objects representing project's issues, sorted by creation date + """ + gitlab_issues = self.git_project.issues.list(order_by='created_at', sort='asc', all=True) + issues = [] + for issue in gitlab_issues: + issues.append(Issue(issue)) + return issues + + def create_issue(self, title, description): + gitlab_issue = self.git_project.issues.create({'title': title, 'description': description}) + return Issue(gitlab_issue) + + # other git_project fields: + # description + # created_at + # default_branch + # tag_list + # http_url_to_repo https URL to clone repository + # avatar_url + # star_count + # forks_count + # last_activity_at + # namespace namespace's JSON object + # _links JSON object with api/v4 links to self, issues, merge_requests, + # repo_branches, labels, events, members + # empty_repo + # archived + # resolve_outdated_diff_discussions + # container_registry_enabled + # issues_enabled + # merge_requests_enabled + # jobs_enabled + # snippets_enabled + # issues_access_level + # repository_access_level, + # wiki_access_level + # builds_access_level + # snippets_access_level + # shared_runners_enabled + # lfs_enabled + # import_status + # import_error + # open_issues_count + # runners_token + # ci_default_git_depth + # public_jobs + # build_git_strategy + # build_timeout + # auto_cancel_pending_pipelines + # build_coverage_regex + # ci_config_path + # shared_with_groups + # only_allow_merge_if_pipeline_succeeds + # request_access_enabled + # only_allow_merge_if_all_discussions_are_resolved + # printing_merge_request_link_enabled + # merge_method + # auto_devops_enabled + # auto_devops_deploy_strategy + # permissions