From 5c635b554e15591a7eb50b4dc6257feab2ab4a75 Mon Sep 17 00:00:00 2001
From: "github-classroom[bot]"
<66690702+github-classroom[bot]@users.noreply.github.com>
Date: Tue, 27 Feb 2024 01:37:27 +0000
Subject: [PATCH] Initial commit
---
.github/activity-icons/activity1.svg | 4 +
.github/activity-icons/activity2.svg | 4 +
.github/activity-icons/activity3.svg | 4 +
.github/activity-icons/points-bar.svg | 13 +
.github/activity-icons/quiz.svg | 4 +
.github/classroom/autograding.json | 84 ++++
.github/grading-scripts/quiz.sh | 48 ++
.github/scripts/escape.sh | 5 +
.github/templates/activity-completed.svg | 14 +
.github/templates/activity-incomplete.svg | 4 +
.github/templates/pr_body.md | 1 +
.github/templates/pr_feedback.md | 69 +++
.github/templates/quiz.svg | 5 +
.github/templates/quiz5.svg | 12 +
.github/workflows/classroom.yml | 511 ++++++++++++++++++++++
LICENSE | 21 +
README.md | 122 ++++++
editme.md | 3 +
quiz.md | 62 +++
19 files changed, 990 insertions(+)
create mode 100644 .github/activity-icons/activity1.svg
create mode 100644 .github/activity-icons/activity2.svg
create mode 100644 .github/activity-icons/activity3.svg
create mode 100644 .github/activity-icons/points-bar.svg
create mode 100644 .github/activity-icons/quiz.svg
create mode 100644 .github/classroom/autograding.json
create mode 100644 .github/grading-scripts/quiz.sh
create mode 100644 .github/scripts/escape.sh
create mode 100644 .github/templates/activity-completed.svg
create mode 100644 .github/templates/activity-incomplete.svg
create mode 100644 .github/templates/pr_body.md
create mode 100644 .github/templates/pr_feedback.md
create mode 100644 .github/templates/quiz.svg
create mode 100644 .github/templates/quiz5.svg
create mode 100644 .github/workflows/classroom.yml
create mode 100644 LICENSE
create mode 100644 README.md
create mode 100644 editme.md
create mode 100644 quiz.md
diff --git a/.github/activity-icons/activity1.svg b/.github/activity-icons/activity1.svg
new file mode 100644
index 0000000..33e6199
--- /dev/null
+++ b/.github/activity-icons/activity1.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/.github/activity-icons/activity2.svg b/.github/activity-icons/activity2.svg
new file mode 100644
index 0000000..33e6199
--- /dev/null
+++ b/.github/activity-icons/activity2.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/.github/activity-icons/activity3.svg b/.github/activity-icons/activity3.svg
new file mode 100644
index 0000000..33e6199
--- /dev/null
+++ b/.github/activity-icons/activity3.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/.github/activity-icons/points-bar.svg b/.github/activity-icons/points-bar.svg
new file mode 100644
index 0000000..d46c6b5
--- /dev/null
+++ b/.github/activity-icons/points-bar.svg
@@ -0,0 +1,13 @@
+
diff --git a/.github/activity-icons/quiz.svg b/.github/activity-icons/quiz.svg
new file mode 100644
index 0000000..33948d6
--- /dev/null
+++ b/.github/activity-icons/quiz.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.github/classroom/autograding.json b/.github/classroom/autograding.json
new file mode 100644
index 0000000..2f60971
--- /dev/null
+++ b/.github/classroom/autograding.json
@@ -0,0 +1,84 @@
+{
+ "tests": [
+ {
+ "name": "Activity 1 - Accept assignment",
+ "setup": "",
+ "run": "[ -e .github/results/activity1.txt ] && exit 0 || exit 1",
+ "input": "",
+ "output": "",
+ "comparison": "included",
+ "timeout": 10,
+ "points": 5
+ },
+ {
+ "name": "Activity 2 - Make commit",
+ "setup": "",
+ "run": "[ -e .github/results/activity2.txt ] && exit 0 || exit 1",
+ "input": "",
+ "output": "",
+ "comparison": "included",
+ "timeout": 10,
+ "points": 5
+ },
+ {
+ "name": "Activity 3 - Comment on PR",
+ "setup": "",
+ "run": "[ -e .github/results/activity3.txt ] && exit 0 || exit 1",
+ "input": "",
+ "output": "",
+ "comparison": "included",
+ "timeout": 10,
+ "points": 5
+ },
+ {
+ "name": "Quiz - Question 1",
+ "setup": "",
+ "run": "/bin/bash .github/grading-scripts/quiz.sh 1",
+ "input": "",
+ "output": "",
+ "comparison": "included",
+ "timeout": 10,
+ "points": 1
+ },
+ {
+ "name": "Quiz - Question 2",
+ "setup": "",
+ "run": "/bin/bash .github/grading-scripts/quiz.sh 2",
+ "input": "",
+ "output": "",
+ "comparison": "included",
+ "timeout": 10,
+ "points": 1
+ },
+ {
+ "name": "Quiz - Question 3",
+ "setup": "",
+ "run": "/bin/bash .github/grading-scripts/quiz.sh 3",
+ "input": "",
+ "output": "",
+ "comparison": "included",
+ "timeout": 10,
+ "points": 1
+ },
+ {
+ "name": "Quiz - Question 4",
+ "setup": "",
+ "run": "/bin/bash .github/grading-scripts/quiz.sh 4",
+ "input": "",
+ "output": "",
+ "comparison": "included",
+ "timeout": 10,
+ "points": 1
+ },
+ {
+ "name": "Quiz - Question 5",
+ "setup": "",
+ "run": "/bin/bash .github/grading-scripts/quiz.sh 5",
+ "input": "",
+ "output": "",
+ "comparison": "included",
+ "timeout": 10,
+ "points": 1
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.github/grading-scripts/quiz.sh b/.github/grading-scripts/quiz.sh
new file mode 100644
index 0000000..392c5b0
--- /dev/null
+++ b/.github/grading-scripts/quiz.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+#
+# param
+# $1 - question number
+
+expected=(2 2 3 4 3)
+# echo ${#expected[@]}
+
+# check quiz file exists
+if [ ! -e quiz.md ]; then
+ echo "Error: quiz file missing"
+ exit 1
+fi
+
+# IFS_backup=$IFS
+# IFS=$'\n'
+answers=($(grep -e "^Answer:" quiz.md | cut -d ':' -f 2 | tr -d "[:blank:]" | sed 's/.*/"&"/'))
+# IFS=$IFS_backup
+# echo ${#answers[@]}
+
+if [[ ${#answers[@]} != 5 ]]; then
+ echo "Error: wrong number of answers in quiz file"
+ exit 1
+fi
+
+score=0
+incorrect=''
+if [ $1 ]; then
+ if [[ $(echo ${answers[$1 - 1]} | xargs) == "${expected[$1 - 1]}"* ]]; then
+ echo "Question $1 answered correctly."
+ echo "pass"
+ else
+ echo "Question $1 incorrect."
+ exit 1
+ fi
+else
+ for i in "${!expected[@]}"; do
+ if [[ $(echo ${answers[$i]} | xargs) == "${expected[$i]}"* ]]; then
+ echo "Question $(( $i+1 )) answered correctly."
+ ((score+=1))
+ else
+ incorrect="$incorrect$(( $i+1 )) "
+ echo "Question $(( $i+1 )) incorrect."
+ fi
+ done
+ echo "::set-output name=quiz_score::$score"
+ echo "::set-output name=incorrect_answers::$incorrect"
+fi
diff --git a/.github/scripts/escape.sh b/.github/scripts/escape.sh
new file mode 100644
index 0000000..9232405
--- /dev/null
+++ b/.github/scripts/escape.sh
@@ -0,0 +1,5 @@
+text="$1"
+text="${text//$'%'/%25}"
+text="${text//$'\n'/'%0A'}"
+text="${text//$'\r'/%0D}"
+echo "$text"
\ No newline at end of file
diff --git a/.github/templates/activity-completed.svg b/.github/templates/activity-completed.svg
new file mode 100644
index 0000000..06d9725
--- /dev/null
+++ b/.github/templates/activity-completed.svg
@@ -0,0 +1,14 @@
+
+ Activity: completed
+
+
+ Completed
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.github/templates/activity-incomplete.svg b/.github/templates/activity-incomplete.svg
new file mode 100644
index 0000000..33e6199
--- /dev/null
+++ b/.github/templates/activity-incomplete.svg
@@ -0,0 +1,4 @@
+
+ Activity: incomplete
+
+
\ No newline at end of file
diff --git a/.github/templates/pr_body.md b/.github/templates/pr_body.md
new file mode 100644
index 0000000..b474dfe
--- /dev/null
+++ b/.github/templates/pr_body.md
@@ -0,0 +1 @@
+This pull request was created as a place for your teacher to leave feedback on your work.
\ No newline at end of file
diff --git a/.github/templates/pr_feedback.md b/.github/templates/pr_feedback.md
new file mode 100644
index 0000000..a04eb63
--- /dev/null
+++ b/.github/templates/pr_feedback.md
@@ -0,0 +1,69 @@
+---
+status-success: ':white_check_mark:'
+status-fail: ':x:'
+activity1-success:
+activity1-fail: |
+ This assignment is designed to be run via [GitHub Classroom](https://classroom.github.com). If you got here without being given an assignment URL from your teacher, please speak to your teacher about setting up a [Classroom assignment](https://docs.github.com/en/education/manage-coursework-with-github-classroom/teach-with-github-classroom/create-an-individual-assignment).
+
+ If your teacher did give you an assignment URL and you still got this message, there is probably a bug in the marking code. Please submit an issue to https://github.com/markpatterson27/GitHub-Classroom-Introductory-Assignment/issues describing the issue (preferably including a link back to _your_ assignment repo).
+activity2-success: Yay. You made a commit.
+activity2-fail: |
+ A commit authored by you has not been found.
+
+ How to make a git commit
+
+ **Clone** - [Clone](https://github.com/git-guides/git-clone) the repository to your local machine.
+
+ \`\`\`
+ git clone https://github.com/${GITHUB_REPOSITORY}.git
+ \`\`\`
+
+ **Edit** - Edit and save the files.
+
+ \`\`\`
+ cd ${REPO_NAME}
+ code editme.md
+ \`\`\`
+
+ **Add** - [Add](https://github.com/git-guides/git-add) the changes to staging.
+
+ \`\`\`
+ git add editme.md
+ \`\`\`
+
+ **Commit** - [Commit](https://github.com/git-guides/git-commit) the changes to the git repo.
+
+ \`\`\`
+ git commit -m \"asked a question in editme.md\"
+ \`\`\`
+
+ **Push** - [Push](https://github.com/git-guides/git-push) the new commits back to the remote repository.
+
+ \`\`\`
+ git push origin main
+ \`\`\`
+
+activity3-success: Interesting comment.
+activity3-fail: Leave a comment below.
+quiz-success: Five out of five. All questions answered correctly. Well done.
+---
+
+## Auto-Feedback
+
+### ${status-activity1} Activity 1 - Accept assignment
+
+${fb-activity1}
+
+### ${status-activity2} Activity 2 - Make commit
+
+${fb-activity2}
+
+### ${status-activity3} Activity 3 - Comment on Feedback PR
+
+${fb-activity3}
+
+### ${status-quiz} Quiz
+
+${fb-quiz}
+
+Autograding Score: ${points}
diff --git a/.github/templates/quiz.svg b/.github/templates/quiz.svg
new file mode 100644
index 0000000..c2b3932
--- /dev/null
+++ b/.github/templates/quiz.svg
@@ -0,0 +1,5 @@
+
+ Quiz Score:
+
+ 0
+
\ No newline at end of file
diff --git a/.github/templates/quiz5.svg b/.github/templates/quiz5.svg
new file mode 100644
index 0000000..ee4fd7e
--- /dev/null
+++ b/.github/templates/quiz5.svg
@@ -0,0 +1,12 @@
+
+ Quiz Score: completed
+ Completed
+
+
+
+
+
+
+ 5
+
+
diff --git a/.github/workflows/classroom.yml b/.github/workflows/classroom.yml
new file mode 100644
index 0000000..86a045d
--- /dev/null
+++ b/.github/workflows/classroom.yml
@@ -0,0 +1,511 @@
+name: GitHub Classroom Workflow
+
+on:
+ push:
+ branches:
+ - '*'
+ - '!status'
+ - '!feedback'
+
+ # Allows you to run this workflow manually from the Actions tab
+ workflow_dispatch:
+
+ issue_comment:
+ types: [created]
+
+jobs:
+ # job to run autograding
+ build:
+ name: Autograding
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ if: ${{ !(github.event_name == 'issue_comment') || contains(github.event.repository.name, github.actor) }}
+ steps:
+ - uses: actions/checkout@v2
+
+ # pause to wait for classroom bot to setup feedback PR
+ - if: ${{ github.actor == 'github-classroom[bot]' }}
+ run: sleep 30
+
+ # Default branch is usually 'main', but in case it isn't get default branch name
+ - name: Get default branch name
+ uses: actions/github-script@v5
+ id: default-branch-name
+ with:
+ github-token: ${{secrets.GITHUB_TOKEN}}
+ script: |
+ // get default branch
+ const repo = await github.rest.repos.get({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ });
+ console.log(`Get repo response - status: ${repo.status}`);
+ return repo.data.default_branch;
+ result-encoding: string
+ - run: echo "Default branch name - ${{ steps.default-branch-name.outputs.result }}"
+
+ # find PR if it exists
+ - name: Find PR number
+ uses: markpatterson27/find-pull-request-action@pre-pr-release
+ id: check-pr
+ with:
+ github-token: ${{secrets.GITHUB_TOKEN}}
+ title: Feedback
+ base: feedback
+ branch: ${{ steps.default-branch-name.outputs.result }}
+ state: all
+ - run: echo ${{ steps.check-pr.outputs.number }}
+
+ # re-open PR if closed
+ - name: Reopen PR
+ if: ${{ steps.check-pr.outputs.state == 'closed' }}
+ uses: actions/github-script@v5
+ env:
+ PR_NUMBER: ${{ steps.check-pr.outputs.number }}
+ with:
+ github-token: ${{secrets.GITHUB_TOKEN}}
+ script: |
+ try {
+ await github.rest.pulls.update({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ pull_number: process.env.PR_NUMBER,
+ state: 'open'
+ });
+ } catch(err) {
+ console.log("Error reopening PR. (Merged PRs can't be reopened).");
+ }
+
+ # delete and recreate result dir
+ - name: Reset results dir
+ run: |
+ rm -rf .github/results
+ mkdir -p .github/results
+
+ # test activity 1
+ - uses: actions/github-script@v4
+ name: "Check Activity 1"
+ id: activity1
+ with:
+ github-token: ${{secrets.GITHUB_TOKEN}}
+ script: |
+ // get repo name
+ const repoName = context.repo.repo.toLowerCase()
+
+ // get repo members
+ const res = await github.repos.listCollaborators({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ });
+ let collaborators = res.data
+ console.log(collaborators)
+
+ // check if one of collab list matches repository name suffix. make case insensitive.
+ // pattern is `assignmentname-username` or `assignmentname-username-i`. #TODO: optionally remove number suffix and use endsWith to match
+ if (collaborators.some(collaborator=>repoName.includes(collaborator.login.toLowerCase()))) {
+ console.log("found collaborator match to repo suffix")
+
+ // write result to file
+ const fs = require('fs');
+ fs.writeFile('.github/results/activity1.txt', 'pass', function (err) {
+ if (err) return console.log(err);
+ });
+
+ return 'success'
+ }
+ else {
+ console.log("no match to repo suffix")
+ return 'fail'
+ }
+ result-encoding: string
+
+ # test activity 2
+ - uses: actions/github-script@v4
+ name: "Check Activity 2"
+ id: activity2
+ with:
+ github-token: ${{secrets.GITHUB_TOKEN}}
+ script: |
+ // get commits, filtered by actor
+ const res = await github.repos.listCommits({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ author: context.actor,
+ });
+ let commitList = res.data
+ console.log(commitList)
+
+ // is commit list non-zero
+ if (Array.isArray(commitList) && commitList.length) {
+ console.log("commits found")
+
+ // write result to file
+ const fs = require('fs');
+ fs.writeFile('.github/results/activity2.txt', 'pass', function (err) {
+ if (err) return console.log(err);
+ });
+
+ return 'success'
+ }
+ else {
+ console.log(`no commits for ${context.actor} found`)
+ return 'fail'
+ }
+ result-encoding: string
+
+ # test activity 3
+ - uses: actions/github-script@v4
+ name: "Check Activity 3"
+ id: activity3
+ if: ${{ steps.check-pr.outputs.number }}
+ env:
+ ISSUE: ${{ steps.check-pr.outputs.number }}
+ with:
+ github-token: ${{secrets.GITHUB_TOKEN}}
+ script: |
+ // get comments on Feedback PR
+ const res = await github.issues.listComments({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: process.env.ISSUE,
+ });
+ let commentList = res.data
+ console.log(commentList)
+
+ // is comment list non-zero AND does actor equal one of comment authors
+ if (Array.isArray(commentList) && commentList.length && commentList.some(comment => comment.user.login == context.actor)) {
+ console.log("comments found")
+
+ // write result to file
+ const fs = require('fs');
+ fs.writeFile('.github/results/activity3.txt', 'pass', function (err) {
+ if (err) return console.log(err);
+ });
+
+ return 'success'
+ }
+ else {
+ console.log(`no comments for ${context.author} found`)
+ return 'fail'
+ }
+ result-encoding: string
+
+ - run: ls .github/results
+
+ # run grading
+ # add id to step so outputs can be referenced
+ - uses: education/autograding@v1
+ name: "** Grading and Feedback **"
+ id: autograde
+ continue-on-error: true
+
+ # # fail job if autograde returns failed
+ # # outcome can be 'success', 'failure', 'cancelled', or 'skipped'
+ # # trigger fail either on !success or on failure depending on preference
+ # - name: check autograde pass fail
+ # if: ${{ steps.autograde.outcome != 'success' }}
+ # run: exit 1
+
+ outputs:
+ grading-score: ${{ steps.autograde.outputs.Points }}
+ activity1-result: ${{ steps.activity1.outputs.result }}
+ activity2-result: ${{ steps.activity2.outputs.result }}
+ activity3-result: ${{ steps.activity3.outputs.result }}
+ default-branch-name: ${{ steps.default-branch-name.outputs.result }}
+ feedback-pr: ${{ steps.check-pr.outputs.number }}
+
+ # job to build activity status icons
+ build-activity-icons:
+ name: Build Activity Icons
+ runs-on: ubuntu-latest
+ if: ${{ always() && (!(github.event_name == 'issue_comment') || contains(github.event.repository.name, github.actor)) }}
+ needs: build
+ steps:
+ # need to checkout whole repo
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+
+ # get quiz score
+ - name: Calculate quiz score
+ id: quiz-score
+ run: |
+ if [[ $(git log remotes/origin/feedback..main quiz.md) ]]; then
+ echo "quiz.md file changed"
+ /bin/bash .github/grading-scripts/quiz.sh || echo "::set-output name=quiz_score::0"
+ else
+ echo "quiz.md file not changed"
+ fi
+
+ # switch to status branch
+ - run: git checkout status || git checkout -b status
+
+ # make dir for activity status icons
+ - name: make icons dir
+ run: mkdir -p .github/activity-icons
+
+ # make/copy activity 1 icon
+ - name: activity 1 icon
+ run: |
+ echo ${{ needs.build.outputs.activity1-result }}
+ if ${{ needs.build.outputs.activity1-result == 'success' }}; then
+ cp .github/templates/activity-completed.svg .github/activity-icons/activity1.svg
+ else
+ cp .github/templates/activity-incomplete.svg .github/activity-icons/activity1.svg
+ fi
+
+ # make/copy activity 2 icon
+ - name: activity 2 icon
+ run: |
+ echo ${{ needs.build.outputs.activity2-result }}
+ if ${{ needs.build.outputs.activity2-result == 'success' }}; then
+ cp .github/templates/activity-completed.svg .github/activity-icons/activity2.svg
+ else
+ cp .github/templates/activity-incomplete.svg .github/activity-icons/activity2.svg
+ fi
+
+ # make/copy activity 3 icon
+ - name: activity 3 icon
+ run: |
+ echo ${{ needs.build.outputs.activity3-result }}
+ if ${{ needs.build.outputs.activity3-result == 'success' }}; then
+ cp .github/templates/activity-completed.svg .github/activity-icons/activity3.svg
+ else
+ cp .github/templates/activity-incomplete.svg .github/activity-icons/activity3.svg
+ fi
+
+ # make/copy quiz icon
+ - name: quiz icon
+ run: |
+ if [[ ! -z "${{ steps.quiz-score.outputs.quiz_score }}" ]]; then
+ score=${{ steps.quiz-score.outputs.quiz_score }}
+ echo $score
+
+ if [[ $score == 5 ]]; then
+ cp .github/templates/quiz5.svg .github/activity-icons/quiz.svg
+ else
+ cp .github/templates/quiz.svg .github/activity-icons/quiz.svg
+ sed -i "s/><\/text>/>${score}<\/text>/" .github/activity-icons/quiz.svg
+ sed -i "s/>[0-9]<\/text>/>${score}<\/text>/" .github/activity-icons/quiz.svg
+ fi
+ fi
+
+ # create points bar
+ - name: points bar
+ uses: markpatterson27/points-bar@v1
+ with:
+ points: ${{ needs.build.outputs.grading-score }}
+ path: '.github/activity-icons/points-bar.svg'
+
+ # commit and push activity icons if statuses have changed
+ - name: Commit changes
+ run: |
+ git config --local user.email "action@github.com"
+ git config --local user.name "GitHub Action"
+ git add '.github/activity-icons'
+ git commit -m "Add/Update activity icons" || exit 0
+ git push origin status
+
+ # create Feedback PR
+ create-feedback-pr:
+ name: Create Feedback PR
+ runs-on: ubuntu-latest
+ # run even if autograding fails.
+ if: ${{ always() && needs.build.outputs.feedback-pr == '' }}
+ needs: [build]
+ steps:
+ # checkout files so can access template
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+
+ # read template
+ - uses: markpatterson27/markdown-to-output@v1
+ id: mto
+ with:
+ filepath: .github/templates/pr_body.md
+
+ # switch to feedback branch
+ - name: Create feedback branch
+ run: |
+ git checkout feedback || git checkout -b feedback
+ git push origin feedback
+
+ # check if base and head are same. create empty commit if they are
+ - name: Create empty commit
+ env:
+ DEFAULT_BRANCH: ${{ needs.build.outputs.default-branch-name }}
+ run: |
+ if [[ $(git rev-parse feedback) == $(git rev-parse $DEFAULT_BRANCH) ]]; then
+ git config --local user.email "action@github.com"
+ git config --local user.name "GitHub Action"
+ git checkout $DEFAULT_BRANCH
+ git commit -m "Setup Feedback PR" --allow-empty
+ git push origin $DEFAULT_BRANCH
+ fi
+
+ # create feedback pr
+ - name: Create Feedback PR
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ title: "Feedback"
+ body: ${{ steps.mto.outputs.body }}
+ base: feedback
+ head: ${{ needs.build.outputs.default-branch-name }}
+ run: |
+ gh pr create --base "$base" --head "$head" --title "$title" --body "$body"
+
+ # job to post feedback message in Feedback PR
+ # Classroom will create the PR when assignment accepted. PR should be issue 1.
+ post-feedback:
+ name: Post Feedback Comment
+ runs-on: ubuntu-latest
+ # run even if autograding fails. only run on main branch and if pr exists.
+ if: ${{ always() && needs.build.outputs.feedback-pr != '' && github.ref == 'refs/heads/main' && github.actor != 'github-classroom[bot]' }}
+ needs: [build]
+ steps:
+ # checkout files so can access template
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+
+ # get quiz score
+ - name: Calculate quiz score
+ id: quiz-score
+ run: |
+ if [[ $(git log remotes/origin/feedback..main quiz.md) ]]; then
+ echo "quiz.md file changed"
+ /bin/bash .github/grading-scripts/quiz.sh || echo "::set-output name=quiz_score::0"
+ else
+ echo "quiz.md file not changed"
+ fi
+
+ # set env var
+ - name: Set additional environment variables
+ run: |
+ echo "REPO_NAME=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_ENV
+
+ # read template
+ - uses: markpatterson27/markdown-to-output@v1
+ id: mto
+ with:
+ filepath: .github/templates/pr_feedback.md
+
+ # set feedback var
+ # activity 1 feedback
+ - name: activity 1 feedback
+ run: |
+ if ${{ needs.build.outputs.activity1-result == 'success' }}; then
+ message="${{ steps.mto.outputs.activity1-success }}"
+ status="${{ steps.mto.outputs.status-success }}"
+ else
+ message="${{ steps.mto.outputs.activity1-fail }}"
+ status="${{ steps.mto.outputs.status-fail }}"
+ fi
+ echo "fb-activity1=$(/bin/bash .github/scripts/escape.sh "$message")" >> $GITHUB_ENV
+ echo "status-activity1=$(/bin/bash .github/scripts/escape.sh "$status")" >> $GITHUB_ENV
+
+ # activity 2 feedback
+ - name: activity 2 feedback
+ run: |
+ if ${{ needs.build.outputs.activity2-result == 'success' }}; then
+ message="${{ steps.mto.outputs.activity2-success }}"
+ status="${{ steps.mto.outputs.status-success }}"
+ else
+ message="${{ steps.mto.outputs.activity2-fail }}"
+ status="${{ steps.mto.outputs.status-fail }}"
+ fi
+ echo "fb-activity2=$(/bin/bash .github/scripts/escape.sh "$message")" >> $GITHUB_ENV
+ echo "status-activity2=$(/bin/bash .github/scripts/escape.sh "$status")" >> $GITHUB_ENV
+
+ # activity 3 feedback
+ - name: activity 3 feedback
+ run: |
+ if ${{ needs.build.outputs.activity3-result == 'success' }}; then
+ message="${{ steps.mto.outputs.activity3-success }}"
+ status="${{ steps.mto.outputs.status-success }}"
+ else
+ message="${{ steps.mto.outputs.activity3-fail }}"
+ status="${{ steps.mto.outputs.status-fail }}"
+ fi
+ echo "fb-activity3=$(/bin/bash .github/scripts/escape.sh "$message")" >> $GITHUB_ENV
+ echo "status-activity3=$(/bin/bash .github/scripts/escape.sh "$status")" >> $GITHUB_ENV
+
+ # quiz feedback
+ - name: quiz feedback
+ run: |
+ if [[ $(git log remotes/origin/feedback..main quiz.md) ]]; then
+ score=${{ steps.quiz-score.outputs.quiz_score }}
+ incorrect=(${{ steps.quiz-score.outputs.incorrect_answers }})
+ message=""
+
+ if [[ $score == 5 ]]; then
+ message="${{ steps.mto.outputs.quiz-success }}"
+ status="${{ steps.mto.outputs.status-success }}"
+ else
+ for i in ${incorrect[@]}; do
+ message+="Question $i incorrect. Try again. "$'\n'
+ done
+
+ case $score in
+ 0) status=":zero:" ;;
+ 1) status=":one:" ;;
+ 2) status=":two:" ;;
+ 3) status=":three:" ;;
+ 4) status=":four:" ;;
+ esac
+ fi
+ else
+ message="Quiz not attempted"
+ status=":zero:"
+ fi
+
+ echo "fb-quiz=$(/bin/bash .github/scripts/escape.sh "$message")" >> $GITHUB_ENV
+ echo "status-quiz=$(/bin/bash .github/scripts/escape.sh "$status")" >> $GITHUB_ENV
+
+ # replace tokens
+ # read template file and replace tokens. token replacement based on env name.
+ - name: prepare comment and substitute tokens
+ id: prep
+ uses: actions/github-script@v3
+ env:
+ points: ${{ needs.build.outputs.grading-score }}
+ template: ${{ steps.mto.outputs.body }}
+ with:
+ script: |
+ const fs = require('fs')
+ let commentBody = process.env.template
+
+ for (envName in process.env) {
+ commentBody = commentBody.replace("${"+envName+"}", process.env[envName]
+ .replace(/%0D/g, '\r')
+ .replace(/%0A/g, '\n')
+ .replace(/%25/g, '\%'))
+ }
+
+ return commentBody
+ result-encoding: string
+
+ # hide old feedback comments
+ - name: hide old feedback comments
+ uses: kanga333/comment-hider@master
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ issue_number: ${{ needs.build.outputs.feedback-pr }}
+
+ # post comment on feedback PR. issues and PRs have same numbers
+ - name: post comment
+ uses: actions/github-script@v3
+ env:
+ MESSAGE: ${{ steps.prep.outputs.result }}
+ ISSUE: ${{ needs.build.outputs.feedback-pr }}
+ with:
+ github-token: ${{secrets.GITHUB_TOKEN}}
+ script: |
+ const { MESSAGE, ISSUE } = process.env
+ await github.issues.createComment({
+ issue_number: process.env.ISSUE,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: `${MESSAGE}`
+ })
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f1b4f0d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Mark Patterson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..532821c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,122 @@
+# :wave: GitHub Classroom Introductory Assignment
+
+
+
+Starter lesson for assessing GitHub Classroom use.
+
+The goal of this assignment is to introduce learners to using GiHub Classroom assignments and to assess that learners have the necessary skill set to complete a classroom assignment.
+
+At the end of this lesson, learners will be able to:
+
+1. Describe what a GitHub Classroom assignment is and accept a GitHub Classroom assignment
+2. Use git to complete an assignment task
+3. Use GitHub features to request feedback
+
+---
+
+## :page_facing_up: Classroom Assignments
+
+A [GitHub Classroom](#learn-more-assignments) assignment is a way that your teacher can distribute coding assignments or exercises to students. Assignments are distributed as GitHub [repositories](#terms). Once an assignment is accepted, students only interact with GitHub. This means students use the same industry standard tools as used by millions of developers around the world.
+
+Assignments can make use of GitHub features to:
+
+- grade your work
+- provide a mechanism to get feedback from your teacher
+- make commenting on code easier
+- set a deadline for assignment completion
+
+
+ :book: Learn more about GitHub Classroom
+
+ GitHub Classroom is a tool that helps your teacher organize and manage GitHub repositories that are used for class exercises and assessments. GitHub Classroom automates repository creation and access control, making it easy to distribute starter code and collect assignments on GitHub.
+
+ A GitHub Classroom assignment is a GitHub repository with access control setup so both you and your teacher can access it. When you accept an assignment, GitHub Classroom will automatically create a new repository for you. The assignment repository will belong to your course's organization account on GitHub, but you and your teacher will have access to it.
+
+ Once an assignment has been accepted, students no longer interact with GitHub classroom. They just interact with GitHub.
+
+
+
+ Accepting Classroom assignment steps
+
+ 1. Follow the assignment link your teacher gave you.
+ 2. Sign in to GitHub. If you don't have a GitHub account you will need to [create one](https://github.com/join).
+ 3. If it's your first time accepting an assignment for the class you may need to select your name from the class roster. This makes it easier for your teacher to identify you. (Your teacher may find it difficult to recognize your GitHub username.)
+ 4. Wait for the assignment to copy to new repository. This usually only takes a few seconds.
+ 5. Refresh the page.
+ 6. If the new assignment repository is ready, there will be a link to it on the page. Follow the link.
+
+
+
+| :keyboard: Activity - Accept assignment |
+|:---|
+|
Chances are, if you are reading this, you have already accepted the assignment and have completed the task. Well done. :tada: (You might need to refresh the page to see the completion status).
If you haven't accepted the assignment yet and are reading this from a central site, ask your teacher for the link to the assignment, then follow the [steps](#assignment-steps) to accepting a classroom assignment. |
+
+---
+
+## :octocat: Git and GitHub
+
+In order to complete classroom assignments, you will need to be able to use git and be familiar with GitHub.
+
+### :large_orange_diamond: git
+
+Git is a software tool for tracking changes across a set of files. It helps programmers to undo changes that break their code and to work collaboratively with others when developing software.
+
+If you are already family with using git, continue on.
+If you are new to using git, please __complete the MS Learn course: :book: [Introduction to Git](https://docs.microsoft.com/en-us/learn/modules/intro-to-git/)__ before continuing.
+
+### :octocat: GitHub
+
+GitHub is a cloud based service for hosting Git repositories. It provides a website, command-line tools, and workflow that makes it easier for developers and users to work together.
+
+:tv: [Video: What is GitHub?](https://www.youtube.com/watch?v=w3jLJU7DT5E)
+
+To learn more about GitHub and its features, please __complete the MS Learn course: :book: [Introduction to GitHub](https://docs.microsoft.com/en-us/learn/modules/introduction-to-github/)__.
+
+| :keyboard: Activity - Make commit |
+|:---|
+|
Make a commit to this assignment repo.
Edit the [`editme.md`](../../edit/main/editme.md) file and add a question for your teacher. When you have finished editing the file, save the changes and commit them to this repository.
You can either use the editing tools on GitHub to do this, or clone this repository to your local computer, make the changes, commit them and push the commit back to GitHub. (You could even try GitHub's builtin VS Code Web editor. Press '.' (dot) to try it.)
|
+
+---
+
+## :pencil: Feedback Pull-Request
+
+A pull request (PR) is a feature of GitHub and part of the [GitHub flow](#terms). It provides a space and tools to review and discuss changes made on one branch before those changes are merged into another branch.
+
+:tv: [Video: Introduction to pull requests](https://youtu.be/kJr-PIfLDl4)
+
+Your teacher might have setup a pull-request specifically for feedback. This PR will provide a place to see changes that you have made to the repo and a space for you to discuss with your teacher the code that you have written.
+
+| :keyboard: Activity - Comment on Feedback PR |
+|:---|
+| Go to the [Feedback pull request](../../pull/1). At the bottom of the page you will find a comment form. Leave a comment asking your teacher to review your previous commit. |
+
+---
+
+## :dart: Knowledge Check
+
+Complete the knowledge review quiz. There are five multiple choice questions on the topics covered in this lesson.
+
+| :keyboard: Activity - Review quiz |
+|:---|
+| Edit the [`quiz.md`](../../edit/main/quiz.md) file and add your answers to each question on the same line as and after where it says 'Answer: '. When you have finished answering the questions, save the file, commit the changes and push your commit back to GitHub. |
+
+---
+
+## :books: Further Resources
+
+
+ Terms
+
+ ### Repository
+
+ A repository is a collection of all your project's files and revision history. You can think of it as a folder that contains all of your project's files. You can work within a repository alone or invite others to collaborate with you on those files. Repositories are called "repos" for short.
+
+ ### GitHub Flow
+
+ The GitHub flow is a lightweight branch-based workflow that allows you to experiment and collaborate on your projects easily.
+
+ Learn more about GitHub Flow:
+ - [Interactive Guide](https://guides.github.com/introduction/flow/)
+ - [Video: GitHub Flow](https://www.youtube.com/watch?v=PBI2Rz-ZOxU)
+
+
\ No newline at end of file
diff --git a/editme.md b/editme.md
new file mode 100644
index 0000000..f8fa35c
--- /dev/null
+++ b/editme.md
@@ -0,0 +1,3 @@
+_Write a question for your teacher below._
+
+Q:
diff --git a/quiz.md b/quiz.md
new file mode 100644
index 0000000..430c2d8
--- /dev/null
+++ b/quiz.md
@@ -0,0 +1,62 @@
+# Quiz
+
+The questions in this quiz are multiple choice. To answer the questions, edit this file and in the space after 'Answer: ' insert the number corresponding to your choice. e.g.
+
+> Answer: 3
+
+When you have finished answering questions, commit your changes and push the commit back to GitHub.
+
+------
+
+Q1. Which statement about GitHub Classroom is true?
+
+1. GitHub Classroom provides an alternative interface for students to use, instead of using GitHub.
+2. GitHub Classroom is a teacher-facing tool that uses the GitHub API to enable the GitHub workflow for education.
+3. GitHub Classroom is a website that provides online courses to learn about GitHub.
+4. GitHub Classroom is developed by 3rd party developers but uses the GitHub API to integrate into GitHub.
+
+Answer:
+
+------
+
+Q2. What does the command `git add` do?
+
+1. Adds a file to GitHub
+2. Adds a file to the staging area
+3. Adds a file to the .git directory
+4. Adds a file to the working directory
+
+Answer:
+
+------
+
+Q3 . What Git commands can be used to correct mistakes?
+
+1. `git reset` and `git recover`
+2. `git rebase` and `git remove`
+3. `git reset` and `git revert`
+4. `git revert` and `git remove`
+
+Answer:
+
+------
+
+Q4. Which GitHub feature provides task automation and workflow functionality, which can be used to implement CI/CD?
+
+1. Forking
+2. Pages
+3. Pull Requests
+4. Actions
+
+Answer:
+
+------
+
+Q5. Pull requests provide a mechanism to request which git action?
+
+1. commit
+2. branch
+3. merge
+4. push
+
+Answer: