-
Notifications
You must be signed in to change notification settings - Fork 16
/
run-linter.go
147 lines (127 loc) · 3.5 KB
/
run-linter.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
package main
import (
"bytes"
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"github.com/mongodb/grip"
)
type result struct {
name string
cmd string
passed bool
duration time.Duration
output []string
}
// String prints the results of a linter run in gotest format.
func (r *result) String() string {
buf := &bytes.Buffer{}
fmt.Fprintln(buf, "=== RUN", r.name)
if r.passed {
fmt.Fprintf(buf, "--- PASS: %s (%s)", r.name, r.duration)
} else {
fmt.Fprintf(buf, strings.Join(r.output, "\n"))
fmt.Fprintf(buf, "--- FAIL: %s (%s)", r.name, r.duration)
}
return buf.String()
}
// fixup goes through the output and improves the output generated by
// specific linters so that all output includes the relative path to the
// error, instead of mixing relative and absolute paths.
func (r *result) fixup(dirname string) {
for idx, ln := range r.output {
if strings.HasPrefix(ln, dirname) {
r.output[idx] = ln[len(dirname)+1:]
}
}
}
// runs the golangci-lint on a list of packages; integrating with the "make lint" target.
func main() {
var (
lintArgs string
lintBin string
customLintersFlag string
customLinters []string
packageList string
output string
packages []string
results []*result
hasFailingTest bool
gopath = os.Getenv("GOPATH")
)
gopath, _ = filepath.Abs(gopath)
flag.StringVar(&lintArgs, "lintArgs", "", "args to pass to golangci-lint")
flag.StringVar(&lintBin, "lintBin", filepath.Join(gopath, "bin", "golangci-lint"), "path to golangci-lint")
flag.StringVar(&packageList, "packages", "", "list of space separated packages")
flag.StringVar(&customLintersFlag, "customLinters", "", "list of comma-separated custom linter commands")
flag.StringVar(&output, "output", "", "output file for to write results.")
flag.Parse()
if len(customLintersFlag) != 0 {
customLinters = strings.Split(customLintersFlag, ",")
}
packages = strings.Split(strings.Replace(packageList, "-", "/", -1), " ")
dirname, _ := os.Getwd()
cwd := filepath.Base(dirname)
for _, pkg := range packages {
pkgDir := "./"
if cwd != pkg {
pkgDir += pkg
}
splitLintArgs := strings.Split(lintArgs, " ")
args := []string{lintBin, "run"}
args = append(args, splitLintArgs...)
args = append(args, pkgDir)
startAt := time.Now()
cmd := exec.Command(args[0], args[1:]...)
cmd.Dir = dirname
out, err := cmd.CombinedOutput()
r := &result{
cmd: strings.Join(args, " "),
name: "lint-" + strings.Replace(pkg, "/", "-", -1),
passed: err == nil,
duration: time.Since(startAt),
output: strings.Split(string(out), "\n"),
}
for _, linter := range customLinters {
customLinterStart := time.Now()
linterArgs := strings.Split(linter, " ")
linterArgs = append(linterArgs, pkgDir)
cmd := exec.Command(linterArgs[0], linterArgs[1:]...)
cmd.Dir = dirname
out, err := cmd.CombinedOutput()
r.passed = r.passed && err == nil
r.duration += time.Since(customLinterStart)
r.output = append(r.output, strings.Split(string(out), "\n")...)
}
r.fixup(dirname)
if !r.passed {
hasFailingTest = true
}
results = append(results, r)
fmt.Println(r)
}
if output != "" {
f, err := os.Create(output)
if err != nil {
os.Exit(1)
}
defer func() {
if err != f.Close() {
panic(err)
}
}()
for _, r := range results {
if _, err = f.WriteString(r.String() + "\n"); err != nil {
grip.Error(err)
os.Exit(1)
}
}
}
if hasFailingTest {
os.Exit(1)
}
}