-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
report.go
148 lines (125 loc) · 3.78 KB
/
report.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
package testcoverage
import (
"bufio"
"errors"
"fmt"
"io"
"os"
"strconv"
"text/tabwriter"
)
func ReportForHuman(w io.Writer, result AnalyzeResult, thr Threshold) {
out := bufio.NewWriter(w)
defer out.Flush()
{
fmt.Fprintf(out, "Files meeting coverage threshold of (%d%%):\t", thr.File)
if len(result.FilesBelowThreshold) > 0 {
fmt.Fprintf(out, "FAIL")
reportIssuesForHuman(out, result.FilesBelowThreshold)
} else {
fmt.Fprintf(out, "PASS")
}
}
{
fmt.Fprintf(out, "\nPackages meeting coverage threshold of (%d%%):\t", thr.Package)
if len(result.PackagesBelowThreshold) > 0 {
fmt.Fprintf(out, "FAIL")
reportIssuesForHuman(out, result.PackagesBelowThreshold)
} else {
fmt.Fprintf(out, "PASS")
}
}
{
fmt.Fprintf(out, "\nTotal coverage meeting the threshold of (%d%%):\t", thr.Total)
if !result.MeetsTotalCoverage {
fmt.Fprintf(out, "FAIL")
} else {
fmt.Fprintf(out, "PASS")
}
}
fmt.Fprintf(out, "\nTotal test coverage: %d%%\n", result.TotalCoverage)
}
func reportIssuesForHuman(w io.Writer, coverageStats []CoverageStats) {
tabber := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0) //nolint:gomnd // relax
defer tabber.Flush()
fmt.Fprintf(tabber, "\n\nIssues with:")
for _, stats := range coverageStats {
fmt.Fprintf(tabber, "\n%s\t%d%%", stats.Name, stats.CoveredPercentage())
}
fmt.Fprintf(tabber, "\n")
}
func ReportForGithubAction(w io.Writer, result AnalyzeResult, thr Threshold) {
out := bufio.NewWriter(w)
defer out.Flush()
reportLineError := func(file, title, msg string) {
fmt.Fprintf(out, "::error file=%s,title=%s,line=1::%s\n", file, title, msg)
}
reportError := func(title, msg string) {
fmt.Fprintf(out, "::error title=%s::%s\n", title, msg)
}
for _, stats := range result.FilesBelowThreshold {
title := "File test coverage below threshold"
c := stats.CoveredPercentage()
t := thr.File
msg := fmt.Sprintf("coverage: %d%%; threshold: %d%%", c, t)
reportLineError(stats.Name, title, msg)
}
for _, stats := range result.PackagesBelowThreshold {
title := "Package test coverage below threshold"
c := stats.CoveredPercentage()
t := thr.Package
msg := fmt.Sprintf("package: %s; coverage: %d%%; threshold: %d%%", stats.Name, c, t)
reportError(title, msg)
}
if !result.MeetsTotalCoverage {
title := "Total test coverage below threshold"
c := result.TotalCoverage
t := thr.Total
msg := fmt.Sprintf("coverage: %d%%; threshold: %d%%", c, t)
reportError(title, msg)
}
}
const (
gaOutputFileEnv = "GITHUB_OUTPUT"
gaOutputTotalCoverage = "total-coverage"
gaOutputBadgeColor = "badge-color"
gaOutputBadgeText = "badge-text"
)
func SetGithubActionOutput(result AnalyzeResult) error {
file, err := openGitHubOutput(os.Getenv(gaOutputFileEnv))
if err != nil {
return fmt.Errorf("could not open GitHub output file: %w", err)
}
defer file.Close()
totalText := strconv.Itoa(result.TotalCoverage)
return errors.Join(
setOutput(file, gaOutputTotalCoverage, totalText),
setOutput(file, gaOutputBadgeColor, coverageColor(result.TotalCoverage)),
setOutput(file, gaOutputBadgeText, totalText+"%"),
)
}
func openGitHubOutput(p string) (io.WriteCloser, error) {
//nolint:gomnd,wrapcheck //relax
return os.OpenFile(p, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
}
func setOutput(w io.Writer, name, value string) error {
if _, err := w.Write([]byte(fmt.Sprintf("%s=%s\n", name, value))); err != nil {
return fmt.Errorf("failed setting github output [var=%s]: %w", name, err)
}
return nil
}
//nolint:gomnd // relax
func coverageColor(coverage int) string {
switch {
case coverage >= 100:
return "#44cc11" // green
case coverage >= 90:
return "#97ca00" // light green
case coverage >= 80:
return "#dfb317" // yellow
case coverage >= 70:
return "#fa7739" // orange
default:
return "#e05d44" // red
}
}