cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.22.2

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/reporter/console.go

130lines · modecode

1package reporter
2
3import (
4 "fmt"
5 "io"
6 "os"
7 "sort"
8 "strconv"
9 "strings"
10
11 "github.com/fatih/color"
12 "github.com/rs/zerolog/log"
13
14 "github.com/cloudflare/pint/internal/checks"
15 "github.com/cloudflare/pint/internal/output"
16)
17
18func NewConsoleReporter(output io.Writer) ConsoleReporter {
19 return ConsoleReporter{output: output}
20}
21
22type ConsoleReporter struct {
23 output io.Writer
24}
25
26func (cr ConsoleReporter) Submit(summary Summary) error {
27 reports := summary.Reports
28 reps := reports[:]
29 sort.Slice(reps, func(i, j int) bool {
30 if reports[i].Path < reports[j].Path {
31 return true
32 }
33 if reports[i].Path > reports[j].Path {
34 return false
35 }
36 if reports[i].Problem.Lines[0] < reports[j].Problem.Lines[0] {
37 return true
38 }
39 if reports[i].Problem.Lines[0] > reports[j].Problem.Lines[0] {
40 return false
41 }
42 if reports[i].Problem.Reporter < reports[j].Problem.Reporter {
43 return true
44 }
45 if reports[i].Problem.Reporter > reports[j].Problem.Reporter {
46 return false
47 }
48 return reports[i].Problem.Text < reports[j].Problem.Text
49 })
50
51 perFile := map[string][]string{}
52 for _, report := range reps {
53 if !shouldReport(report) {
54 log.Debug().
55 Str("path", report.Path).
56 Str("lines", output.FormatLineRangeString(report.Problem.Lines)).
57 Msg("Problem reported on unmodified line, skipping")
58 continue
59 }
60
61 if _, ok := perFile[report.Path]; !ok {
62 perFile[report.Path] = []string{}
63 }
64
65 content, err := readFile(report.Path)
66 if err != nil {
67 return err
68 }
69
70 msg := []string{}
71 firstLine, lastLine := report.Problem.LineRange()
72 msg = append(msg, color.CyanString("%s:%s: ", report.Path, printLineRange(firstLine, lastLine)))
73 switch report.Problem.Severity {
74 case checks.Bug, checks.Fatal:
75 msg = append(msg, color.RedString(report.Problem.Text))
76 case checks.Warning:
77 msg = append(msg, color.YellowString(report.Problem.Text))
78 default:
79 msg = append(msg, color.HiBlackString(report.Problem.Text))
80 }
81 msg = append(msg, color.MagentaString(" (%s)\n", report.Problem.Reporter))
82
83 lines := strings.Split(content, "\n")
84 if lastLine > len(lines)-1 {
85 lastLine = len(lines) - 1
86 log.Warn().Str("path", report.Path).Msgf("Tried to read more lines than present in the source file, this is likely due to '\n' usage in some rules, see https://github.com/cloudflare/pint/issues/20 for details")
87 }
88 for _, c := range lines[firstLine-1 : lastLine] {
89 msg = append(msg, color.WhiteString("%s\n", c))
90 }
91 perFile[report.Path] = append(perFile[report.Path], strings.Join(msg, ""))
92 }
93
94 paths := []string{}
95 for path := range perFile {
96 paths = append(paths, path)
97 }
98 sort.Strings(paths)
99
100 for _, path := range paths {
101 msgs := perFile[path]
102 for _, msg := range msgs {
103 fmt.Fprintln(cr.output, msg)
104 }
105 }
106
107 return nil
108}
109
110func readFile(path string) (string, error) {
111 f, err := os.Open(path)
112 if err != nil {
113 return "", err
114 }
115 defer f.Close()
116
117 content, err := io.ReadAll(f)
118 if err != nil {
119 return "", err
120 }
121
122 return string(content), nil
123}
124
125func printLineRange(s, e int) string {
126 if s == e {
127 return strconv.Itoa(s)
128 }
129 return fmt.Sprintf("%d-%d", s, e)
130}
131