Skip to content

Commit

Permalink
Introduce the "report" command to combine multiple evaluations into a…
Browse files Browse the repository at this point in the history
… single file

Closes #205
  • Loading branch information
ruiAzevedo19 committed Jul 17, 2024
1 parent 5a7fb63 commit 090eeb2
Show file tree
Hide file tree
Showing 6 changed files with 616 additions and 2 deletions.
1 change: 1 addition & 0 deletions cmd/eval-dev-quality/cmd/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
type Command struct {
Evaluate `command:"evaluate" description:"Run an evaluation, by default with all defined models, repositories and tasks."`
InstallTools `command:"install-tools" description:"Checks and installs all tools required for the evaluation benchmark."`
Report `command:"report" description:"Combines the results of multiple evaluations."`
Version `command:"version" description:"Display the version information of the binary."`
}

Expand Down
6 changes: 4 additions & 2 deletions cmd/eval-dev-quality/cmd/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func TestExecute(t *testing.T) {

ExpectedOutput: bytesutil.StringTrimIndentations(`
Usage:
eval-dev-quality [OPTIONS] [evaluate | install-tools | version]
eval-dev-quality [OPTIONS] [command]
Command to manage, update and actually execute the ` + "`" + `eval-dev-quality` + "`" + `
evaluation benchmark.
Expand All @@ -47,6 +47,7 @@ func TestExecute(t *testing.T) {
Available commands:
evaluate Run an evaluation, by default with all defined models, repositories and tasks.
install-tools Checks and installs all tools required for the evaluation benchmark.
report Combines the results of multiple evaluations.
version Display the version information of the binary.
`),
})
Expand All @@ -56,7 +57,7 @@ func TestExecute(t *testing.T) {

ExpectedOutput: bytesutil.StringTrimIndentations(`
Usage:
eval-dev-quality [OPTIONS] [evaluate | install-tools | version]
eval-dev-quality [OPTIONS] [command]
Command to manage, update and actually execute the ` + "`" + `eval-dev-quality` + "`" + `
evaluation benchmark.
Expand All @@ -67,6 +68,7 @@ func TestExecute(t *testing.T) {
Available commands:
evaluate Run an evaluation, by default with all defined models, repositories and tasks.
install-tools Checks and installs all tools required for the evaluation benchmark.
report Combines the results of multiple evaluations.
version Display the version information of the binary.
`),
})
Expand Down
107 changes: 107 additions & 0 deletions cmd/eval-dev-quality/cmd/report.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package cmd

import (
"os"
"path/filepath"
"sort"

pkgerrors "github.com/pkg/errors"
"golang.org/x/exp/maps"

"github.com/symflower/eval-dev-quality/evaluate/report"
"github.com/symflower/eval-dev-quality/log"
)

// Report holds the "report" command.
type Report struct {
// EvaluationPaths holds the list of file paths where the results of previous evaluations are stored.
EvaluationPaths []string `long:"evaluation-path" description:"File path for an evaluation CSV file where the results of a previous evaluation are stored."`
// ResultPath holds the directory path where the overall results should be written to.
ResultPath string `long:"result-path" description:"Directory path were the combined results are written to."`

// logger holds the logger of the command.
logger *log.Logger
}

var _ SetLogger = (*Evaluate)(nil)

// SetLogger sets the logger of the command.
func (command *Report) SetLogger(logger *log.Logger) {
command.logger = logger
}

// Execute executes the command.
func (command *Report) Execute(args []string) (err error) {
// Create the result path directory and check if there is already an evaluation CSV file in there.
var evaluationCSVFile *os.File
if err = os.MkdirAll(filepath.Dir(command.ResultPath), 0755); err != nil {
command.logger.Panicf("ERROR: %s", err)
}
if _, err := os.Stat(filepath.Join(command.ResultPath, "evaluation.csv")); err != nil {
if os.IsNotExist(err) {
evaluationCSVFile, err = os.Create(filepath.Join(command.ResultPath, "evaluation.csv"))
if err != nil {
command.logger.Panicf("ERROR: %s", err)
}
defer evaluationCSVFile.Close()
} else {
command.logger.Panicf("ERROR: %s", err)
}
} else {
command.logger.Panicf("ERROR: an evaluation CSV file already exists in %s", command.ResultPath)
}

var allRecords []string
for _, evaluationPath := range command.EvaluationPaths {
// Collect all evaluation CSV file paths.
evaluationFilePaths, err := pathsFromGlobPattern(evaluationPath)
if err != nil {
command.logger.Panicf("ERROR: %s", err)
}
// Collect all records from the evaluation CSV files.
records, err := report.RecordsFromEvaluationCSVFiles(evaluationFilePaths)
if err != nil {
command.logger.Panicf("ERROR: %s", err)
}
allRecords = append(allRecords, records...)
}

if len(allRecords) == 0 {
command.logger.Printf("no evaluation records found in %+v", command.EvaluationPaths)

return nil
}
sort.Strings(allRecords)

// Write all records into a single evaluation CSV file.
evaluationFile, err := report.NewEvaluationFile(evaluationCSVFile)
if err != nil {
command.logger.Panicf("ERROR: %s", err)
}
if err := evaluationFile.WriteEvaluationRawRecords(allRecords); err != nil {
command.logger.Panicf("ERROR: %s", err)
}

return nil
}

// pathsFromGlobPattern returns all evaluation CSV file paths.
func pathsFromGlobPattern(evaluationGlobPattern string) (evaluationFilePaths []string, err error) {
if filepath.Base(evaluationGlobPattern) != "evaluation.csv" {
return nil, pkgerrors.WithStack(pkgerrors.Errorf(`the path needs to end with "evaluation.csv" file, but found %q`, evaluationGlobPattern))
}

evaluationGlobFilePaths, err := filepath.Glob(evaluationGlobPattern)
if err != nil {
return nil, pkgerrors.WithStack(err)
} else if len(evaluationGlobFilePaths) == 0 {
return nil, pkgerrors.Errorf("no files matched the pattern %q", evaluationGlobPattern)
}

evaluationCSVFilePaths := map[string]bool{}
for _, evaluationCSVFilePath := range evaluationGlobFilePaths {
evaluationCSVFilePaths[evaluationCSVFilePath] = true
}

return maps.Keys(evaluationCSVFilePaths), nil
}
Loading

0 comments on commit 090eeb2

Please sign in to comment.