Creating issues in github classrooms


(Buskcoin) #1

Hello all,

This is sort of a feature request and I am curious what the community’s thoughts are.
From my experience, the way github is used in the real world often involves issues being created and, in turn, programmers responding to the issues and making pull request.

I would like to simulate the same scenarios for my classes. I think it would be great to get them in the habit of using github’s issues system to add features to a simple program. For example, I could have an incomplete program with several small issues attached to it and have the students take up issues and complete the assignment collaboratively.

Currently, I would have to recreate the issues on the repository every time I have the students accept the Github Classroom assignment because issues are not copied over. What I would really love to have is the ability to tag issues for a repository that I want the students to receive in their sandbox copy of the repository. This is the feature that I would like to have.

Hopefully that makes sense. I wanted to propose the idea here before I made a feature request on the actual github classroom repository to see if anyone else thinks it’s worth it.
:grinning:
Keith


(Joel Ross) #2

Just wanted to chime in that I love this idea. I don’t do a lot of issue stuff when teaching, but this does sound like a really useful feature.


(Thomas Flucke) #3

I am currently working on writing a course curriculum for debugging strategies. Our current plan was to have students clone a repository with a list of bugs in the form of issues and have them submit pull requests, exactly like what you described.

I was sorely disappointed to find out that the issues weren’t cloned. We’re working on a script now to automatically add issues but this really seems like something that should part of classroom.


(Buskcoin) #4

I am glad to hear that more people are interested in this feature. If you can share the script, It would be greatly appreciated.

Thanks


(Thomas Flucke) #5

We just finished the integration testing. Here’s what we have:

handle_hook.sh

#!/bin/bash

# @param1 path to config file

# Processes HTTP POST requests from github web hooks

# config file format:
# {
#     "authtoken": "<Github auth token>",
#     "log_mode": "normal",
#     "assignments": {
#         "<Assignment name>": {
#             "ref": "<repo owner>/<repo name>",
#             "copy": [
#                 "issues",
#                 "hooks",
#                 "protection"
#             ]
#         },
#         "<Assignment name>": {
#             "ref": "<repo owner>/<repo name>",
#             "copy": []
#         }
#     }    
# }

shopt -s xpg_echo

CONFIG_FILE="$1"

if [ ! -f "$CONFIG_FILE" ]; then
    echo "Cannot find file '$CONFIG_FILE'." 1>&2
    exit 1
elif [ ! -r "$CONFIG_FILE" ]; then
    echo "Cannot open '$CONFIG_FILE' for reading." 1>&2
    exit 1
fi

if ! which curl > /dev/null; then
    echo "curl is not installed." 1>&2
    exit 1
elif ! which jq > /dev/null; then
    echo "jq is not installed." 1>&2
    exit 1
fi

LOG_MODE=$(jq -rc '.log_mode' "$CONFIG_FILE")
if [ "$LOG_MODE" != "silent" -o \
                 "$LOG_MODE" != "normal" -o \
                 "$LOG_MODE" != "debug" -o \
                 "$LOG_MODE" != "verbose" ]; then
    LOG_MODE="normal"
fi
export LOG_MODE

TOKEN=$(jq -rc '.authtoken' "$CONFIG_FILE")
if [ "$?" -ne 0 -o "$TOKEN" = "" -o "$TOKEN" = "null" ]; then
    echo "Cannot read 'authtoken' from '$CONFIG_FILE'." 1>&2
    exit 1
fi
if [ "$LOG_MODE" = "debug" ]; then
    echo "Using oauth token $TOKEN"
fi

PAYLOAD=$(jq -Mc '.')
if [ "$?" -ne 0 ]; then
    echo "Cannot read json from stdin." 1>&2
    exit 1
fi
if [ "$LOG_MODE" = "verbose" ]; then
    echo "Processing Payload:"
    echo -E "$PAYLOAD"
fi

ACTION="$(echo -E "$PAYLOAD" | jq -rc '.action')"
if [ "$LOG_MODE" = "debug" ]; then
    echo "Action: $ACTION"
fi
REPO_NAME="$(echo -E "$PAYLOAD" | jq -rc '.repository.full_name')"
if [ "$LOG_MODE" = "verbose" ]; then
    echo "Repository name: $REPO_NAME"
fi
ASSIGNMENT_NAME="$(echo "$REPO_NAME" | cut -d/ -f2 | grep -Eo '.*-' | head -c-2)"
if [ "$LOG_MODE" = "debug" ]; then
    echo "Assignment name: $ASSIGNMENT_NAME"
fi
ASSIGNMENT_CONF="$(jq ".assignments[\"$ASSIGNMENT_NAME\"]" $CONFIG_FILE)"
if [ "$LOG_MODE" = "verbose" ]; then
    echo "Assignment config:"
    echo -E "$ASSIGNMENT_CONF"
fi

case "$ACTION" in
    "created")
        "$(dirname "$0")/init_repo.sh" \
            "$TOKEN" \
            "$(echo "$ASSIGNMENT_CONF" | jq -r '.ref')" \
            "$REPO_NAME" \
            "$(echo "$ASSIGNMENT_CONF" | jq -rc '.copy[]')"
        ;;
    *)
        echo "Unknown action: '$ACTION'" 1>&2
        ;;
esac

init_repo.sh

#!/bin/bash

# Copy set of properties from one repository to another.

# @param1 Auth Token obtained from Developer Settings in Github
# @param2 {origin usr}/{origin repo}
# @param3 {copied usr}/{copied repo}
# @param4 (optional) List of things to copy.  Can be:
#  issues
#  hooks
#  protection

TOKEN="$1"
REF="$2"
TARG="$3"
TO_COPY="${4-issues hooks protection}"

shopt -s xpg_echo

if ! which curl > /dev/null; then
    echo "curl is not installed." 1>&2
    exit 1
elif ! which jq > /dev/null; then
    echo "jq is not installed." 1>&2
    exit 1
fi

copyIssues() {
    # @param1 Additional curl flags for sending the request

    ISSUES="$(curl -sH "Authorization: token $TOKEN" https://api.github.com/repos/$REF/issues)"
    if [ "$?" -ne 0 ]; then
        echo "Error: Could not fetch issue information." 1>&2
        echo "$ISSUE" 1>&2
        exit 1
    fi
    for i in $(seq 0 $(expr $(echo -E "$ISSUES" | jq '. | length') - 1)) ; do
        curl $1 -i -d "$(echo -E "$ISSUES" | jq ".[$i] | {title, body, assignee, milestone, labels}")" \
             -H "Authorization: token $TOKEN" -X POST "https://api.github.com/repos/$TARG/issues" > /dev/null
    done
}

copyHooks() {
    # @param1 Additional curl flags for sending the request

    HOOKS="$(curl -sH "Authorization: token $TOKEN" https://api.github.com/repos/$REF/hooks)"
    if [ "$?" -ne 0 ]; then
        echo "Error: Could not fetch hook information." 1>&2
        echo "$HOOKS" 1>&2
        exit 1
    fi
    for i in $(seq 0 $(expr $(echo -E "$HOOKS" | jq '. | length') - 1)) ; do
        curl $1 -i -d "$(echo -E "$HOOKS")" \
             -sH "Authorization: token $TOKEN" -X POST "https://api.github.com/repos/$TARG/hooks" > /dev/null
    done
}

copyProtections() {
    # @param1 Additional curl flags for sending the request
    
    PROTECT="$(curl -sH "Authorization: token $TOKEN" https://api.github.com/repos/$REF/branches/master/protection)"
    if [ "$?" -ne 0 ]; then
        echo "Error: Could not fetch branch protection information." 1>&2
        echo "$PROTECT" 1>&2
        exit 1
    fi
    PROTECT_BODY="$(echo -E "$PROTECT" |
                     jq '{required_status_checks, enforce_admins:
                     (if .enforce_admins != null then true else null end),
                     required_pull_request_reviews, restrictions}')"
    curl $1 -i -d "$PROTECT_BODY" -sH "Authorization: token $TOKEN" \
         -X PUT "https://api.github.com/repos/$TARG/branches/master/protection" > /dev/null
}

if [ "$LOG_MODE" = "verbose" ]; then
    echo "Initializing new repository"
    echo "Copying:"
    echo -E "$TO_COPY"
    echo "from $REF to $TARG"
fi

for mode in $TO_COPY; do
    case "$mode" in
        "issues")
            copyIssues "-s"
            ;;
        "hooks")
            copyHooks "-s"
            ;;
        "protection")
            copyProtections "-s"
            ;;
        *)
            echo "Unknown copy parameter: '$mode'" 1>&2
            ;;
    esac
done

This script requires you have curl and jq installed. Be set this up with a CGI script and linked it to repository hooks for our github organization.


(Buskcoin) #6

Awesome! I will play with this. Thank you.


(Michael Cullen) #7

I agree - My comments on another thread