126 lines
2.7 KiB
Go
126 lines
2.7 KiB
Go
package ci
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"github.com/logrusorgru/aurora"
|
|
"github.com/spf13/viper"
|
|
"github.com/wagoodman/dive/image"
|
|
"io/ioutil"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
func NewEvaluator() *Evaluator {
|
|
ciConfig := viper.New()
|
|
ciConfig.SetConfigType("yaml")
|
|
|
|
ciConfig.SetDefault("rules.lowestEfficiency", 0.9)
|
|
ciConfig.SetDefault("rules.highestWastedBytes", "disabled")
|
|
ciConfig.SetDefault("rules.highestUserWastedPercent", 0.1)
|
|
|
|
return &Evaluator{
|
|
Config: ciConfig,
|
|
Rules: loadCiRules(),
|
|
Results: make(map[string]RuleResult),
|
|
Pass: true,
|
|
}
|
|
}
|
|
|
|
func (ci *Evaluator) LoadConfig(configFile string) error {
|
|
fileBytes, err := ioutil.ReadFile(configFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = ci.Config.ReadConfig(bytes.NewBuffer(fileBytes))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ci *Evaluator) isRuleEnabled(rule Rule) bool {
|
|
value := ci.Config.GetString(rule.Key())
|
|
return value != "disabled"
|
|
}
|
|
|
|
func (ci *Evaluator) Evaluate(analysis *image.AnalysisResult) bool {
|
|
for _, rule := range ci.Rules {
|
|
if ci.isRuleEnabled(rule) {
|
|
|
|
value := ci.Config.GetString(rule.Key())
|
|
status, message := rule.Evaluate(analysis, value)
|
|
|
|
if _, exists := ci.Results[rule.Key()]; exists {
|
|
panic(fmt.Errorf("CI rule result recorded twice: %s", rule.Key()))
|
|
}
|
|
|
|
if status == RuleFailed {
|
|
ci.Pass = false
|
|
}
|
|
|
|
ci.Results[rule.Key()] = RuleResult{
|
|
status: status,
|
|
message: message,
|
|
}
|
|
} else {
|
|
ci.Results[rule.Key()] = RuleResult{
|
|
status: RuleDisabled,
|
|
message: "rule disabled",
|
|
}
|
|
}
|
|
}
|
|
|
|
ci.Tally.Total = len(ci.Results)
|
|
for rule, result := range ci.Results {
|
|
switch result.status {
|
|
case RulePassed:
|
|
ci.Tally.Pass++
|
|
case RuleFailed:
|
|
ci.Tally.Fail++
|
|
case RuleWarning:
|
|
ci.Tally.Warn++
|
|
case RuleDisabled:
|
|
ci.Tally.Skip++
|
|
default:
|
|
panic(fmt.Errorf("unknown test status (rule='%v'): %v", rule, result.status))
|
|
}
|
|
}
|
|
|
|
return ci.Pass
|
|
}
|
|
|
|
func (ci *Evaluator) Report() {
|
|
status := "PASS"
|
|
|
|
rules := make([]string, 0, len(ci.Results))
|
|
for name := range ci.Results {
|
|
rules = append(rules, name)
|
|
}
|
|
sort.Strings(rules)
|
|
|
|
if ci.Tally.Fail > 0 {
|
|
status = "FAIL"
|
|
}
|
|
|
|
for _, rule := range rules {
|
|
result := ci.Results[rule]
|
|
name := strings.TrimPrefix(rule, "rules.")
|
|
if result.message != "" {
|
|
fmt.Printf(" %s: %s: %s\n", result.status.String(), name, result.message)
|
|
} else {
|
|
fmt.Printf(" %s: %s\n", result.status.String(), name)
|
|
}
|
|
}
|
|
|
|
summary := fmt.Sprintf("Result:%s [Total:%d] [Passed:%d] [Failed:%d] [Warn:%d] [Skipped:%d]", status, ci.Tally.Total, ci.Tally.Pass, ci.Tally.Fail, ci.Tally.Warn, ci.Tally.Skip)
|
|
if ci.Pass {
|
|
fmt.Println(aurora.Green(summary))
|
|
} else if ci.Pass && ci.Tally.Warn > 0 {
|
|
fmt.Println(aurora.Blue(summary))
|
|
} else {
|
|
fmt.Println(aurora.Red(summary))
|
|
}
|
|
}
|