forked from reviewdog/reviewdog
-
Notifications
You must be signed in to change notification settings - Fork 0
/
reviewdog.go
141 lines (119 loc) · 3.81 KB
/
reviewdog.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
package reviewdog
import (
"bytes"
"context"
"fmt"
"io"
"os"
"github.com/reviewdog/reviewdog/diff"
"github.com/reviewdog/reviewdog/filter"
"github.com/reviewdog/reviewdog/parser"
"github.com/reviewdog/reviewdog/pathutil"
"github.com/reviewdog/reviewdog/proto/rdf"
)
// Reviewdog represents review dog application which parses result of compiler
// or linter, get diff and filter the results by diff, and report filtered
// results.
type Reviewdog struct {
toolname string
p parser.Parser
c CommentService
d DiffService
filterMode filter.Mode
failLevel FailLevel
}
// NewReviewdog returns a new Reviewdog.
func NewReviewdog(toolname string, p parser.Parser, c CommentService, d DiffService, filterMode filter.Mode, failLevel FailLevel) *Reviewdog {
return &Reviewdog{p: p, c: c, d: d, toolname: toolname, filterMode: filterMode, failLevel: failLevel}
}
// RunFromResult creates a new Reviewdog and runs it with check results.
func RunFromResult(ctx context.Context, c CommentService, results []*rdf.Diagnostic,
filediffs []*diff.FileDiff, strip int, toolname string, filterMode filter.Mode, failLevel FailLevel) error {
return (&Reviewdog{c: c, toolname: toolname, filterMode: filterMode, failLevel: failLevel}).runFromResult(ctx, results, filediffs, strip)
}
// Comment represents a reported result as a comment.
type Comment struct {
Result *filter.FilteredDiagnostic
ToolName string
}
// CommentService is an interface which posts Comment.
type CommentService interface {
Post(context.Context, *Comment) error
}
// FilteredCommentService is an interface which support posting filtered Comment.
type FilteredCommentService interface {
CommentService
PostFiltered(context.Context, *Comment) error
}
// BulkCommentService posts comments all at once when Flush() is called.
// Flush() will be called at the end of each reviewdog run.
type BulkCommentService interface {
CommentService
Flush(context.Context) error
}
// NamedCommentService can set tool name and level. Useful for update tool name
// for each reviewdog run with reviewdog project config.
type NamedCommentService interface {
CommentService
SetTool(toolName string, level string)
}
// DiffService is an interface which get diff.
type DiffService interface {
Diff(context.Context) ([]byte, error)
Strip() int
}
func (w *Reviewdog) runFromResult(ctx context.Context, results []*rdf.Diagnostic,
filediffs []*diff.FileDiff, strip int) error {
wd, err := os.Getwd()
if err != nil {
return err
}
pathutil.NormalizePathInResults(results, wd)
checks := filter.FilterCheck(results, filediffs, strip, wd, w.filterMode)
shouldFail := false
for _, check := range checks {
comment := &Comment{
Result: check,
ToolName: w.toolname,
}
if !check.ShouldReport {
if fc, ok := w.c.(FilteredCommentService); ok {
if err := fc.PostFiltered(ctx, comment); err != nil {
return err
}
} else {
continue
}
} else {
if err := w.c.Post(ctx, comment); err != nil {
return err
}
shouldFail = shouldFail || w.failLevel.ShouldFail(check.Diagnostic.GetSeverity())
}
}
if bulk, ok := w.c.(BulkCommentService); ok {
if err := bulk.Flush(ctx); err != nil {
return err
}
}
if shouldFail {
return fmt.Errorf("found at least one issue with severity greater than or equal to the given level: %s", w.failLevel.String())
}
return nil
}
// Run runs Reviewdog application.
func (w *Reviewdog) Run(ctx context.Context, r io.Reader) error {
results, err := w.p.Parse(r)
if err != nil {
return fmt.Errorf("parse error: %w", err)
}
d, err := w.d.Diff(ctx)
if err != nil {
return fmt.Errorf("fail to get diff: %w", err)
}
filediffs, err := diff.ParseMultiFile(bytes.NewReader(d))
if err != nil {
return fmt.Errorf("fail to parse diff: %w", err)
}
return w.runFromResult(ctx, results, filediffs, w.d.Strip())
}