@@ -28,7 +28,7 @@ The execution starts here:
28
28
29
29
``` go title=cmd/golangci-lint/main.go
30
30
func main () {
31
- e := commands.NewExecutor (version, commit, date )
31
+ e := commands.NewExecutor (info )
32
32
33
33
if err := e.Execute (); err != nil {
34
34
fmt.Fprintf (os.Stderr , " failed executing command with error %v \n " , err)
@@ -45,7 +45,8 @@ type Executor struct {
45
45
runCmd *cobra.Command
46
46
lintersCmd *cobra.Command
47
47
48
- exitCode int
48
+ exitCode int
49
+ buildInfo BuildInfo
49
50
50
51
cfg *config.Config
51
52
log logutils.Log
@@ -69,9 +70,9 @@ We use dependency injection and all root dependencies are stored in this executo
69
70
70
71
In the function ` NewExecutor ` we do the following:
71
72
72
- 1 . init dependencies
73
- 2 . init [ cobra] ( https://github.com/spf13/cobra ) commands
74
- 3 . parse config file using [ viper] ( https://github.com/spf13/viper ) and merge it with command line args .
73
+ 1 . Initialize dependencies.
74
+ 2 . Initialize [ cobra] ( https://github.com/spf13/cobra ) commands.
75
+ 3 . Parse the config file using [ viper] ( https://github.com/spf13/viper ) and merge it with command line arguments .
75
76
76
77
The following execution is controlled by ` cobra ` . If a user executes ` golangci-lint run `
77
78
then ` cobra ` executes ` e.runCmd ` .
@@ -82,19 +83,23 @@ Different `cobra` commands have different runners, e.g. a `run` command is confi
82
83
func (e *Executor ) initRun () {
83
84
e.runCmd = &cobra.Command {
84
85
Use: " run" ,
85
- Short: welcomeMessage ,
86
+ Short: " Run the linters " ,
86
87
Run: e.executeRun ,
87
- PreRun : func (_ *cobra.Command , _ []string ) {
88
+ PreRunE : func (_ *cobra.Command , _ []string ) error {
88
89
if ok := e.acquireFileLock (); !ok {
89
- e. log . Fatalf ( " Parallel golangci-lint is running" )
90
+ return errors. New ( " parallel golangci-lint is running" )
90
91
}
92
+ return nil
91
93
},
92
94
PostRun: func (_ *cobra.Command , _ []string ) {
93
95
e.releaseFileLock ()
94
96
},
95
97
}
96
98
e.rootCmd .AddCommand (e.runCmd )
97
- e.runCmd .SetOutput (logutils.StdOut ) // use custom output to properly color it in Windows terminals
99
+
100
+ e.runCmd .SetOut (logutils.StdOut ) // use custom output to properly color it in Windows terminals
101
+ e.runCmd .SetErr (logutils.StdErr )
102
+
98
103
e.initRunConfiguration (e.runCmd )
99
104
}
100
105
```
@@ -114,13 +119,13 @@ func (cl *ContextLoader) Load(ctx context.Context, linters []*linter.Config) (*l
114
119
loadMode := cl.findLoadMode (linters)
115
120
pkgs , err := cl.loadPackages (ctx, loadMode)
116
121
if err != nil {
117
- return nil , err
122
+ return nil , fmt. Errorf ( " failed to load packages: % w " , err)
118
123
}
119
124
120
- // ...
121
- ret := &linter.Context {
122
- // ...
123
- }
125
+ // ...
126
+ ret := &linter.Context {
127
+ // ...
128
+ }
124
129
return ret, nil
125
130
}
126
131
```
@@ -142,10 +147,11 @@ func (lc *Config) WithLoadFiles() *Config {
142
147
143
148
If a linter uses ` go/analysis ` and needs type information, we need to extract more data by ` go/packages ` :
144
149
145
- ``` go title=/ pkg/lint/linter/config.go
150
+ ``` go title=pkg/lint/linter/config.go
146
151
func (lc *Config ) WithLoadForGoAnalysis () *Config {
147
152
lc = lc.WithLoadFiles ()
148
- lc.LoadMode |= packages.NeedImports | packages.NeedDeps | packages.NeedExportsFile | packages.NeedTypesSizes
153
+ lc.LoadMode |= packages.NeedImports | packages.NeedDeps | packages.NeedExportFile | packages.NeedTypesSizes
154
+ lc.IsSlow = true
149
155
return lc
150
156
}
151
157
```
@@ -159,20 +165,24 @@ First, we need to find all enabled linters. All linters are registered here:
159
165
160
166
``` go title=pkg/lint/lintersdb/manager.go
161
167
func (m Manager ) GetAllSupportedLinterConfigs () []*linter .Config {
162
- // ...
163
- lcs := []*linter.Config {
168
+ // ...
169
+ linters = append (linters,
170
+ // ...
171
+ linter.NewConfig (golinters.NewBodyclose ()).
172
+ WithSince (" v1.18.0" ).
173
+ WithLoadForGoAnalysis ().
174
+ WithPresets (linter.PresetPerformance , linter.PresetBugs ).
175
+ WithURL (" https://github.com/timakin/bodyclose" ),
176
+ // ...
164
177
linter.NewConfig (golinters.NewGovet (govetCfg)).
178
+ WithEnabledByDefault ().
179
+ WithSince (" v1.0.0" ).
165
180
WithLoadForGoAnalysis ().
166
- WithPresets (linter.PresetBugs ).
181
+ WithPresets (linter.PresetBugs , linter. PresetMetaLinter ).
167
182
WithAlternativeNames (" vet" , " vetshadow" ).
168
183
WithURL (" https://pkg.go.dev/cmd/vet" ),
169
- linter.NewConfig (golinters.NewBodyclose ()).
170
- WithLoadForGoAnalysis ().
171
- WithPresets (linter.PresetPerformance , linter.PresetBugs ).
172
- WithURL (" https://github.com/timakin/bodyclose" ),
173
- // ...
174
- }
175
- // ...
184
+ }
185
+ // ...
176
186
}
177
187
```
178
188
@@ -189,9 +199,9 @@ We merge enabled linters into one `MetaLinter` to improve execution time if we c
189
199
// into a fewer number of linters. E.g. some go/analysis linters can be optimized into
190
200
// one metalinter for data reuse and speed up.
191
201
func (es EnabledSet) GetOptimizedLinters() ([]*linter.Config, error) {
192
- // ...
193
- es.combineGoAnalysisLinters (resultLintersSet)
194
- // ...
202
+ // ...
203
+ es.combineGoAnalysisLinters (resultLintersSet)
204
+ // ...
195
205
}
196
206
```
197
207
@@ -221,6 +231,8 @@ type Issue struct {
221
231
FromLinter string
222
232
Text string
223
233
234
+ Severity string
235
+
224
236
// Source lines of a code with the issue to show
225
237
SourceLines []string
226
238
@@ -250,8 +262,10 @@ We have an abstraction of `result.Processor` to postprocess found issues:
250
262
``` sh
251
263
$ tree -L 1 ./pkg/result/processors/
252
264
./pkg/result/processors/
265
+ ./pkg/result/processors/
253
266
├── autogenerated_exclude.go
254
267
├── autogenerated_exclude_test.go
268
+ ├── base_rule.go
255
269
├── cgo.go
256
270
├── diff.go
257
271
├── exclude.go
@@ -262,6 +276,7 @@ $ tree -L 1 ./pkg/result/processors/
262
276
├── fixer.go
263
277
├── identifier_marker.go
264
278
├── identifier_marker_test.go
279
+ ├── issues.go
265
280
├── max_from_linter.go
266
281
├── max_from_linter_test.go
267
282
├── max_per_file_from_linter.go
@@ -270,17 +285,23 @@ $ tree -L 1 ./pkg/result/processors/
270
285
├── max_same_issues_test.go
271
286
├── nolint.go
272
287
├── nolint_test.go
288
+ ├── path_prefixer.go
289
+ ├── path_prefixer_test.go
273
290
├── path_prettifier.go
274
291
├── path_shortener.go
275
292
├── processor.go
293
+ ├── processor_test.go
294
+ ├── severity_rules.go
295
+ ├── severity_rules_test.go
276
296
├── skip_dirs.go
277
297
├── skip_files.go
278
298
├── skip_files_test.go
299
+ ├── sort_results.go
300
+ ├── sort_results_test.go
279
301
├── source_code.go
280
302
├── testdata
281
303
├── uniq_by_line.go
282
- ├── uniq_by_line_test.go
283
- └── utils.go
304
+ └── uniq_by_line_test.go
284
305
```
285
306
286
307
The abstraction is simple:
@@ -303,14 +324,24 @@ We have an abstraction for printing found issues.
303
324
$ tree -L 1 ./pkg/printers/
304
325
./pkg/printers/
305
326
├── checkstyle.go
327
+ ├── checkstyle_test.go
306
328
├── codeclimate.go
329
+ ├── codeclimate_test.go
307
330
├── github.go
308
331
├── github_test.go
332
+ ├── html.go
333
+ ├── html_test.go
309
334
├── json.go
335
+ ├── json_test.go
310
336
├── junitxml.go
337
+ ├── junitxml_test.go
311
338
├── printer.go
312
339
├── tab.go
313
- └── text.go
340
+ ├── tab_test.go
341
+ ├── teamcity.go
342
+ ├── teamcity_test.go
343
+ ├── text.go
344
+ └── text_test.go
314
345
```
315
346
316
347
Needed printer is selected by command line option ` --out-format ` .
0 commit comments