forked from seriousben/go-patch-cover
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cover.go
150 lines (132 loc) · 3.9 KB
/
cover.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
138
139
140
141
142
143
144
145
146
147
148
149
150
package patchcover
import (
"html/template"
"io"
"os"
"strings"
"github.com/bluekeyes/go-gitdiff/gitdiff"
"golang.org/x/tools/cover"
)
func ProcessFiles(coverageFile, diffFile, prevCovFile string) (CoverageData, error) {
patch, err := os.Open(diffFile)
if err != nil {
return CoverageData{}, err
}
files, _, err := gitdiff.Parse(patch)
if err != nil {
return CoverageData{}, err
}
profiles, err := cover.ParseProfiles(coverageFile)
if err != nil {
return CoverageData{}, err
}
var prevProfiles []*cover.Profile
if prevCovFile != "" {
prevProfiles, err = cover.ParseProfiles(prevCovFile)
if err != nil {
return CoverageData{}, err
}
}
d, err := computeCoverage(files, profiles, prevProfiles)
if err != nil {
return CoverageData{}, err
}
d.HasPrevCoverage = prevCovFile != ""
return d, nil
}
type CoverageData struct {
NumStmt int `json:"num_stmt"`
CoverCount int `json:"cover_count"`
Coverage float64 `json:"coverage"`
PatchNumStmt int `json:"patch_num_stmt"`
PatchCoverCount int `json:"patch_cover_count"`
PatchCoverage float64 `json:"patch_coverage"`
HasPrevCoverage bool `json:"has_prev_coverage"`
PrevNumStmt int `json:"prev_num_stmt"`
PrevCoverCount int `json:"prev_cover_count"`
PrevCoverage float64 `json:"prev_coverage"`
}
func RenderTemplateOutput(data CoverageData, tmplOverride string, out io.Writer) error {
const defaultTmpl = `
{{- if .HasPrevCoverage -}}
previous coverage: {{printf "%.1f" .PrevCoverage}}% of statements
{{ else -}}
previous coverage: unknown
{{ end -}}
new coverage: {{printf "%.1f" .Coverage}}% of statements
patch coverage: {{printf "%.1f" .PatchCoverage}}% of changed statements ({{ .PatchCoverCount }}/{{ .PatchNumStmt }})
`
tmpl := defaultTmpl
if tmplOverride != "" {
tmpl = tmplOverride
}
t, err := template.New("cover_template").Parse(tmpl)
if err != nil {
return err
}
return t.ExecuteTemplate(out, "cover_template", data)
}
func computeCoverage(diffFiles []*gitdiff.File, coverProfiles []*cover.Profile, prevCoverProfiles []*cover.Profile) (CoverageData, error) {
var data CoverageData
// patch coverage
for _, p := range coverProfiles {
for _, f := range diffFiles {
// Using suffix since profiles are prepended with the go module.
if !strings.HasSuffix(p.FileName, f.NewName) {
//fmt.Printf("%s != %s\n", p.FileName, f.NewName)
continue
}
blockloop:
for _, b := range p.Blocks {
//fmt.Printf("BLOCK %s:%d %d %d %d\n", p.FileName, b.StartLine, b.EndLine, b.NumStmt, b.Count)
for _, t := range f.TextFragments {
for i, line := range t.Lines {
if line.Op != gitdiff.OpAdd {
continue
}
lineNum := int(t.NewPosition) + i
//lineString := strings.ReplaceAll(line.Line, "\n", "")
// fmt.Printf("DIFF %s:%d %s\n", f.NewName, lineNum, lineString)
if b.StartLine <= lineNum && lineNum <= b.EndLine {
data.PatchNumStmt += b.NumStmt
// fmt.Printf("COVER %s:%d %d %d - %s\n", p.FileName, lineNum, b.NumStmt, b.Count, lineString)
if b.Count > 0 {
data.PatchCoverCount += b.NumStmt
}
continue blockloop
}
}
}
}
}
}
// total coverage
for _, p := range coverProfiles {
for _, b := range p.Blocks {
data.NumStmt += b.NumStmt
if b.Count > 0 {
data.CoverCount += b.NumStmt
}
}
}
// prev total coverage
for _, p := range prevCoverProfiles {
for _, b := range p.Blocks {
data.PrevNumStmt += b.NumStmt
if b.Count > 0 {
data.PrevCoverCount += b.NumStmt
}
}
}
// TODO: Previous coverage
if data.NumStmt != 0 {
data.Coverage = float64(data.CoverCount) / float64(data.NumStmt) * 100
}
if data.PatchNumStmt != 0 {
data.PatchCoverage = float64(data.PatchCoverCount) / float64(data.PatchNumStmt) * 100
}
if data.PrevNumStmt != 0 {
data.PrevCoverage = float64(data.PrevCoverCount) / float64(data.PrevNumStmt) * 100
}
return data, nil
}