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

This commit is contained in:
2026-04-06 14:28:51 +03:00
parent cb70adbf09
commit 856d7935b5
3 changed files with 90 additions and 14 deletions

View File

@@ -156,13 +156,27 @@ jobs:
compression-level: 9
summary:
needs: [test]
needs: [build_judge, test]
if: ${{ always() }}
name: SUMMARY
runs-on: Linux-Runner
timeout-minutes: 5
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
uses: https://github.com/christopherHX/gitea-download-artifact@v4
with:
@@ -171,18 +185,7 @@ jobs:
- name: Aggregate
shell: bash
run: |
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
run: judge aggregate reports > SUMMARY.md
- name: Upload summary
uses: https://github.com/christopherHX/gitea-upload-artifact@v4

View File

@@ -14,6 +14,7 @@ const usage = `judge — CI/CD testing system for student solutions
Usage:
judge <tests.jdg> <solution-dir> [flags]
judge aggregate <reports-dir>
Flags:
--json output as JSON instead of text
@@ -24,10 +25,15 @@ Flags:
Example:
judge lab1.jdg ./student-solution
judge lab1.jdg ./student-solution --json
judge lab1.jdg ./student-solution --wrapper "valgrind --error-exitcode=99"
judge aggregate reports/
`
func main() {
if len(os.Args) >= 2 && os.Args[1] == "aggregate" {
runAggregate()
return
}
fs := flag.NewFlagSet("judge", flag.ContinueOnError)
fs.SetOutput(os.Stderr)
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) {
fmt.Fprintf(os.Stderr, "error: "+msg+"\n", args...)
os.Exit(1)

View File

@@ -4,6 +4,9 @@ import (
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"sort"
"strings"
"github.com/Mond1c/judge/runner"
@@ -74,6 +77,60 @@ type jsonTestResult struct {
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 {
res := jsonSuiteResult{
TotalScore: r.TotalScore,