From e50f612ab51683b72d9f7eb7a4c0ebed69cfd091 Mon Sep 17 00:00:00 2001
From: Christopher Bohn <bohn@unl.edu>
Date: Fri, 13 Sep 2019 11:21:45 -0500
Subject: [PATCH] Create class wrappers for git concepts.
Besides facilitating a more OO approach, the wrapper will make code
completion in IDEs possible.
---
api/course.py | 3 +-
api/gitlab_functions.py | 3 +
gitlab_classes.py | 325 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 330 insertions(+), 1 deletion(-)
create mode 100644 gitlab_classes.py
diff --git a/api/course.py b/api/course.py
index fd77bdf..5a907ff 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 c43f72e..797e859 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 0000000..87328fd
--- /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
--
GitLab