github / gh-classroom

GitHub Classroom CLI Extension is a powerful and easy-to-use command line tool that enhances the functionality of the GitHub CLI, specifically tailored for educators using GitHub Classroom.
MIT License
83 stars 14 forks source link

Feature request: add `submit` command #19

Open zrdaley opened 1 year ago

zrdaley commented 1 year ago

Premise

Git is hard for students in introductory courses (e.g., CS1). Particularly at term's start, when commands like

python foo.py

or

gcc foo.c
./a.out

are already quite new to many students (and complicated if something goes wrong), it's just not compelling to add the cognitive overhead of, or instructional time for, commands like

git add
git commit
git push

in the earliest days of a course, particularly if Git, early on, is used primarily for submitting work (and not yet for actual collaboration or versioning).

Much like computer science itself teaches abstraction, and much like instructional scaffolding characterizes many curricula, so can (and, daresay, should) Git be abstracted away until such time as a teacher's students are ready for lessons in Git itself.

Solution

Provide students with a gh classroom submit command that automates the requisite git-add, git-commit, and git-push commands via which to submit their work, executed a la

gh classroom submit ORG/REPO [DIR]

or

gh classroom submit ORG/REPO@BRANCH [DIR]

wherein ORG is a teacher's org (for GitHub Classroom), REPO is a student's repo therein, BRANCH is an optional branch therein, and DIR is the directory to submit (i.e., push to the remote repo), which would default to $PWD.

Alternatively, per @octosteve, a student could be prompted interactively to select an assignment to submit.

Implementation Details

Underneath the hood, gh-classroom-submit would be a GitHub CLI extension:

  1. Clone a student's repo to, e.g., /tmp (and optionally check out a particular branch).
  2. Effectively remove the contents thereof.
  3. Copy the contents of $PWD to that directory, git adding and committing the same.
  4. Push the commit back to the remote repo.

For maximum compatibility and ease of installation, probably best if gh-classroom-submit is implemented as an interpreted extension in Python and distributed via PyPI. That way, students can use it having just Python on their PC or Mac, without additionally needing the GitHub CLI itself, installation of which could be a tad more involved, especially for less comfortable students.

Alternatively, if interactive prompts are compelling, using Go might be best, if only to use the same terminal-based GUI libraries that other extensions are using. Pre-installation in students' Codespaces, too, would be trivial to automate.

Pseudocode

Assumes $ORG, $REPO, and optionally $BRANCH are already set, as via command-line arguments or sensible defaults.

#!/usr/bin/bash

# We'll clone a bare repo here
export GIT_DIR=$(mktemp -d)

# We'll assume the student's work is in $PWD
export GIT_WORK_TREE="$PWD"

# Clone the remote's .git directory
git clone --bare "git@github.com:$ORG/$REPO" "$GIT_DIR"

# We'll "submit" to this branch
git symbolic-ref HEAD "refs/heads/$BRANCH"

# Let's check out the teacher's .gitignore from the student's remote clone thereof
git checkout main .gitignore

# Let's add everything from $PWD, modulo the .gitignore
git add --all

# Represent this submission with a commit
git commit --allow-empty --allow-empty-message --message ""

# Push the submission to the remote branch
git push origin "refs/heads/$BRANCH"

Upsides

This approach would avoid any merge conflicts altogether (by first cloning the remote repo), as might (all too frequently) happen if a student accepts an assignment, clones the repo locally, starts to make changes locally, and unwittingly then makes changes (and commits) remotely, as via GitHub.com's pencil icon.

Students also have a habit of deleting things they shouldn't, if only because they don't recognize them (e.g., a .git directory in their local clone). Alternatively, if students happen to create a new folder locally into which they cp their work (not realizing their original folder also had a "hidden" .git folder), they might end up without a local repo altogether from which to push. (And the solution then would be a convoluted, manual git-clone, then an rm, then another cp or mv or the like, every step of which would (all too frequently) be fraught with potential pitfalls.

To reduce the probability of mistakes and FAQs, then, much better to automate and abstract (at least at term's start) the submission process entirely.

Alternatives

To resolve cases in which students have induced merge conflicts, as by editing a file on GitHub.com via the pencil icon but wanting to submit different code locally, we could force-push. But any solution that risks overwriting history and/or losing work isn't ideal and is best to avoid.

Similarly could we try to resolve what would otherwise be merge conflicts with -Xours, but that, too, would risk overwriting remote work that would be best to preserve.

Alternatively still, if a student's state resembles

remote:  A - B - C
local:       \ D - E

we could try to achieve

remote: A - B - C - F
local: A - B - C - F

wherein F == E, but that would overwrite local history (i.e., commits), which is likely to confuse students who consciously made those local commits.

Best, then, for gh-classroom-submit to be a consistent abstraction, ignoring the local repo (i.e., .git) altogether and worrying only about getting the student's local code to the remote, without losing history locally or remotely. A student could thus actually use Git locally, particularly when learning it for the first time. But submissions would be entirely independent of that local history.

In cases where a student (or teacher) wants students local commits to be reflected in their remote repo, that's when it's time for the "training wheels" to come off, replacing the abstraction that is gh-classroom-submit with actual git commands that students themselves execute.