From 18b0513a9cf0d525c20382d965c5b61adf6c8d6a Mon Sep 17 00:00:00 2001 From: scottyang Date: Wed, 19 Apr 2023 22:50:52 -0700 Subject: [PATCH] github integration --- CanvasGroupy/_modidx.py | 30 +- CanvasGroupy/canvas_group.py | 2 +- CanvasGroupy/gh_group.py | 183 +++--- README.md | 3 +- _proc/02_gh_group_creation.ipynb | 462 +++++---------- _proc/03_canvas_group_creation.ipynb | 20 +- _proc/_docs/canvas_group_creation.html | 185 ++---- _proc/_docs/core.html | 183 ++---- _proc/_docs/gh_group_creation.html | 530 ++++++------------ _proc/_docs/groupeng_assign.html | 383 +++++-------- _proc/_docs/index.html | 178 ++---- _proc/_docs/search.json | 33 +- .../site_libs/bootstrap/bootstrap.min 2.css | 10 + .../site_libs/bootstrap/bootstrap.min 3.css | 10 + .../site_libs/bootstrap/bootstrap.min.css | 4 +- .../quarto-syntax-highlighting.css | 32 -- _proc/_docs/sitemap.xml | 8 +- _proc/credentials.json | 4 + _proc/sidebar.yml | 1 - _proc/sidebar.yml.bak | 2 - nbs/00_core.ipynb | 93 --- nbs/02_gh_group_creation.ipynb | 431 +++++++++----- nbs/03_canvas_group_creation.ipynb | 39 +- nbs/credentials.json | 4 + nbs/sidebar.yml | 1 - 25 files changed, 1074 insertions(+), 1757 deletions(-) create mode 100644 _proc/_docs/site_libs/bootstrap/bootstrap.min 2.css create mode 100644 _proc/_docs/site_libs/bootstrap/bootstrap.min 3.css create mode 100644 _proc/credentials.json delete mode 100644 nbs/00_core.ipynb create mode 100644 nbs/credentials.json diff --git a/CanvasGroupy/_modidx.py b/CanvasGroupy/_modidx.py index ac70c36..f4f64ba 100644 --- a/CanvasGroupy/_modidx.py +++ b/CanvasGroupy/_modidx.py @@ -33,19 +33,17 @@ 'CanvasGroupy/gh_group.py'), 'CanvasGroupy.gh_group.GitHubGroup.__init__': ( 'gh_group_creation.html#githubgroup.__init__', 'CanvasGroupy/gh_group.py'), - 'CanvasGroupy.gh_group.cd_cmd': ('gh_group_creation.html#cd_cmd', 'CanvasGroupy/gh_group.py'), - 'CanvasGroupy.gh_group.check_gh_auth': ( 'gh_group_creation.html#check_gh_auth', - 'CanvasGroupy/gh_group.py'), - 'CanvasGroupy.gh_group.command': ('gh_group_creation.html#command', 'CanvasGroupy/gh_group.py'), - 'CanvasGroupy.gh_group.delete_directory': ( 'gh_group_creation.html#delete_directory', - 'CanvasGroupy/gh_group.py'), - 'CanvasGroupy.gh_group.git_add_all': ( 'gh_group_creation.html#git_add_all', - 'CanvasGroupy/gh_group.py'), - 'CanvasGroupy.gh_group.git_commit': ( 'gh_group_creation.html#git_commit', - 'CanvasGroupy/gh_group.py'), - 'CanvasGroupy.gh_group.git_creat_repo_cmd': ( 'gh_group_creation.html#git_creat_repo_cmd', - 'CanvasGroupy/gh_group.py'), - 'CanvasGroupy.gh_group.git_manage_access_cmd': ( 'gh_group_creation.html#git_manage_access_cmd', - 'CanvasGroupy/gh_group.py'), - 'CanvasGroupy.gh_group.git_rename_cmd': ( 'gh_group_creation.html#git_rename_cmd', - 'CanvasGroupy/gh_group.py')}}} + 'CanvasGroupy.gh_group.GitHubGroup.add_collaborators': ( 'gh_group_creation.html#githubgroup.add_collaborators', + 'CanvasGroupy/gh_group.py'), + 'CanvasGroupy.gh_group.GitHubGroup.auth_github': ( 'gh_group_creation.html#githubgroup.auth_github', + 'CanvasGroupy/gh_group.py'), + 'CanvasGroupy.gh_group.GitHubGroup.create_group_repo': ( 'gh_group_creation.html#githubgroup.create_group_repo', + 'CanvasGroupy/gh_group.py'), + 'CanvasGroupy.gh_group.GitHubGroup.create_repo': ( 'gh_group_creation.html#githubgroup.create_repo', + 'CanvasGroupy/gh_group.py'), + 'CanvasGroupy.gh_group.GitHubGroup.get_repo': ( 'gh_group_creation.html#githubgroup.get_repo', + 'CanvasGroupy/gh_group.py'), + 'CanvasGroupy.gh_group.GitHubGroup.rename_files': ( 'gh_group_creation.html#githubgroup.rename_files', + 'CanvasGroupy/gh_group.py'), + 'CanvasGroupy.gh_group.GitHubGroup.set_org': ( 'gh_group_creation.html#githubgroup.set_org', + 'CanvasGroupy/gh_group.py')}}} diff --git a/CanvasGroupy/canvas_group.py b/CanvasGroupy/canvas_group.py index fee2315..e9b7745 100644 --- a/CanvasGroupy/canvas_group.py +++ b/CanvasGroupy/canvas_group.py @@ -52,7 +52,7 @@ def set_group_category(self, self.group_category = self.group_categories[category_name] except KeyError: raise KeyError(f"{category_name} did not found in the group categories." - f"\n Try to create one with CanvasGroup.create_group_category") + f"Try to create one with CanvasGroup.create_group_category") return self.group_category def get_course(self): diff --git a/CanvasGroupy/gh_group.py b/CanvasGroupy/gh_group.py index cb6e3b6..56cd1ea 100644 --- a/CanvasGroupy/gh_group.py +++ b/CanvasGroupy/gh_group.py @@ -1,99 +1,108 @@ # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/02_gh_group_creation.ipynb. # %% auto 0 -__all__ = ['GitHubGroup', 'command', 'check_gh_auth', 'git_creat_repo_cmd', 'git_manage_access_cmd', 'cd_cmd', 'git_rename_cmd', - 'git_commit', 'git_add_all', 'delete_directory'] +__all__ = ['GitHubGroup'] # %% ../nbs/02_gh_group_creation.ipynb 3 from github import Github +import github +import json # %% ../nbs/02_gh_group_creation.ipynb 4 -class GitHubGroup(): +class GitHubGroup: def __init__(self, - token="", - org="" + credentials_fp="", # the file path to the credential json + org="", # the organization name ): - return ... + self.github = None + self.org = None + + if credentials_fp != "": + self.auth_github(credentials_fp) + if org != "": + self.set_org(org) -# %% ../nbs/02_gh_group_creation.ipynb 8 -def command(cmd: str # command to call in bash - ) -> (bool, str): # success, output - "Execute the given command in shell" - success = False - try: - output = subprocess.check_output(cmd, shell=True, stderr = subprocess.STDOUT) - success = True - except subprocess.CalledProcessError as e: - output = e.output - except Exception as e: - # check_call can raise other exceptions, such as FileNotFoundError - output = str(e) - print('> '+cmd) - print(output.decode()) - return success, output + def auth_github(self, + credentials_fp: str # the personal access token generated at GitHub Settings + ): + "Authenticate GitHub account with the provided credentials" + with open(credentials_fp, "r") as f: + token = json.load(f)["GitHub Token"] + self.github = Github(token) + # check authorization + _ = self.github.get_user().get_repos()[0] + + def set_org(self, + org: str # the target organization name + ): + "Set the target organization for repo creation" + self.org = self.github.get_organization(org) -# %% ../nbs/02_gh_group_creation.ipynb 9 -def check_gh_auth() -> bool: # whether you have authenticate - "Check whether you have gh auth configured" - msg = command("gh auth status")[1] - if "You are not logged into any GitHub hosts" in str(msg): - return False - return True - -# %% ../nbs/02_gh_group_creation.ipynb 10 -def git_creat_repo_cmd(repo_name:str, # the name of the created repository - repo_org: str, # the GitHub organization name - template_repo:str, # the template repository that the new repo will use - private_repo=True # the visibility of the repository - ) -> str: # the command of repo creation - "Generate the appropriate command for creating GitHub repository" - cmd = "gh repo create" - if template_repo is not None: - cmd = f"{cmd} --template {template_repo}" - if private_repo: - cmd = f"{cmd} --private" - cmd = f"{cmd} --clone {repo_org}/{repo_name}" - return cmd - -# %% ../nbs/02_gh_group_creation.ipynb 12 -def git_manage_access_cmd(repo_name:str, # the name of the created repository - repo_org: str, # the GitHub organization name that the repo belongs to - collaorator_id: str, # the GitHub id of the collaborator, or team name if `add_team=True` - permission="push", # the permission to that collaborator - add_team=False # add access to github org's team - ) -> str: # the command of repo creation - "GitHub CLI Command for modifying access priviliges of repo" - if add_team: - return (f"gh api -X PUT -f permission={permission} --silent " - f"/orgs/{repo_org}/teams/{collaorator_id}/repos/{repo_org}/{repo_name}") - cmd = f"gh api -X PUT -f permission={permission} --silent repos/{repo_org}/{repo_name}/{collaorator_id}" - return cmd - - -# %% ../nbs/02_gh_group_creation.ipynb 15 -def cd_cmd(target_dir: str # the target directory we want to change to - ) -> str: # the command of cd - "Unix command for change directory" - return f"cd {target_dir}" - -# %% ../nbs/02_gh_group_creation.ipynb 16 -def git_rename_cmd(source: str, # the original name of the file - target: str # the target name of the file - ) -> str: # the command of git rename file - "GitHub mv command to rename file in the directory" - return f"git mv {source} {target}" - -# %% ../nbs/02_gh_group_creation.ipynb 17 -def git_commit(commit_msg: str, # Commit Message - ) -> str: # the command for git commit - "GitHub commit command" - return f'git commit -m "{commit_msg}"' - -# %% ../nbs/02_gh_group_creation.ipynb 18 -def git_add_all(): - return "git add -A" - -# %% ../nbs/02_gh_group_creation.ipynb 19 -def delete_directory(dir_name: str # the directory that we want to delete - ) -> str: # the command for delete dir - return f"rm -rf {dir_name}" + def create_repo(self, + repo_name: str, # repository name + repo_template="", # template repository that new repo will use. If empty string, an empty repo will be created. Put in the format of "/" + private=True, # visibility of the created repository + description="", # description for the GitHub repository + personal_account=False, # create repos in personal GitHub account + ) -> github.Repository.Repository: + "Create a repository, either blank, or from a template" + if self.org is None and personal_account: + raise ValueError("Organization is not set") + if personal_account: + parent = self.github.get_user() + else: + parent = self.org + if repo_template == "": + return parent.create_repo( + name=repo_name, + private=private, + description=description + ) + # create from template + return parent.create_repo_from_template( + name=repo_name, + repo=self.get_repo(repo_template), + private=private, + description=description, + ) + + def get_repo(self, + repo_full_name: str # full name of the target repository + ) -> github.Repository.Repository: + "To get a repository by its name" + return self.github.get_repo(repo_full_name) + + def rename_files(self, + repo: github.Repository.Repository, # the repository that we want to rename file + og_filename: str, # old file name + new_filename: str # new file name + ): + "Rename the file by delete the old file and commit the new file" + file = repo.get_contents(og_filename) + repo.create_file(new_filename, "rename files", file.decoded_content) + repo.delete_file(og_filename, "delete old files", file.sha) + + def add_collaborators(self, + repo: github.Repository.Repository, # target repository + collaborator:str, # GitHub username of the collaborator + permission:str # `pull`, `push` or `admin` + ): + "add collaborators to the repository" + repo.add_to_collaborators(collaborator, permission) + + def create_group_repo(self, + repo_name: str, # group repository name + collaborators: [str], # list of collaborators GitHub id + permission: str, # the permission of collaborators + rename_files=dict(), # dictionary of files renames {:} + repo_template="", # If empty string, an empty repo will be created. Put in the format of "/" + private=True, # visibility of the created repository + description="", # description for the GitHub repository + ) -> github.Repository.Repository: + "Create a Group Repository" + repo = self.create_repo(repo_name, repo_template, private, description) + for og_name, new_name in rename_files.values(): + self.rename_files(repo, og_name, new_name) + for collaborator in collaborators: + self.add_collaborators(repo, collaborator) + return repo diff --git a/README.md b/README.md index faa5200..f423def 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# CanvasGroupy +CanvasGroupy +================ diff --git a/_proc/02_gh_group_creation.ipynb b/_proc/02_gh_group_creation.ipynb index 39410ee..8947103 100644 --- a/_proc/02_gh_group_creation.ipynb +++ b/_proc/02_gh_group_creation.ipynb @@ -30,24 +30,34 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L11){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L12){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### GitHubGroup\n", "\n", - "> GitHubGroup (token='', org='')\n", + "> GitHubGroup (credentials_fp='', org='')\n", "\n", - "Initialize self. See help(type(self)) for accurate signature." + "Initialize self. See help(type(self)) for accurate signature.\n", + "\n", + "| | **Type** | **Default** | **Details** |\n", + "| -- | -------- | ----------- | ----------- |\n", + "| credentials_fp | str | | the file path to the credential json |\n", + "| org | str | | the organization name |" ], "text/plain": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L11){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L12){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### GitHubGroup\n", "\n", - "> GitHubGroup (token='', org='')\n", + "> GitHubGroup (credentials_fp='', org='')\n", + "\n", + "Initialize self. See help(type(self)) for accurate signature.\n", "\n", - "Initialize self. See help(type(self)) for accurate signature." + "| | **Type** | **Default** | **Details** |\n", + "| -- | -------- | ----------- | ----------- |\n", + "| credentials_fp | str | | the file path to the credential json |\n", + "| org | str | | the organization name |" ] }, "execution_count": 1, @@ -62,13 +72,13 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "metadata": { - "language": "python" - }, - "outputs": [], - "source": [] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## GitHub Authentication\n", + "\n", + "View this [document](https://docs.google.com/document/d/1RvZnOX6nh0bXn6Zh4U-Yxazukuez5oGrtcP8mN-Roco/edit?usp=sharing) for how to set up your GitHub Personal Access Token. (TODO: be sure to specify scopes)" + ] }, { "cell_type": "code", @@ -77,53 +87,56 @@ "language": "python" }, "outputs": [], - "source": [] + "source": [ + "credentials_fp = \"credentials.json\"\n", + "g = GitHubGroup(credentials_fp=\"../../credentials.json\", org=\"COGS118A\")" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# If you wish to use `gh`" + "Optionally, you can instansiate a GitHubGroup object and authenticate yourself by calling the following method." ] }, { "cell_type": "code", "execution_count": 2, - "metadata": {}, + "metadata": { + "language": "python" + }, "outputs": [ { "data": { "text/markdown": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L19){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L25){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", - "### command\n", + "### GitHubGroup.auth_github\n", "\n", - "> command (cmd:str)\n", + "> GitHubGroup.auth_github (credentials_fp:str)\n", "\n", - "Execute the given command in shell\n", + "Authenticate GitHub account with the provided credentials\n", "\n", "| | **Type** | **Details** |\n", "| -- | -------- | ----------- |\n", - "| cmd | str | command to call in bash |\n", - "| **Returns** | **(, )** | **success, output** |" + "| credentials_fp | str | the personal access token generated at GitHub Settings |" ], "text/plain": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L19){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L25){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", - "### command\n", + "### GitHubGroup.auth_github\n", "\n", - "> command (cmd:str)\n", + "> GitHubGroup.auth_github (credentials_fp:str)\n", "\n", - "Execute the given command in shell\n", + "Authenticate GitHub account with the provided credentials\n", "\n", "| | **Type** | **Details** |\n", "| -- | -------- | ----------- |\n", - "| cmd | str | command to call in bash |\n", - "| **Returns** | **(, )** | **success, output** |" + "| credentials_fp | str | the personal access token generated at GitHub Settings |" ] }, "execution_count": 2, @@ -134,107 +147,7 @@ "source": [ "#| echo: false\n", "#| output: asis\n", - "show_doc(command)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L36){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### check_gh_auth\n", - "\n", - "> check_gh_auth ()\n", - "\n", - "Check whether you have gh auth configured" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L36){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### check_gh_auth\n", - "\n", - "> check_gh_auth ()\n", - "\n", - "Check whether you have gh auth configured" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "#| echo: false\n", - "#| output: asis\n", - "show_doc(check_gh_auth)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L44){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### git_creat_repo_cmd\n", - "\n", - "> git_creat_repo_cmd (repo_name:str, repo_org:str, template_repo:str,\n", - "> private_repo=True)\n", - "\n", - "Generate the appropriate command for creating GitHub repository\n", - "\n", - "| | **Type** | **Default** | **Details** |\n", - "| -- | -------- | ----------- | ----------- |\n", - "| repo_name | str | | the name of the created repository |\n", - "| repo_org | str | | the GitHub organization name |\n", - "| template_repo | str | | the template repository that the new repo will use |\n", - "| private_repo | bool | True | the visibility of the repository |\n", - "| **Returns** | **str** | | **the command of repo creation** |" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L44){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### git_creat_repo_cmd\n", - "\n", - "> git_creat_repo_cmd (repo_name:str, repo_org:str, template_repo:str,\n", - "> private_repo=True)\n", - "\n", - "Generate the appropriate command for creating GitHub repository\n", - "\n", - "| | **Type** | **Default** | **Details** |\n", - "| -- | -------- | ----------- | ----------- |\n", - "| repo_name | str | | the name of the created repository |\n", - "| repo_org | str | | the GitHub organization name |\n", - "| template_repo | str | | the template repository that the new repo will use |\n", - "| private_repo | bool | True | the visibility of the repository |\n", - "| **Returns** | **str** | | **the command of repo creation** |" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "#| echo: false\n", - "#| output: asis\n", - "show_doc(git_creat_repo_cmd)" + "show_doc(GitHubGroup.auth_github)" ] }, { @@ -243,132 +156,74 @@ "metadata": { "language": "python" }, - "outputs": [], - "source": [ - "#| hide\n", - "test_eq(\n", - " 'gh repo create --template COGS108/group_template --private --clone COGS108/Group01_SP23',\n", - " git_creat_repo_cmd(\"Group01_SP23\", \"COGS108\", \"COGS108/group_template\")\n", - ")\n", - "test_eq(\n", - " 'gh repo create --private --clone COGS108/Group01_SP23',\n", - " git_creat_repo_cmd(\"Group01_SP23\", \"COGS108\", None)\n", - ")\n", - "test_eq(\n", - " 'gh repo create --clone COGS108/Group01_SP23',\n", - " git_creat_repo_cmd(\"Group01_SP23\", \"COGS108\", None, private_repo=False)\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, "outputs": [ { "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L59){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### git_manage_access_cmd\n", - "\n", - "> git_manage_access_cmd (repo_name:str, repo_org:str, collaorator_id:str,\n", - "> permission='push', add_team=False)\n", - "\n", - "GitHub CLI Command for modifying access priviliges of repo\n", - "\n", - "| | **Type** | **Default** | **Details** |\n", - "| -- | -------- | ----------- | ----------- |\n", - "| repo_name | str | | the name of the created repository |\n", - "| repo_org | str | | the GitHub organization name that the repo belongs to |\n", - "| collaorator_id | str | | the GitHub id of the collaborator, or team name if `add_team=True` |\n", - "| permission | str | push | the permission to that collaborator |\n", - "| add_team | bool | False | add access to github org's team |\n", - "| **Returns** | **str** | | **the command of repo creation** |" - ], "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L59){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### git_manage_access_cmd\n", - "\n", - "> git_manage_access_cmd (repo_name:str, repo_org:str, collaorator_id:str,\n", - "> permission='push', add_team=False)\n", - "\n", - "GitHub CLI Command for modifying access priviliges of repo\n", - "\n", - "| | **Type** | **Default** | **Details** |\n", - "| -- | -------- | ----------- | ----------- |\n", - "| repo_name | str | | the name of the created repository |\n", - "| repo_org | str | | the GitHub organization name that the repo belongs to |\n", - "| collaorator_id | str | | the GitHub id of the collaborator, or team name if `add_team=True` |\n", - "| permission | str | push | the permission to that collaborator |\n", - "| add_team | bool | False | add access to github org's team |\n", - "| **Returns** | **str** | | **the command of repo creation** |" + "'Scott Yang'" ] }, - "execution_count": 5, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "#| echo: false\n", - "#| output: asis\n", - "show_doc(git_manage_access_cmd)" + "g = GitHubGroup()\n", + "g.auth_github(\"../../credentials.json\")\n", + "g.github.get_user().name" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The team must be in the same organization with the repos' parent organization." + "## GitHub Organization Settings\n", + "\n", + "Usually, you want to create students repositories under a course GitHub organization. To set the target organization, you can call the following function." ] }, { "cell_type": "code", - "execution_count": 6, - "metadata": {}, + "execution_count": 3, + "metadata": { + "language": "python" + }, "outputs": [ { "data": { "text/markdown": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L74){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L35){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", - "### cd_cmd\n", + "### GitHubGroup.set_org\n", "\n", - "> cd_cmd (target_dir:str)\n", + "> GitHubGroup.set_org (org:str)\n", "\n", - "Unix command for change directory\n", + "Set the target organization for repo creation\n", "\n", "| | **Type** | **Details** |\n", "| -- | -------- | ----------- |\n", - "| target_dir | str | the target directory we want to change to |\n", - "| **Returns** | **str** | **the command of cd** |" + "| org | str | the target organization name |" ], "text/plain": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L74){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L35){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", - "### cd_cmd\n", + "### GitHubGroup.set_org\n", "\n", - "> cd_cmd (target_dir:str)\n", + "> GitHubGroup.set_org (org:str)\n", "\n", - "Unix command for change directory\n", + "Set the target organization for repo creation\n", "\n", "| | **Type** | **Details** |\n", "| -- | -------- | ----------- |\n", - "| target_dir | str | the target directory we want to change to |\n", - "| **Returns** | **str** | **the command of cd** |" + "| org | str | the target organization name |" ] }, - "execution_count": 6, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -376,117 +231,45 @@ "source": [ "#| echo: false\n", "#| output: asis\n", - "show_doc(cd_cmd)" + "show_doc(GitHubGroup.set_org)" ] }, { "cell_type": "code", - "execution_count": 7, - "metadata": {}, + "execution_count": null, + "metadata": { + "language": "python" + }, "outputs": [ { "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L80){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### git_rename_cmd\n", - "\n", - "> git_rename_cmd (source:str, target:str)\n", - "\n", - "GitHub mv command to rename file in the directory\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| source | str | the original name of the file |\n", - "| target | str | the target name of the file |\n", - "| **Returns** | **str** | **the command of git rename file** |" - ], "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L80){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### git_rename_cmd\n", - "\n", - "> git_rename_cmd (source:str, target:str)\n", - "\n", - "GitHub mv command to rename file in the directory\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| source | str | the original name of the file |\n", - "| target | str | the target name of the file |\n", - "| **Returns** | **str** | **the command of git rename file** |" + "Organization(login=\"COGS118A\")" ] }, - "execution_count": 7, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "#| echo: false\n", - "#| output: asis\n", - "show_doc(git_rename_cmd)" + "g.set_org(\"COGS118A\")\n", + "g.org" ] }, { - "cell_type": "code", - "execution_count": 8, + "cell_type": "markdown", "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L87){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### git_commit\n", - "\n", - "> git_commit (commit_msg:str)\n", - "\n", - "GitHub commit command\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| commit_msg | str | Commit Message |\n", - "| **Returns** | **str** | **the command for git commit** |" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L87){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### git_commit\n", - "\n", - "> git_commit (commit_msg:str)\n", - "\n", - "GitHub commit command\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| commit_msg | str | Commit Message |\n", - "| **Returns** | **str** | **the command for git commit** |" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ - "#| echo: false\n", - "#| output: asis\n", - "show_doc(git_commit)" + "## Create GitHub Group in one Call" ] }, { "cell_type": "code", - "execution_count": 9, - "metadata": {}, + "execution_count": 4, + "metadata": { + "language": "python" + }, "outputs": [ { "data": { @@ -495,21 +278,55 @@ "\n", "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L93){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", - "### git_add_all\n", + "### GitHubGroup.create_group_repo\n", + "\n", + "> GitHubGroup.create_group_repo (repo_name:str,\n", + "> collaborators:[],\n", + "> permission:str, rename_files={},\n", + "> repo_template='', private=True,\n", + "> description='')\n", + "\n", + "Create a Group Repository\n", "\n", - "> git_add_all ()" + "| | **Type** | **Default** | **Details** |\n", + "| -- | -------- | ----------- | ----------- |\n", + "| repo_name | str | | group repository name |\n", + "| collaborators | [] | | list of collaborators GitHub id |\n", + "| permission | str | | the permission of collaborators |\n", + "| rename_files | dict | {} | dictionary of files renames {:} |\n", + "| repo_template | str | | If empty string, an empty repo will be created. Put in the format of \"/\" |\n", + "| private | bool | True | visibility of the created repository |\n", + "| description | str | | description for the GitHub repository |\n", + "| **Returns** | **Repository** | | |" ], "text/plain": [ "---\n", "\n", "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L93){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", - "### git_add_all\n", + "### GitHubGroup.create_group_repo\n", + "\n", + "> GitHubGroup.create_group_repo (repo_name:str,\n", + "> collaborators:[],\n", + "> permission:str, rename_files={},\n", + "> repo_template='', private=True,\n", + "> description='')\n", "\n", - "> git_add_all ()" + "Create a Group Repository\n", + "\n", + "| | **Type** | **Default** | **Details** |\n", + "| -- | -------- | ----------- | ----------- |\n", + "| repo_name | str | | group repository name |\n", + "| collaborators | [] | | list of collaborators GitHub id |\n", + "| permission | str | | the permission of collaborators |\n", + "| rename_files | dict | {} | dictionary of files renames {:} |\n", + "| repo_template | str | | If empty string, an empty repo will be created. Put in the format of \"/\" |\n", + "| private | bool | True | visibility of the created repository |\n", + "| description | str | | description for the GitHub repository |\n", + "| **Returns** | **Repository** | | |" ] }, - "execution_count": 9, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -517,54 +334,29 @@ "source": [ "#| echo: false\n", "#| output: asis\n", - "show_doc(git_add_all)" + "show_doc(GitHubGroup.create_group_repo)" ] }, { "cell_type": "code", - "execution_count": 10, - "metadata": {}, + "execution_count": null, + "metadata": { + "language": "python" + }, "outputs": [ { "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L97){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### delete_directory\n", - "\n", - "> delete_directory (dir_name:str)\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| dir_name | str | the directory that we want to delete |\n", - "| **Returns** | **str** | **the command for delete dir** |" - ], "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L97){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### delete_directory\n", - "\n", - "> delete_directory (dir_name:str)\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| dir_name | str | the directory that we want to delete |\n", - "| **Returns** | **str** | **the command for delete dir** |" + ">" ] }, - "execution_count": 10, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "#| echo: false\n", - "#| output: asis\n", - "show_doc(delete_directory)" + "g.create_group_repo" ] }, { diff --git a/_proc/03_canvas_group_creation.ipynb b/_proc/03_canvas_group_creation.ipynb index 12238c6..0d6e079 100644 --- a/_proc/03_canvas_group_creation.ipynb +++ b/_proc/03_canvas_group_creation.ipynb @@ -208,6 +208,8 @@ "source": [ "# instansiate a new Canvas Group Object \n", "# if your class size is large, it will take around 2 minutes to grab all student info.\n", + "API_URL = \"https://canvas.ucsd.edu/\"\n", + "API_KEY = ...\n", "cg = CanvasGroup(API_URL, API_KEY, course_id=course_id)" ] }, @@ -318,7 +320,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that it will throw a Value Error if the target `in_group_category` did not exist in the course." + "Note that it will throw a Key Error if the target `in_group_category` did not exist in the course." ] }, { @@ -354,6 +356,13 @@ ")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following tutorial and examples demonstrates how to create and set a Group Category within a course context." + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -778,15 +787,6 @@ "member1 = \"email\"\n", "cg.join_canvas_group(group1, [member1])" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "language": "python" - }, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/_proc/_docs/canvas_group_creation.html b/_proc/_docs/canvas_group_creation.html index e6508fd..b9896c3 100644 --- a/_proc/_docs/canvas_group_creation.html +++ b/_proc/_docs/canvas_group_creation.html @@ -2,7 +2,7 @@ - + @@ -18,10 +18,9 @@ ul.task-list{list-style: none;} ul.task-list li input[type="checkbox"] { width: 0.8em; - margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + margin: 0 0.8em 0.2em -1.6em; vertical-align: middle; } -/* CSS for syntax highlighting */ pre > code.sourceCode { white-space: pre; position: relative; } pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } pre > code.sourceCode > span:empty { height: 1.2em; } @@ -48,13 +47,43 @@ -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; padding: 0 4px; width: 4em; + color: #aaaaaa; } -pre.numberSource { margin-left: 3em; padding-left: 4px; } +pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; } div.sourceCode { } @media screen { pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } } +code span.al { color: #ff0000; font-weight: bold; } /* Alert */ +code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */ +code span.at { color: #7d9029; } /* Attribute */ +code span.bn { color: #40a070; } /* BaseN */ +code span.bu { color: #008000; } /* BuiltIn */ +code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */ +code span.ch { color: #4070a0; } /* Char */ +code span.cn { color: #880000; } /* Constant */ +code span.co { color: #60a0b0; font-style: italic; } /* Comment */ +code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */ +code span.do { color: #ba2121; font-style: italic; } /* Documentation */ +code span.dt { color: #902000; } /* DataType */ +code span.dv { color: #40a070; } /* DecVal */ +code span.er { color: #ff0000; font-weight: bold; } /* Error */ +code span.ex { } /* Extension */ +code span.fl { color: #40a070; } /* Float */ +code span.fu { color: #06287e; } /* Function */ +code span.im { color: #008000; font-weight: bold; } /* Import */ +code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */ +code span.kw { color: #007020; font-weight: bold; } /* Keyword */ +code span.op { color: #666666; } /* Operator */ +code span.ot { color: #007020; } /* Other */ +code span.pp { color: #bc7a00; } /* Preprocessor */ +code span.sc { color: #4070a0; } /* SpecialChar */ +code span.ss { color: #bb6688; } /* SpecialString */ +code span.st { color: #4070a0; } /* String */ +code span.va { color: #19177c; } /* Variable */ +code span.vs { color: #4070a0; } /* VerbatimString */ +code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */ @@ -115,62 +144,47 @@ CanvasGroupy -
-
-
-
-

Note that it will throw a Value Error if the target in_group_category did not exist in the course.

+

Note that it will throw a Key Error if the target in_group_category did not exist in the course.

cg.assign_canvas_group(
     group_name="Failed",
@@ -406,6 +422,7 @@ 

CanvasGrou
KeyError: 'Group Project 2 did not found in the group categories.\n Try to create one with CanvasGroup.create_group_category'

+

The following tutorial and examples demonstrates how to create and set a Group Category within a course context.

@@ -638,23 +655,9 @@

CanvasGroup. icon: icon }; anchorJS.add('.anchored'); - const isCodeAnnotation = (el) => { - for (const clz of el.classList) { - if (clz.startsWith('code-annotation-')) { - return true; - } - } - return false; - } const clipboard = new window.ClipboardJS('.code-copy-button', { - text: function(trigger) { - const codeEl = trigger.previousElementSibling.cloneNode(true); - for (const childEl of codeEl.children) { - if (isCodeAnnotation(childEl)) { - childEl.remove(); - } - } - return codeEl.innerText; + target: function(trigger) { + return trigger.previousElementSibling; } }); clipboard.on('success', function(e) { @@ -719,92 +722,6 @@

CanvasGroup. return note.innerHTML; }); } - let selectedAnnoteEl; - const selectorForAnnotation = ( cell, annotation) => { - let cellAttr = 'data-code-cell="' + cell + '"'; - let lineAttr = 'data-code-annotation="' + annotation + '"'; - const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; - return selector; - } - const selectCodeLines = (annoteEl) => { - const doc = window.document; - const targetCell = annoteEl.getAttribute("data-target-cell"); - const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); - const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); - const lines = annoteSpan.getAttribute("data-code-lines").split(","); - const lineIds = lines.map((line) => { - return targetCell + "-" + line; - }) - let top = null; - let height = null; - let parent = null; - if (lineIds.length > 0) { - //compute the position of the single el (top and bottom and make a div) - const el = window.document.getElementById(lineIds[0]); - top = el.offsetTop; - height = el.offsetHeight; - parent = el.parentElement.parentElement; - if (lineIds.length > 1) { - const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); - const bottom = lastEl.offsetTop + lastEl.offsetHeight; - height = bottom - top; - } - if (top !== null && height !== null && parent !== null) { - // cook up a div (if necessary) and position it - let div = window.document.getElementById("code-annotation-line-highlight"); - if (div === null) { - div = window.document.createElement("div"); - div.setAttribute("id", "code-annotation-line-highlight"); - div.style.position = 'absolute'; - parent.appendChild(div); - } - div.style.top = top - 2 + "px"; - div.style.height = height + 4 + "px"; - let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); - if (gutterDiv === null) { - gutterDiv = window.document.createElement("div"); - gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); - gutterDiv.style.position = 'absolute'; - const codeCell = window.document.getElementById(targetCell); - const gutter = codeCell.querySelector('.code-annotation-gutter'); - gutter.appendChild(gutterDiv); - } - gutterDiv.style.top = top - 2 + "px"; - gutterDiv.style.height = height + 4 + "px"; - } - selectedAnnoteEl = annoteEl; - } - }; - const unselectCodeLines = () => { - const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; - elementsIds.forEach((elId) => { - const div = window.document.getElementById(elId); - if (div) { - div.remove(); - } - }); - selectedAnnoteEl = undefined; - }; - // Attach click handler to the DT - const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); - for (const annoteDlNode of annoteDls) { - annoteDlNode.addEventListener('click', (event) => { - const clickedEl = event.target; - if (clickedEl !== selectedAnnoteEl) { - unselectCodeLines(); - const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); - if (activeEl) { - activeEl.classList.remove('code-annotation-active'); - } - selectCodeLines(clickedEl); - clickedEl.classList.add('code-annotation-active'); - } else { - // Unselect the line - unselectCodeLines(); - clickedEl.classList.remove('code-annotation-active'); - } - }); - } const findCites = (el) => { const parentEl = el.parentElement; if (parentEl) { diff --git a/_proc/_docs/core.html b/_proc/_docs/core.html index 493578e..9802f03 100644 --- a/_proc/_docs/core.html +++ b/_proc/_docs/core.html @@ -2,7 +2,7 @@ - + @@ -18,10 +18,9 @@ ul.task-list{list-style: none;} ul.task-list li input[type="checkbox"] { width: 0.8em; - margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + margin: 0 0.8em 0.2em -1.6em; vertical-align: middle; } -/* CSS for syntax highlighting */ pre > code.sourceCode { white-space: pre; position: relative; } pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } pre > code.sourceCode > span:empty { height: 1.2em; } @@ -48,13 +47,43 @@ -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; padding: 0 4px; width: 4em; + color: #aaaaaa; } -pre.numberSource { margin-left: 3em; padding-left: 4px; } +pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; } div.sourceCode { } @media screen { pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } } +code span.al { color: #ff0000; font-weight: bold; } /* Alert */ +code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */ +code span.at { color: #7d9029; } /* Attribute */ +code span.bn { color: #40a070; } /* BaseN */ +code span.bu { color: #008000; } /* BuiltIn */ +code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */ +code span.ch { color: #4070a0; } /* Char */ +code span.cn { color: #880000; } /* Constant */ +code span.co { color: #60a0b0; font-style: italic; } /* Comment */ +code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */ +code span.do { color: #ba2121; font-style: italic; } /* Documentation */ +code span.dt { color: #902000; } /* DataType */ +code span.dv { color: #40a070; } /* DecVal */ +code span.er { color: #ff0000; font-weight: bold; } /* Error */ +code span.ex { } /* Extension */ +code span.fl { color: #40a070; } /* Float */ +code span.fu { color: #06287e; } /* Function */ +code span.im { color: #008000; font-weight: bold; } /* Import */ +code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */ +code span.kw { color: #007020; font-weight: bold; } /* Keyword */ +code span.op { color: #666666; } /* Operator */ +code span.ot { color: #007020; } /* Other */ +code span.pp { color: #bc7a00; } /* Preprocessor */ +code span.sc { color: #4070a0; } /* SpecialChar */ +code span.ss { color: #bb6688; } /* SpecialString */ +code span.st { color: #4070a0; } /* String */ +code span.va { color: #19177c; } /* Variable */ +code span.vs { color: #4070a0; } /* VerbatimString */ +code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */ @@ -115,68 +144,52 @@ CanvasGroupy -
-
-
- -
- -
- -
-