Files
goreportcard/check/check.go
80111+shawnps@users.noreply.github.com f236fc9a56 add back RevertFiles for CLI #397
2024-03-31 12:28:37 +09:00

126 lines
3.2 KiB
Go

package check
import (
"fmt"
"log"
"sort"
)
// Check describes what methods various checks (gofmt, go lint, etc.)
// should implement
type Check interface {
Name() string
Description() string
Weight() float64
// Percentage returns the passing percentage of the check,
// as well as a map of filename to output
Percentage() (float64, []FileSummary, error)
}
// Score represents the result of a single check
type Score struct {
Name string `json:"name"`
Description string `json:"description"`
FileSummaries []FileSummary `json:"file_summaries"`
Weight float64 `json:"weight"`
Percentage float64 `json:"percentage"`
Error string `json:"error"`
}
// ChecksResult represents the combined result of multiple checks
type ChecksResult struct {
Checks []Score `json:"checks"`
Average float64 `json:"average"`
Grade Grade `json:"GradeFromPercentage"`
Files int `json:"files"`
Issues int `json:"issues"`
DidError bool `json:"did_error"`
}
// Run executes all checks on the given directory
func Run(dir string, cli bool) (ChecksResult, error) {
filenames, skipped, err := GoFiles(dir)
if err != nil {
return ChecksResult{}, fmt.Errorf("could not get filenames: %v", err)
}
if len(filenames) == 0 {
return ChecksResult{}, fmt.Errorf("no .go files found")
}
err = RenameFiles(skipped)
if err != nil {
log.Println("Could not rename files:", err)
}
if cli {
defer RevertFiles(skipped)
}
checks := []Check{
GoFmt{Dir: dir, Filenames: filenames},
GoVet{Dir: dir, Filenames: filenames},
// GoLint{Dir: dir, Filenames: filenames},
GoCyclo{Dir: dir, Filenames: filenames},
License{Dir: dir, Filenames: []string{}},
Misspell{Dir: dir, Filenames: filenames},
IneffAssign{Dir: dir, Filenames: filenames},
// Staticcheck{Dir: dir, Filenames: filenames},
// ErrCheck{Dir: dir, Filenames: filenames}, // disable errcheck for now, too slow and not finalized
}
ch := make(chan Score)
for _, c := range checks {
go func(c Check) {
p, summaries, err := c.Percentage()
errMsg := ""
if err != nil {
log.Printf("ERROR: (%s) %v", c.Name(), err)
errMsg = err.Error()
}
s := Score{
Name: c.Name(),
Description: c.Description(),
FileSummaries: summaries,
Weight: c.Weight(),
Percentage: p,
Error: errMsg,
}
ch <- s
}(c)
}
resp := ChecksResult{
Files: len(filenames),
}
var total, totalWeight float64
var issues = make(map[string]bool)
for i := 0; i < len(checks); i++ {
s := <-ch
resp.Checks = append(resp.Checks, s)
total += s.Percentage * s.Weight
totalWeight += s.Weight
for _, fs := range s.FileSummaries {
issues[fs.Filename] = true
}
if s.Error != "" {
resp.DidError = true
}
}
total /= totalWeight
sort.Sort(ByWeight(resp.Checks))
resp.Average = total
resp.Issues = len(issues)
resp.Grade = GradeFromPercentage(total * 100)
return resp, nil
}
// ByWeight implements sorting for checks by weight descending
type ByWeight []Score
func (a ByWeight) Len() int { return len(a) }
func (a ByWeight) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByWeight) Less(i, j int) bool { return a[i].Weight > a[j].Weight }