From 625f123e18d3bf68c23485e809b3b1d22801af0e Mon Sep 17 00:00:00 2001
From: zjc_he <zjc_he@sjtu.edu.cn>
Date: Mon, 3 Jun 2024 00:50:31 +0800
Subject: [PATCH 01/15] feat(internal/scoreboard/scoreboard.go): skeleton of
 scoreboard

---
 internal/scoreboard/scoreboard.go | 52 +++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)
 create mode 100644 internal/scoreboard/scoreboard.go

diff --git a/internal/scoreboard/scoreboard.go b/internal/scoreboard/scoreboard.go
new file mode 100644
index 0000000..d306ee0
--- /dev/null
+++ b/internal/scoreboard/scoreboard.go
@@ -0,0 +1,52 @@
+package scoreboard
+
+import (
+	"encoding/json"
+	"os"
+)
+
+type Question struct {
+	Name    string `json:"name"`
+	Score   int    `json:"score"`
+	Comment string `json:"comment"`
+}
+
+type ScoreboardData struct {
+	StudentName string     `json:"studentname"`
+	StudentId   string     `json:"studentid"`
+	Questions   []Question `json:"questions"`
+}
+
+type Scoreboard struct {
+	scoreboard ScoreboardData
+}
+
+func (b *Scoreboard) Init(studentName string, studentId string) {
+	b.scoreboard.StudentName = studentName
+	b.scoreboard.StudentId = studentId
+	b.scoreboard.Questions = make([]Question, 0)
+}
+
+func (b *Scoreboard) AddScore(questionName string, score int) {
+	flag := false
+	for i, question := range b.scoreboard.Questions {
+		if question.Name == questionName {
+			b.scoreboard.Questions[i].Score = score
+			flag = true
+			break
+		}
+	}
+	if flag {
+		b.scoreboard.Questions = append(b.scoreboard.Questions, Question{Name: questionName, Score: score})
+	}
+}
+
+func (b *Scoreboard) SaveFile(filePath string) {
+	json_file, _ := os.Create(filePath)
+	defer json_file.Close()
+
+	encoder := json.NewEncoder(json_file)
+	encoder.SetEscapeHTML(false)
+	encoder.SetIndent("", "  ")
+	_ = encoder.Encode(b.scoreboard)
+}
-- 
2.30.2


From 3a095e64d4bb70821f547e17eb51a47ee8deb2f5 Mon Sep 17 00:00:00 2001
From: zjc_he <zjc_he@sjtu.edu.cn>
Date: Sun, 9 Jun 2024 20:50:29 +0800
Subject: [PATCH 02/15] feat(.gitignore): ignoring folder created by teapot

---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index 4c5caca..d0ee053 100644
--- a/.gitignore
+++ b/.gitignore
@@ -125,3 +125,4 @@ $RECYCLE.BIN/
 build/
 !examples/**/*.out
 tmp/
+repos/
-- 
2.30.2


From 753ed6f9c66db2c0da2c242eb711babbe7f98de3 Mon Sep 17 00:00:00 2001
From: zjc_he <zjc_he@sjtu.edu.cn>
Date: Sun, 9 Jun 2024 20:58:27 +0800
Subject: [PATCH 03/15] 
 feat(cmd/joj3/main_test.go,-internal/scoreboard/scoreboard.go): automatically
 update scoreboard each time the test program runs

---
 cmd/joj3/main_test.go             | 16 ++++++
 internal/scoreboard/scoreboard.go | 93 +++++++++++++++++++++++--------
 2 files changed, 86 insertions(+), 23 deletions(-)

diff --git a/cmd/joj3/main_test.go b/cmd/joj3/main_test.go
index 22cbb78..3273b32 100644
--- a/cmd/joj3/main_test.go
+++ b/cmd/joj3/main_test.go
@@ -9,6 +9,7 @@ import (
 	"strings"
 	"testing"
 
+	"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/scoreboard"
 	"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
 )
 
@@ -61,7 +62,16 @@ func readStageResults(t *testing.T, path string) []stage.StageResult {
 	return results
 }
 
+func removeStringPrefix(s, prefix string) string {
+	if strings.HasPrefix(s, prefix) {
+		return s[len(prefix):]
+	}
+	return s
+}
+
 func TestMain(t *testing.T) {
+	scoreboard := scoreboard.Scoreboard{}
+	scoreboard.Init("TestingStudent", "520370000000")
 	var tests []string
 	root := "../../tmp/submodules/JOJ3-examples"
 	err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
@@ -107,6 +117,7 @@ func TestMain(t *testing.T) {
 			defer os.Remove(outputFile)
 			main()
 			stageResults := readStageResults(t, outputFile)
+			scoreboard.AddScore(removeStringPrefix(tt, "/examples/"), stageResults)
 			regex := true
 			expectedFile := "expected_regex.json"
 			if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
@@ -117,4 +128,9 @@ func TestMain(t *testing.T) {
 			compareStageResults(t, stageResults, expectedStageResults, regex)
 		})
 	}
+	if !t.Failed() {
+		scoreboard.SaveFile("../../scoreboard.json")
+		defer os.Remove("../../scoreboard.json")
+		scoreboard.Submit()
+	}
 }
diff --git a/internal/scoreboard/scoreboard.go b/internal/scoreboard/scoreboard.go
index d306ee0..9030a9e 100644
--- a/internal/scoreboard/scoreboard.go
+++ b/internal/scoreboard/scoreboard.go
@@ -1,44 +1,40 @@
 package scoreboard
 
 import (
+	"bytes"
 	"encoding/json"
+	"fmt"
+	"log/slog"
 	"os"
+	"os/exec"
+
+	"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
 )
 
-type Question struct {
-	Name    string `json:"name"`
-	Score   int    `json:"score"`
-	Comment string `json:"comment"`
+type StageRecord struct {
+	StageName    string              `json:"stagename"`
+	StageResults []stage.StageResult `json:"stageresults"`
 }
 
 type ScoreboardData struct {
-	StudentName string     `json:"studentname"`
-	StudentId   string     `json:"studentid"`
-	Questions   []Question `json:"questions"`
+	StageRecords []StageRecord `json:"stagerecords"`
 }
 
 type Scoreboard struct {
-	scoreboard ScoreboardData
+	studentName string
+	studentId   string
+	scoreboard  ScoreboardData
 }
 
 func (b *Scoreboard) Init(studentName string, studentId string) {
-	b.scoreboard.StudentName = studentName
-	b.scoreboard.StudentId = studentId
-	b.scoreboard.Questions = make([]Question, 0)
+	b.studentName = studentName
+	b.studentId = studentId
+	b.scoreboard.StageRecords = make([]StageRecord, 0)
 }
 
-func (b *Scoreboard) AddScore(questionName string, score int) {
-	flag := false
-	for i, question := range b.scoreboard.Questions {
-		if question.Name == questionName {
-			b.scoreboard.Questions[i].Score = score
-			flag = true
-			break
-		}
-	}
-	if flag {
-		b.scoreboard.Questions = append(b.scoreboard.Questions, Question{Name: questionName, Score: score})
-	}
+func (b *Scoreboard) AddScore(stagename string, results []stage.StageResult) {
+	b.scoreboard.StageRecords = append(b.scoreboard.StageRecords,
+		StageRecord{StageName: stagename, StageResults: results})
 }
 
 func (b *Scoreboard) SaveFile(filePath string) {
@@ -50,3 +46,54 @@ func (b *Scoreboard) SaveFile(filePath string) {
 	encoder.SetIndent("", "  ")
 	_ = encoder.Encode(b.scoreboard)
 }
+
+func (b *Scoreboard) Submit() {
+	e := os.Mkdir("repos", 0o777)
+	if e != nil {
+		slog.Error("Encountered problems createing folder: ", "err", e)
+		return
+	}
+	var teapotCommand string
+	origHome := os.Getenv("ORIG_HOME")
+	if origHome != "" {
+		// For drone server
+		teapotCommand = fmt.Sprintf("cp %s/.config/ci/teapot.env .env && joint-teapot JOJ3-scoreboard \"../../scoreboard.json\" %s %s \"JOJ3-examples\" \"JOJ3_dev.csv\"", origHome, b.studentName, b.studentId)
+	} else {
+		// For local developers
+		jointTeapotRoot := os.Getenv("TEAPOT_ROOT")
+		if jointTeapotRoot == "" {
+			slog.Error("Unable to find joint-teapot. Have you configured environment variable TEAPOT_ROOT?")
+			return
+		}
+		teapotCommand = fmt.Sprintf("cp %s/.env .env && source %s/env/bin/activate && python3 -m joint_teapot JOJ3-scoreboard \"../../scoreboard.json\" %s %s \"JOJ3-examples\" \"JOJ3_dev.csv\" && deactivate", jointTeapotRoot, jointTeapotRoot, b.studentName, b.studentId)
+	}
+	defer os.Remove(".env")
+	teapotCmd := exec.Command("/bin/bash", "-c", teapotCommand)
+	defer os.Remove("joint-teapot.log")
+
+	stderrPipe, err := teapotCmd.StderrPipe()
+	if err != nil {
+		slog.Error("Error creating stderr pipe when submitting scoreboard: ", "err", err)
+		return
+	}
+	err = teapotCmd.Start()
+	if err != nil {
+		slog.Error("Error starting command when submitting scoreboard: ", "err", err)
+		return
+	}
+
+	var stderr bytes.Buffer
+	_, err = stderr.ReadFrom(stderrPipe)
+	if err != nil {
+		slog.Error("Error reading stderr when submitting scoreboard: ", "err", err)
+		return
+	}
+
+	err = teapotCmd.Wait()
+	if err != nil {
+		slog.Error("Tried to submit scoreboard, but it finished with error: ", "err", err)
+		slog.Error("Stderr output:", "stderr", stderr.String())
+		return
+	}
+	slog.Info("Scoreboard was submitted with following outputs: ", "stderr", stderr.String())
+}
-- 
2.30.2


From 1e2f5aa4e0b4873110a488135bdad585a24d762e Mon Sep 17 00:00:00 2001
From: zjc_he <zjc_he@sjtu.edu.cn>
Date: Mon, 10 Jun 2024 12:52:52 +0800
Subject: [PATCH 04/15] feat(.drone.yml,-main_test.go,-.gitignore): submit
 scoreboard in drone instead

---
 .drone.yml            | 10 ++++++++++
 .gitignore            |  1 +
 cmd/joj3/main_test.go |  6 +++---
 3 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index 9f009f4..e2a96af 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -26,6 +26,16 @@ steps:
       commands:
           - make prepare-test
           - make test
+    - name: scoreboard
+      environment:
+          - 'export ORIG_HOME=$(grep ^${USER}: /etc/passwd |cut -d : -f 6)'
+          - PATH=$PATH:$ORIG_HOME/.local/bin
+      commands:
+          - if echo "${DRONE_REPO_NAME}" | grep -q '-'; then SUBMITTER_NAME=$(echo "{DRONE_REPO_NAME}" | cut -d'-' -f1); else SUBMITTER_NAME={DRONE_REPO_NAME};
+            fi
+          - mkdir repo
+          - cp $ORIG_HOME/.config/ci/teapot.env .env && joint-teapot JOJ3-scoreboard "score.json" $SUBMITTER_NAME "" "JOJ3-examples" "JOJ3_dev.csv"
+          - cat joint-teapot.log
     - name: store
       commands:
           - cp build/joj3 /home/drone/.local/bin/joj3
diff --git a/.gitignore b/.gitignore
index d0ee053..3b63635 100644
--- a/.gitignore
+++ b/.gitignore
@@ -126,3 +126,4 @@ build/
 !examples/**/*.out
 tmp/
 repos/
+score.json
diff --git a/cmd/joj3/main_test.go b/cmd/joj3/main_test.go
index 3273b32..e9717f7 100644
--- a/cmd/joj3/main_test.go
+++ b/cmd/joj3/main_test.go
@@ -129,8 +129,8 @@ func TestMain(t *testing.T) {
 		})
 	}
 	if !t.Failed() {
-		scoreboard.SaveFile("../../scoreboard.json")
-		defer os.Remove("../../scoreboard.json")
-		scoreboard.Submit()
+		scoreboard.SaveFile("../../score.json")
+		// defer os.Remove("../../score.json")
+		// scoreboard.Submit()
 	}
 }
-- 
2.30.2


From cc08f1e19d5bbe137f5fac298e6fce94380d9461 Mon Sep 17 00:00:00 2001
From: zjc_he <zjc_he@sjtu.edu.cn>
Date: Mon, 10 Jun 2024 12:54:49 +0800
Subject: [PATCH 05/15] fix(.drone.yml): fixing .drone.yml

---
 .drone.yml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index e2a96af..dc8df54 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -7,6 +7,9 @@ server:
     user: drone
     ssh_key:
         from_secret: joj3-test
+environment:
+    - 'export ORIG_HOME=$(grep ^${USER}: /etc/passwd |cut -d : -f 6)'
+    - PATH=$PATH:$ORIG_HOME/.local/bin
 
 steps:
     - name: prepare
@@ -27,9 +30,6 @@ steps:
           - make prepare-test
           - make test
     - name: scoreboard
-      environment:
-          - 'export ORIG_HOME=$(grep ^${USER}: /etc/passwd |cut -d : -f 6)'
-          - PATH=$PATH:$ORIG_HOME/.local/bin
       commands:
           - if echo "${DRONE_REPO_NAME}" | grep -q '-'; then SUBMITTER_NAME=$(echo "{DRONE_REPO_NAME}" | cut -d'-' -f1); else SUBMITTER_NAME={DRONE_REPO_NAME};
             fi
-- 
2.30.2


From 33de1178ac99fa8cbaaad6fa8de33f5de0201656 Mon Sep 17 00:00:00 2001
From: zjc_he <zjc_he@sjtu.edu.cn>
Date: Mon, 10 Jun 2024 12:57:29 +0800
Subject: [PATCH 06/15] fix(.drone.yml): fixing .drone.yml

---
 .drone.yml | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index dc8df54..807f5b3 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -7,9 +7,6 @@ server:
     user: drone
     ssh_key:
         from_secret: joj3-test
-environment:
-    - 'export ORIG_HOME=$(grep ^${USER}: /etc/passwd |cut -d : -f 6)'
-    - PATH=$PATH:$ORIG_HOME/.local/bin
 
 steps:
     - name: prepare
@@ -31,6 +28,8 @@ steps:
           - make test
     - name: scoreboard
       commands:
+          - 'export ORIG_HOME=$(grep ^${USER}: /etc/passwd |cut -d : -f 6)'
+          - PATH=$PATH:$ORIG_HOME/.local/bin
           - if echo "${DRONE_REPO_NAME}" | grep -q '-'; then SUBMITTER_NAME=$(echo "{DRONE_REPO_NAME}" | cut -d'-' -f1); else SUBMITTER_NAME={DRONE_REPO_NAME};
             fi
           - mkdir repo
-- 
2.30.2


From bc6222307f4622db0c3152af5c93c9efdf36e70f Mon Sep 17 00:00:00 2001
From: zjc_he <zjc_he@sjtu.edu.cn>
Date: Mon, 10 Jun 2024 13:10:13 +0800
Subject: [PATCH 07/15] feat(.drone.yml,-submit_scoreboard.sh): moving commands
 to a submit_scoreboard.sh

---
 .drone.yml                   |  8 +-------
 scripts/submit_scoreboard.sh | 13 +++++++++++++
 2 files changed, 14 insertions(+), 7 deletions(-)
 create mode 100644 scripts/submit_scoreboard.sh

diff --git a/.drone.yml b/.drone.yml
index 807f5b3..19ae5ac 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -28,13 +28,7 @@ steps:
           - make test
     - name: scoreboard
       commands:
-          - 'export ORIG_HOME=$(grep ^${USER}: /etc/passwd |cut -d : -f 6)'
-          - PATH=$PATH:$ORIG_HOME/.local/bin
-          - if echo "${DRONE_REPO_NAME}" | grep -q '-'; then SUBMITTER_NAME=$(echo "{DRONE_REPO_NAME}" | cut -d'-' -f1); else SUBMITTER_NAME={DRONE_REPO_NAME};
-            fi
-          - mkdir repo
-          - cp $ORIG_HOME/.config/ci/teapot.env .env && joint-teapot JOJ3-scoreboard "score.json" $SUBMITTER_NAME "" "JOJ3-examples" "JOJ3_dev.csv"
-          - cat joint-teapot.log
+          - bash scripts/submit_scoreboard.sh
     - name: store
       commands:
           - cp build/joj3 /home/drone/.local/bin/joj3
diff --git a/scripts/submit_scoreboard.sh b/scripts/submit_scoreboard.sh
new file mode 100644
index 0000000..91ef6ca
--- /dev/null
+++ b/scripts/submit_scoreboard.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+export ORIG_HOME=$(grep ^${USER}: /etc/passwd |cut -d : -f 6)
+PATH=$PATH:$ORIG_HOME/.local/bin
+
+if echo "${DRONE_REPO_NAME}" | grep -q '-'; then
+    SUBMITTER_NAME=$(echo "{DRONE_REPO_NAME}" | cut -d'-' -f1);
+else
+    SUBMITTER_NAME={DRONE_REPO_NAME};
+fi
+
+mkdir repo
+cp $ORIG_HOME/.config/ci/teapot.env .env && joint-teapot JOJ3-scoreboard "score.json" $SUBMITTER_NAME "" "JOJ3-examples" "JOJ3_dev.csv"
+cat joint-teapot.log
-- 
2.30.2


From 24b7b2b555b53bbd1a8a8ea2df10fcb7943e1c68 Mon Sep 17 00:00:00 2001
From: zjc_he <zjc_he@sjtu.edu.cn>
Date: Mon, 10 Jun 2024 13:23:17 +0800
Subject: [PATCH 08/15] fix(submit_scoreboard.sh): fix new folder name

---
 scripts/submit_scoreboard.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/submit_scoreboard.sh b/scripts/submit_scoreboard.sh
index 91ef6ca..436314f 100644
--- a/scripts/submit_scoreboard.sh
+++ b/scripts/submit_scoreboard.sh
@@ -8,6 +8,6 @@ else
     SUBMITTER_NAME={DRONE_REPO_NAME};
 fi
 
-mkdir repo
+mkdir repos
 cp $ORIG_HOME/.config/ci/teapot.env .env && joint-teapot JOJ3-scoreboard "score.json" $SUBMITTER_NAME "" "JOJ3-examples" "JOJ3_dev.csv"
 cat joint-teapot.log
-- 
2.30.2


From 629e0ecb29229bf3fe0246d32b1d60ec5619ed58 Mon Sep 17 00:00:00 2001
From: zjc_he <zjc_he@sjtu.edu.cn>
Date: Mon, 10 Jun 2024 14:00:27 +0800
Subject: [PATCH 09/15] feat(.drone.yml,-submit_scoreboard.sh): setting up .env

---
 .drone.yml                   |  4 ++++
 scripts/submit_scoreboard.sh | 11 ++++++++++-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/.drone.yml b/.drone.yml
index 19ae5ac..253eb79 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -27,6 +27,10 @@ steps:
           - make prepare-test
           - make test
     - name: scoreboard
+      environment:
+          GITEA_ACCESS_TOKEN:
+              from_secret: gitea-token
+          GITEA_ORG_NAME: FOCS-dev
       commands:
           - bash scripts/submit_scoreboard.sh
     - name: store
diff --git a/scripts/submit_scoreboard.sh b/scripts/submit_scoreboard.sh
index 436314f..eb4a54a 100644
--- a/scripts/submit_scoreboard.sh
+++ b/scripts/submit_scoreboard.sh
@@ -9,5 +9,14 @@ else
 fi
 
 mkdir repos
-cp $ORIG_HOME/.config/ci/teapot.env .env && joint-teapot JOJ3-scoreboard "score.json" $SUBMITTER_NAME "" "JOJ3-examples" "JOJ3_dev.csv"
+
+echo 'CANVAS_ACCESS_TOKEN=""' > .env
+echo 'CANVAS_COURSE_ID=0' >> .env
+echo 'GITEA_ACCESS_TOKEN=$GITEA_ACCESS_TOKEN' >> .env
+echo 'GITEA_ORG_NAME=$GITEA_ORG_NAME' >> .env
+echo 'MATTERMOST_TEAM=""' >> .env
+echo 'MATTERMOST_ACCESS_TOKEN=""' >> .env
+echo 'MATTERMOST_TEACHING_TEAM=[]' >> .env
+
+joint-teapot JOJ3-scoreboard "score.json" $SUBMITTER_NAME "" "JOJ3-examples" "JOJ3_dev.csv"
 cat joint-teapot.log
-- 
2.30.2


From 1d135c7cab0fe6f7e84365a6b6fb843dc3e23d49 Mon Sep 17 00:00:00 2001
From: zjc_he <zjc_he@sjtu.edu.cn>
Date: Mon, 10 Jun 2024 14:02:41 +0800
Subject: [PATCH 10/15] fix(submit_scoreboard.sh): fix repo name

---
 scripts/submit_scoreboard.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/scripts/submit_scoreboard.sh b/scripts/submit_scoreboard.sh
index eb4a54a..34f76e1 100644
--- a/scripts/submit_scoreboard.sh
+++ b/scripts/submit_scoreboard.sh
@@ -3,9 +3,9 @@ export ORIG_HOME=$(grep ^${USER}: /etc/passwd |cut -d : -f 6)
 PATH=$PATH:$ORIG_HOME/.local/bin
 
 if echo "${DRONE_REPO_NAME}" | grep -q '-'; then
-    SUBMITTER_NAME=$(echo "{DRONE_REPO_NAME}" | cut -d'-' -f1);
+    SUBMITTER_NAME=$(echo "${DRONE_REPO_NAME}" | cut -d'-' -f1);
 else
-    SUBMITTER_NAME={DRONE_REPO_NAME};
+    SUBMITTER_NAME=${DRONE_REPO_NAME};
 fi
 
 mkdir repos
-- 
2.30.2


From e80f4b55da30590abb5455b6e9c0cda815c71f4f Mon Sep 17 00:00:00 2001
From: zjc_he <zjc_he@sjtu.edu.cn>
Date: Mon, 10 Jun 2024 15:28:40 +0800
Subject: [PATCH 11/15] 
 feat(cmd/joj3/main_test.go,-internal/scoreboard/scoreboard.go,-scripts/submit_scoreboard.sh):
 removing unused function in scoreboard

---
 cmd/joj3/main_test.go             |  4 +-
 internal/scoreboard/scoreboard.go | 63 +------------------------------
 scripts/submit_scoreboard.sh      |  3 +-
 3 files changed, 5 insertions(+), 65 deletions(-)

diff --git a/cmd/joj3/main_test.go b/cmd/joj3/main_test.go
index e9717f7..83a4601 100644
--- a/cmd/joj3/main_test.go
+++ b/cmd/joj3/main_test.go
@@ -71,7 +71,7 @@ func removeStringPrefix(s, prefix string) string {
 
 func TestMain(t *testing.T) {
 	scoreboard := scoreboard.Scoreboard{}
-	scoreboard.Init("TestingStudent", "520370000000")
+	scoreboard.Init()
 	var tests []string
 	root := "../../tmp/submodules/JOJ3-examples"
 	err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
@@ -130,7 +130,5 @@ func TestMain(t *testing.T) {
 	}
 	if !t.Failed() {
 		scoreboard.SaveFile("../../score.json")
-		// defer os.Remove("../../score.json")
-		// scoreboard.Submit()
 	}
 }
diff --git a/internal/scoreboard/scoreboard.go b/internal/scoreboard/scoreboard.go
index 9030a9e..e43eadd 100644
--- a/internal/scoreboard/scoreboard.go
+++ b/internal/scoreboard/scoreboard.go
@@ -1,12 +1,8 @@
 package scoreboard
 
 import (
-	"bytes"
 	"encoding/json"
-	"fmt"
-	"log/slog"
 	"os"
-	"os/exec"
 
 	"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
 )
@@ -21,14 +17,10 @@ type ScoreboardData struct {
 }
 
 type Scoreboard struct {
-	studentName string
-	studentId   string
-	scoreboard  ScoreboardData
+	scoreboard ScoreboardData
 }
 
-func (b *Scoreboard) Init(studentName string, studentId string) {
-	b.studentName = studentName
-	b.studentId = studentId
+func (b *Scoreboard) Init() {
 	b.scoreboard.StageRecords = make([]StageRecord, 0)
 }
 
@@ -46,54 +38,3 @@ func (b *Scoreboard) SaveFile(filePath string) {
 	encoder.SetIndent("", "  ")
 	_ = encoder.Encode(b.scoreboard)
 }
-
-func (b *Scoreboard) Submit() {
-	e := os.Mkdir("repos", 0o777)
-	if e != nil {
-		slog.Error("Encountered problems createing folder: ", "err", e)
-		return
-	}
-	var teapotCommand string
-	origHome := os.Getenv("ORIG_HOME")
-	if origHome != "" {
-		// For drone server
-		teapotCommand = fmt.Sprintf("cp %s/.config/ci/teapot.env .env && joint-teapot JOJ3-scoreboard \"../../scoreboard.json\" %s %s \"JOJ3-examples\" \"JOJ3_dev.csv\"", origHome, b.studentName, b.studentId)
-	} else {
-		// For local developers
-		jointTeapotRoot := os.Getenv("TEAPOT_ROOT")
-		if jointTeapotRoot == "" {
-			slog.Error("Unable to find joint-teapot. Have you configured environment variable TEAPOT_ROOT?")
-			return
-		}
-		teapotCommand = fmt.Sprintf("cp %s/.env .env && source %s/env/bin/activate && python3 -m joint_teapot JOJ3-scoreboard \"../../scoreboard.json\" %s %s \"JOJ3-examples\" \"JOJ3_dev.csv\" && deactivate", jointTeapotRoot, jointTeapotRoot, b.studentName, b.studentId)
-	}
-	defer os.Remove(".env")
-	teapotCmd := exec.Command("/bin/bash", "-c", teapotCommand)
-	defer os.Remove("joint-teapot.log")
-
-	stderrPipe, err := teapotCmd.StderrPipe()
-	if err != nil {
-		slog.Error("Error creating stderr pipe when submitting scoreboard: ", "err", err)
-		return
-	}
-	err = teapotCmd.Start()
-	if err != nil {
-		slog.Error("Error starting command when submitting scoreboard: ", "err", err)
-		return
-	}
-
-	var stderr bytes.Buffer
-	_, err = stderr.ReadFrom(stderrPipe)
-	if err != nil {
-		slog.Error("Error reading stderr when submitting scoreboard: ", "err", err)
-		return
-	}
-
-	err = teapotCmd.Wait()
-	if err != nil {
-		slog.Error("Tried to submit scoreboard, but it finished with error: ", "err", err)
-		slog.Error("Stderr output:", "stderr", stderr.String())
-		return
-	}
-	slog.Info("Scoreboard was submitted with following outputs: ", "stderr", stderr.String())
-}
diff --git a/scripts/submit_scoreboard.sh b/scripts/submit_scoreboard.sh
index 34f76e1..c104342 100644
--- a/scripts/submit_scoreboard.sh
+++ b/scripts/submit_scoreboard.sh
@@ -19,4 +19,5 @@ echo 'MATTERMOST_ACCESS_TOKEN=""' >> .env
 echo 'MATTERMOST_TEACHING_TEAM=[]' >> .env
 
 joint-teapot JOJ3-scoreboard "score.json" $SUBMITTER_NAME "" "JOJ3-examples" "JOJ3_dev.csv"
-cat joint-teapot.log
+rm score.json
+rm .env
-- 
2.30.2


From e7271042b581332af57028c700203c96b490e0bc Mon Sep 17 00:00:00 2001
From: zjc_he <zjc_he@sjtu.edu.cn>
Date: Wed, 12 Jun 2024 17:45:58 +0800
Subject: [PATCH 12/15] Merge branch 'master' into scoreboard

---
 examples/clangtidy/sillycode         | 2 +-
 examples/compile/error               | 2 +-
 examples/compile/success             | 2 +-
 examples/cppcheck/sillycode          | 2 +-
 examples/cpplint/sillycode           | 2 +-
 examples/dummy/error                 | 2 +-
 examples/dummy/success               | 2 +-
 examples/keyword/clangtidy/sillycode | 2 +-
 examples/keyword/cpplint/sillycode   | 2 +-
 9 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/examples/clangtidy/sillycode b/examples/clangtidy/sillycode
index 34f1bcd..607ac46 160000
--- a/examples/clangtidy/sillycode
+++ b/examples/clangtidy/sillycode
@@ -1 +1 @@
-Subproject commit 34f1bcd9cf3e2905ecfd95284b25eae2568d38df
+Subproject commit 607ac46d3421fd145f2a1f0dbcba9e37f7563be9
diff --git a/examples/compile/error b/examples/compile/error
index 9f0d88e..dc7be30 160000
--- a/examples/compile/error
+++ b/examples/compile/error
@@ -1 +1 @@
-Subproject commit 9f0d88eff4e9d7d3ac58f460609272f7d2e527e7
+Subproject commit dc7be30db1fbfd83ecb78f214cff3f42732a1365
diff --git a/examples/compile/success b/examples/compile/success
index a900711..21f6df7 160000
--- a/examples/compile/success
+++ b/examples/compile/success
@@ -1 +1 @@
-Subproject commit a90071148cb7e39cf3e93b18a1e71632d7e974a3
+Subproject commit 21f6df70d483f34a99b50335e0a1fbe50d3a82dd
diff --git a/examples/cppcheck/sillycode b/examples/cppcheck/sillycode
index d33b07f..0815ab9 160000
--- a/examples/cppcheck/sillycode
+++ b/examples/cppcheck/sillycode
@@ -1 +1 @@
-Subproject commit d33b07f18bf36c77dcf9a012d265dc7bd45fac9f
+Subproject commit 0815ab90d72641fc274231c075282567e9e17865
diff --git a/examples/cpplint/sillycode b/examples/cpplint/sillycode
index 6d47ed4..a700156 160000
--- a/examples/cpplint/sillycode
+++ b/examples/cpplint/sillycode
@@ -1 +1 @@
-Subproject commit 6d47ed4f6f7b8632784513edd8a206689503fc56
+Subproject commit a7001564a22f9807119efb7b8f4cf6f74d4c12fc
diff --git a/examples/dummy/error b/examples/dummy/error
index 9cf0d99..6cbfd9f 160000
--- a/examples/dummy/error
+++ b/examples/dummy/error
@@ -1 +1 @@
-Subproject commit 9cf0d994aa613dc38f2bc99f42d0dd7509c3d42c
+Subproject commit 6cbfd9ff1ea95cd5c6c5f832e99cda6f9f2ea851
diff --git a/examples/dummy/success b/examples/dummy/success
index c2fe51b..b1afead 160000
--- a/examples/dummy/success
+++ b/examples/dummy/success
@@ -1 +1 @@
-Subproject commit c2fe51b4cd485339fd18924196b01eed6848ba1d
+Subproject commit b1afead762d2b2704823af83847c9155c6a1422b
diff --git a/examples/keyword/clangtidy/sillycode b/examples/keyword/clangtidy/sillycode
index 9de8a32..51160e0 160000
--- a/examples/keyword/clangtidy/sillycode
+++ b/examples/keyword/clangtidy/sillycode
@@ -1 +1 @@
-Subproject commit 9de8a32bc3a55f0652d487421384d0a163bf0aaa
+Subproject commit 51160e0a0cb01159fa264435865185083d756b06
diff --git a/examples/keyword/cpplint/sillycode b/examples/keyword/cpplint/sillycode
index 9be8c3c..f43b0b3 160000
--- a/examples/keyword/cpplint/sillycode
+++ b/examples/keyword/cpplint/sillycode
@@ -1 +1 @@
-Subproject commit 9be8c3c329342059f49683a4e810938e8321adbe
+Subproject commit f43b0b3a7b873ee935b19e4e5f26a8ceda7d3d61
-- 
2.30.2


From 4455304db9bf721543ee3e433c5b3fc5e3c15252 Mon Sep 17 00:00:00 2001
From: zjc_he <zjc_he@sjtu.edu.cn>
Date: Wed, 3 Jul 2024 00:22:20 +0800
Subject: [PATCH 13/15] style(main_test.go,-.drone.yml,-scoreboard.go):
 reformats

---
 .drone.yml                                         |  2 +-
 cmd/joj3/main_test.go                              |  9 +--------
 internal/scoreboard/scoreboard.go                  | 14 +++++++-------
 ...reboard.sh => submit_scoreboard_failedtable.sh} | 12 +++++++-----
 4 files changed, 16 insertions(+), 21 deletions(-)
 rename scripts/{submit_scoreboard.sh => submit_scoreboard_failedtable.sh} (62%)

diff --git a/.drone.yml b/.drone.yml
index 253eb79..e834e25 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -32,7 +32,7 @@ steps:
               from_secret: gitea-token
           GITEA_ORG_NAME: FOCS-dev
       commands:
-          - bash scripts/submit_scoreboard.sh
+          - bash scripts/submit_scoreboard_failedtable.sh
     - name: store
       commands:
           - cp build/joj3 /home/drone/.local/bin/joj3
diff --git a/cmd/joj3/main_test.go b/cmd/joj3/main_test.go
index 83a4601..daea3cf 100644
--- a/cmd/joj3/main_test.go
+++ b/cmd/joj3/main_test.go
@@ -62,13 +62,6 @@ func readStageResults(t *testing.T, path string) []stage.StageResult {
 	return results
 }
 
-func removeStringPrefix(s, prefix string) string {
-	if strings.HasPrefix(s, prefix) {
-		return s[len(prefix):]
-	}
-	return s
-}
-
 func TestMain(t *testing.T) {
 	scoreboard := scoreboard.Scoreboard{}
 	scoreboard.Init()
@@ -117,7 +110,7 @@ func TestMain(t *testing.T) {
 			defer os.Remove(outputFile)
 			main()
 			stageResults := readStageResults(t, outputFile)
-			scoreboard.AddScore(removeStringPrefix(tt, "/examples/"), stageResults)
+			scoreboard.AddScore(strings.TrimPrefix(tt, "/examples/"), stageResults)
 			regex := true
 			expectedFile := "expected_regex.json"
 			if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
diff --git a/internal/scoreboard/scoreboard.go b/internal/scoreboard/scoreboard.go
index e43eadd..63e5abd 100644
--- a/internal/scoreboard/scoreboard.go
+++ b/internal/scoreboard/scoreboard.go
@@ -7,13 +7,13 @@ import (
 	"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
 )
 
-type StageRecord struct {
-	StageName    string              `json:"stagename"`
+type TestRecord struct {
+	TestName     string              `json:"testname"`
 	StageResults []stage.StageResult `json:"stageresults"`
 }
 
 type ScoreboardData struct {
-	StageRecords []StageRecord `json:"stagerecords"`
+	TestRecords []TestRecord `json:"testrecords"`
 }
 
 type Scoreboard struct {
@@ -21,12 +21,12 @@ type Scoreboard struct {
 }
 
 func (b *Scoreboard) Init() {
-	b.scoreboard.StageRecords = make([]StageRecord, 0)
+	b.scoreboard.TestRecords = make([]TestRecord, 0)
 }
 
-func (b *Scoreboard) AddScore(stagename string, results []stage.StageResult) {
-	b.scoreboard.StageRecords = append(b.scoreboard.StageRecords,
-		StageRecord{StageName: stagename, StageResults: results})
+func (b *Scoreboard) AddScore(testname string, results []stage.StageResult) {
+	b.scoreboard.TestRecords = append(b.scoreboard.TestRecords,
+		TestRecord{TestName: testname, StageResults: results})
 }
 
 func (b *Scoreboard) SaveFile(filePath string) {
diff --git a/scripts/submit_scoreboard.sh b/scripts/submit_scoreboard_failedtable.sh
similarity index 62%
rename from scripts/submit_scoreboard.sh
rename to scripts/submit_scoreboard_failedtable.sh
index c104342..1e6d892 100644
--- a/scripts/submit_scoreboard.sh
+++ b/scripts/submit_scoreboard_failedtable.sh
@@ -2,11 +2,12 @@
 export ORIG_HOME=$(grep ^${USER}: /etc/passwd |cut -d : -f 6)
 PATH=$PATH:$ORIG_HOME/.local/bin
 
-if echo "${DRONE_REPO_NAME}" | grep -q '-'; then
-    SUBMITTER_NAME=$(echo "${DRONE_REPO_NAME}" | cut -d'-' -f1);
-else
-    SUBMITTER_NAME=${DRONE_REPO_NAME};
-fi
+# if echo "${DRONE_REPO_NAME}" | grep -q '-'; then
+#     SUBMITTER_NAME=$(echo "${DRONE_REPO_NAME}" | cut -d'-' -f1);
+# else
+#     SUBMITTER_NAME=${DRONE_REPO_NAME};
+# fi
+SUBMITTER_NAME=${DRONE_REPO_NAME}
 
 mkdir repos
 
@@ -19,5 +20,6 @@ echo 'MATTERMOST_ACCESS_TOKEN=""' >> .env
 echo 'MATTERMOST_TEACHING_TEAM=[]' >> .env
 
 joint-teapot JOJ3-scoreboard "score.json" $SUBMITTER_NAME "" "JOJ3-examples" "JOJ3_dev.csv"
+joint-teapot JOJ3-failed-table "score.json" "JOJ3-examples" $DRONE_REPO_NAME $DRONE_REMOTE_URL "JOJ3-failed.md"
 rm score.json
 rm .env
-- 
2.30.2


From 7f5527322626cd22f0d7d3eb21217021f34a5a28 Mon Sep 17 00:00:00 2001
From: zjc_he <zjc_he@sjtu.edu.cn>
Date: Wed, 3 Jul 2024 11:08:54 +0800
Subject: [PATCH 14/15] update submodules

---
 examples/cppcheck/sillycode          | 2 +-
 examples/keyword/clangtidy/sillycode | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/examples/cppcheck/sillycode b/examples/cppcheck/sillycode
index 0815ab9..40fe2db 160000
--- a/examples/cppcheck/sillycode
+++ b/examples/cppcheck/sillycode
@@ -1 +1 @@
-Subproject commit 0815ab90d72641fc274231c075282567e9e17865
+Subproject commit 40fe2dbef18ac5188f72fe788426e3d9c8aa88ae
diff --git a/examples/keyword/clangtidy/sillycode b/examples/keyword/clangtidy/sillycode
index 51160e0..9938ef0 160000
--- a/examples/keyword/clangtidy/sillycode
+++ b/examples/keyword/clangtidy/sillycode
@@ -1 +1 @@
-Subproject commit 51160e0a0cb01159fa264435865185083d756b06
+Subproject commit 9938ef006e25c8caea24493172e60a58380c8df4
-- 
2.30.2


From 8ede2dab4ebdb43833d873b2ae676c86ad10cc3e Mon Sep 17 00:00:00 2001
From: zjc_he <zjc_he@sjtu.edu.cn>
Date: Wed, 3 Jul 2024 11:56:16 +0800
Subject: [PATCH 15/15] update submodules

---
 examples/clangtidy/sillycode       | 2 +-
 examples/compile/error             | 2 +-
 examples/compile/success           | 2 +-
 examples/cpplint/sillycode         | 2 +-
 examples/dummy/error               | 2 +-
 examples/dummy/success             | 2 +-
 examples/keyword/cpplint/sillycode | 2 +-
 7 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/examples/clangtidy/sillycode b/examples/clangtidy/sillycode
index 607ac46..6084f4d 160000
--- a/examples/clangtidy/sillycode
+++ b/examples/clangtidy/sillycode
@@ -1 +1 @@
-Subproject commit 607ac46d3421fd145f2a1f0dbcba9e37f7563be9
+Subproject commit 6084f4dc39929257f35eb2467b5aa105ceb03e81
diff --git a/examples/compile/error b/examples/compile/error
index dc7be30..2593e79 160000
--- a/examples/compile/error
+++ b/examples/compile/error
@@ -1 +1 @@
-Subproject commit dc7be30db1fbfd83ecb78f214cff3f42732a1365
+Subproject commit 2593e79505a93042d308c5fc355dba671dd4fdba
diff --git a/examples/compile/success b/examples/compile/success
index 21f6df7..638e9f6 160000
--- a/examples/compile/success
+++ b/examples/compile/success
@@ -1 +1 @@
-Subproject commit 21f6df70d483f34a99b50335e0a1fbe50d3a82dd
+Subproject commit 638e9f661092d39daaf6e1ffc8ba5998fc56c96a
diff --git a/examples/cpplint/sillycode b/examples/cpplint/sillycode
index a700156..1ec92f3 160000
--- a/examples/cpplint/sillycode
+++ b/examples/cpplint/sillycode
@@ -1 +1 @@
-Subproject commit a7001564a22f9807119efb7b8f4cf6f74d4c12fc
+Subproject commit 1ec92f39ce2fac82356e79ae08c457784769d49c
diff --git a/examples/dummy/error b/examples/dummy/error
index 6cbfd9f..8571a8b 160000
--- a/examples/dummy/error
+++ b/examples/dummy/error
@@ -1 +1 @@
-Subproject commit 6cbfd9ff1ea95cd5c6c5f832e99cda6f9f2ea851
+Subproject commit 8571a8ba30fb2c431d504ed9cfc74d33b9820246
diff --git a/examples/dummy/success b/examples/dummy/success
index b1afead..a933d18 160000
--- a/examples/dummy/success
+++ b/examples/dummy/success
@@ -1 +1 @@
-Subproject commit b1afead762d2b2704823af83847c9155c6a1422b
+Subproject commit a933d18dda38446d96e36ec5032c6dd48546511b
diff --git a/examples/keyword/cpplint/sillycode b/examples/keyword/cpplint/sillycode
index f43b0b3..96d0234 160000
--- a/examples/keyword/cpplint/sillycode
+++ b/examples/keyword/cpplint/sillycode
@@ -1 +1 @@
-Subproject commit f43b0b3a7b873ee935b19e4e5f26a8ceda7d3d61
+Subproject commit 96d02348a20a5a244cd4f82e94a04dccfe3f009c
-- 
2.30.2