fix aggregate
Some checks failed
judge / Build judge (push) Successful in 10s
judge / Linux / gcc / Debug (push) Successful in 9s
judge / Linux / clang / Release (push) Successful in 12s
judge / Linux / clang / Sanitized (push) Successful in 11s
judge / Linux / gcc / Release (push) Successful in 11s
judge / Linux / gcc / Sanitized (push) Successful in 10s
judge / Linux / gcc / Debug (valgrind) (push) Successful in 17s
judge / Windows / clang / Debug (push) Successful in 1m28s
judge / Windows / clang / Release (push) Successful in 1m24s
judge / Windows / msvc / Release (push) Successful in 1m28s
judge / Windows / msvc / Debug (push) Successful in 1m33s
judge / SUMMARY (push) Failing after 4s
Some checks failed
judge / Build judge (push) Successful in 10s
judge / Linux / gcc / Debug (push) Successful in 9s
judge / Linux / clang / Release (push) Successful in 12s
judge / Linux / clang / Sanitized (push) Successful in 11s
judge / Linux / gcc / Release (push) Successful in 11s
judge / Linux / gcc / Sanitized (push) Successful in 10s
judge / Linux / gcc / Debug (valgrind) (push) Successful in 17s
judge / Windows / clang / Debug (push) Successful in 1m28s
judge / Windows / clang / Release (push) Successful in 1m24s
judge / Windows / msvc / Release (push) Successful in 1m28s
judge / Windows / msvc / Debug (push) Successful in 1m33s
judge / SUMMARY (push) Failing after 4s
This commit is contained in:
@@ -156,13 +156,27 @@ jobs:
|
|||||||
compression-level: 9
|
compression-level: 9
|
||||||
|
|
||||||
summary:
|
summary:
|
||||||
needs: [test]
|
needs: [build_judge, test]
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
name: SUMMARY
|
name: SUMMARY
|
||||||
runs-on: Linux-Runner
|
runs-on: Linux-Runner
|
||||||
timeout-minutes: 5
|
timeout-minutes: 5
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: Download judge binary
|
||||||
|
uses: https://github.com/christopherHX/gitea-download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: judge-bin
|
||||||
|
path: judge-bin
|
||||||
|
|
||||||
|
- name: Install judge on PATH
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir -p bin
|
||||||
|
cp judge-bin/judge-linux-amd64 bin/judge
|
||||||
|
chmod +x bin/judge
|
||||||
|
echo "$PWD/bin" >> "$GITHUB_PATH"
|
||||||
|
|
||||||
- name: Download all reports
|
- name: Download all reports
|
||||||
uses: https://github.com/christopherHX/gitea-download-artifact@v4
|
uses: https://github.com/christopherHX/gitea-download-artifact@v4
|
||||||
with:
|
with:
|
||||||
@@ -171,18 +185,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Aggregate
|
- name: Aggregate
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: judge aggregate reports > SUMMARY.md
|
||||||
echo "# Judge results" > SUMMARY.md
|
|
||||||
echo "" >> SUMMARY.md
|
|
||||||
echo "| Configuration | Score |" >> SUMMARY.md
|
|
||||||
echo "|---|---|" >> SUMMARY.md
|
|
||||||
shopt -s nullglob
|
|
||||||
for f in reports/*/*.json; do
|
|
||||||
cfg=$(basename "$(dirname "$f")" | sed 's/^report_//')
|
|
||||||
score=$(grep -o '"total_score":[^,}]*' "$f" | head -1 | cut -d: -f2)
|
|
||||||
echo "| $cfg | ${score:- -} |" >> SUMMARY.md
|
|
||||||
done
|
|
||||||
cat SUMMARY.md
|
|
||||||
|
|
||||||
- name: Upload summary
|
- name: Upload summary
|
||||||
uses: https://github.com/christopherHX/gitea-upload-artifact@v4
|
uses: https://github.com/christopherHX/gitea-upload-artifact@v4
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ const usage = `judge — CI/CD testing system for student solutions
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
judge <tests.jdg> <solution-dir> [flags]
|
judge <tests.jdg> <solution-dir> [flags]
|
||||||
|
judge aggregate <reports-dir>
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
--json output as JSON instead of text
|
--json output as JSON instead of text
|
||||||
@@ -24,10 +25,15 @@ Flags:
|
|||||||
Example:
|
Example:
|
||||||
judge lab1.jdg ./student-solution
|
judge lab1.jdg ./student-solution
|
||||||
judge lab1.jdg ./student-solution --json
|
judge lab1.jdg ./student-solution --json
|
||||||
judge lab1.jdg ./student-solution --wrapper "valgrind --error-exitcode=99"
|
judge aggregate reports/
|
||||||
`
|
`
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
if len(os.Args) >= 2 && os.Args[1] == "aggregate" {
|
||||||
|
runAggregate()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
fs := flag.NewFlagSet("judge", flag.ContinueOnError)
|
fs := flag.NewFlagSet("judge", flag.ContinueOnError)
|
||||||
fs.SetOutput(os.Stderr)
|
fs.SetOutput(os.Stderr)
|
||||||
fs.Usage = func() { fmt.Fprint(os.Stderr, usage) }
|
fs.Usage = func() { fmt.Fprint(os.Stderr, usage) }
|
||||||
@@ -85,6 +91,16 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runAggregate() {
|
||||||
|
if len(os.Args) < 3 {
|
||||||
|
fatalf("usage: judge aggregate <reports-dir>")
|
||||||
|
}
|
||||||
|
dir := os.Args[2]
|
||||||
|
if err := reporter.Aggregate(os.Stdout, dir); err != nil {
|
||||||
|
fatalf("%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func fatalf(msg string, args ...any) {
|
func fatalf(msg string, args ...any) {
|
||||||
fmt.Fprintf(os.Stderr, "error: "+msg+"\n", args...)
|
fmt.Fprintf(os.Stderr, "error: "+msg+"\n", args...)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Mond1c/judge/runner"
|
"github.com/Mond1c/judge/runner"
|
||||||
@@ -74,6 +77,60 @@ type jsonTestResult struct {
|
|||||||
Failures []string `json:"failures,omitempty"`
|
Failures []string `json:"failures,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Aggregate(w io.Writer, dir string) error {
|
||||||
|
files, err := filepath.Glob(filepath.Join(dir, "*", "*.json"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("glob reports: %w", err)
|
||||||
|
}
|
||||||
|
if len(files) == 0 {
|
||||||
|
files, _ = filepath.Glob(filepath.Join(dir, "*.json"))
|
||||||
|
}
|
||||||
|
if len(files) == 0 {
|
||||||
|
return fmt.Errorf("no JSON reports found in %s", dir)
|
||||||
|
}
|
||||||
|
sort.Strings(files)
|
||||||
|
|
||||||
|
type entry struct {
|
||||||
|
Config string
|
||||||
|
Score float64
|
||||||
|
}
|
||||||
|
|
||||||
|
var entries []entry
|
||||||
|
allPassed := true
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
data, err := os.ReadFile(f)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("read %s: %w", f, err)
|
||||||
|
}
|
||||||
|
var report jsonSuiteResult
|
||||||
|
if err := json.Unmarshal(data, &report); err != nil {
|
||||||
|
return fmt.Errorf("parse %s: %w", f, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := filepath.Base(filepath.Dir(f))
|
||||||
|
cfg = strings.TrimPrefix(cfg, "report_")
|
||||||
|
|
||||||
|
entries = append(entries, entry{Config: cfg, Score: report.TotalScore})
|
||||||
|
if report.TotalScore < 0.9999 {
|
||||||
|
allPassed = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(w, "# Judge results")
|
||||||
|
fmt.Fprintln(w)
|
||||||
|
fmt.Fprintln(w, "| Configuration | Score |")
|
||||||
|
fmt.Fprintln(w, "|---|---|")
|
||||||
|
for _, e := range entries {
|
||||||
|
fmt.Fprintf(w, "| %s | %.4f |\n", e.Config, e.Score)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !allPassed {
|
||||||
|
return fmt.Errorf("one or more configurations scored below 1.0")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func jsonResult(r *runner.SuiteResult) jsonSuiteResult {
|
func jsonResult(r *runner.SuiteResult) jsonSuiteResult {
|
||||||
res := jsonSuiteResult{
|
res := jsonSuiteResult{
|
||||||
TotalScore: r.TotalScore,
|
TotalScore: r.TotalScore,
|
||||||
|
|||||||
Reference in New Issue
Block a user