-
Notifications
You must be signed in to change notification settings - Fork 9
/
main.go
137 lines (122 loc) · 3.36 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package main
import (
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"github.com/mcubik/goverreport/report"
"gopkg.in/yaml.v2"
)
// Command arguments
type arguments struct {
coverprofile, metric, sortBy, order string
threshold float64
metricDefaulted bool
packages bool
}
var args arguments
const configFile = ".goverreport.yml"
// Configuration
type configuration struct {
Root string `yaml:"root"`
Exclusions []string `yaml:"exclusions"`
Threshold float64 `yaml:"threshold,omitempty"`
Metric string `yaml:"thresholdType,omitempty"`
}
// Parser arguments
func init() {
flag.StringVar(&args.coverprofile, "coverprofile", "coverage.out", "Coverage output file")
flag.StringVar(&args.sortBy, "sort", "filename", "Column to sort by: filename, package, block, stmt, missing-blocks, missing-stmts")
flag.StringVar(&args.order, "order", "asc", "Sort order: asc, desc")
flag.Float64Var(&args.threshold, "threshold", 0, "Return an error if the coverage is below a threshold")
flag.StringVar(&args.metric, "metric", "block", "Use a specific metric for the threshold: block, stmt")
flag.BoolVar(&args.packages, "packages", false, "Report coverage per package instead of per file")
args.metricDefaulted = true
}
func parseArguments() {
flag.Parse()
flag.Visit(func(f *flag.Flag) {
if f.Name == "metric" {
args.metricDefaulted = false
}
})
}
func main() {
// Parse arguments
parseArguments()
config, err := loadConfig(configFile)
if err != nil {
fmt.Println(err)
os.Exit(2)
}
passed, err := run(config, args, os.Stdout)
if err != nil {
fmt.Println(err)
os.Exit(2)
}
if !passed {
os.Exit(1)
}
}
// Runs the command
func run(config configuration, args arguments, writer io.Writer) (bool, error) {
// Use config values if arguments aren't set
var metric string
var threshold float64
if args.metricDefaulted && config.Metric != "" {
metric = config.Metric
} else {
metric = args.metric
}
if args.threshold == 0 {
threshold = config.Threshold
} else {
threshold = args.threshold
}
rep, err := report.GenerateReport(args.coverprofile, config.Root, config.Exclusions, args.sortBy, args.order, args.packages)
if err != nil {
return false, err
}
report.PrintTable(rep, writer, args.packages)
passed, err := checkThreshold(threshold, rep.Total, metric)
if err != nil {
return false, err
}
return passed, nil
}
// Loads the report configuration from a yml file
func loadConfig(filename string) (configuration, error) {
conf := configuration{Exclusions: []string{}}
data, err := ioutil.ReadFile(filename)
if err != nil {
if !os.IsNotExist(err) {
return conf, err
}
} else {
if err := yaml.Unmarshal(data, &conf); err != nil {
return configuration{}, err
}
}
return conf, nil
}
// Checks whether the coverage is above a threshold value.
// metric states which value will be used to check the threshold,
// block coverage (block) or statement coverage (stmt).
func checkThreshold(threshold float64, total report.Summary, metric string) (bool, error) {
if threshold > 0 {
switch metric {
case "block":
if total.BlockCoverage < threshold {
return false, nil
}
case "stmt":
if total.StmtCoverage < threshold {
return false, nil
}
default:
return false, fmt.Errorf("Invalid metric '%s', use 'block' or 'stmt'", metric)
}
}
return true, nil
}