@@ -8,12 +8,14 @@ import (
8
8
"io/ioutil"
9
9
"log"
10
10
"os"
11
+ "path/filepath"
11
12
"runtime"
12
13
"strings"
13
14
"time"
14
15
15
16
"github.com/fatih/color"
16
17
"github.com/golangci/golangci-lint/pkg/config"
18
+ "github.com/golangci/golangci-lint/pkg/fsutils"
17
19
"github.com/golangci/golangci-lint/pkg/lint"
18
20
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
19
21
"github.com/golangci/golangci-lint/pkg/printers"
@@ -318,16 +320,80 @@ func (e *Executor) parseConfig() {
318
320
return
319
321
}
320
322
321
- if configFile == "" {
322
- viper .SetConfigName (".golangci" )
323
- viper .AddConfigPath ("./" )
324
- } else {
323
+ if configFile != "" {
325
324
viper .SetConfigFile (configFile )
325
+ } else {
326
+ setupConfigFileSearch (fs .Args ())
326
327
}
327
328
328
329
e .parseConfigImpl ()
329
330
}
330
331
332
+ func setupConfigFileSearch (args []string ) {
333
+ // skip all args ([golangci-lint, run/linters]) before files/dirs list
334
+ for len (args ) != 0 {
335
+ if args [0 ] == "run" {
336
+ args = args [1 :]
337
+ break
338
+ }
339
+
340
+ args = args [1 :]
341
+ }
342
+
343
+ // find first file/dir arg
344
+ firstArg := "./..."
345
+ if len (args ) != 0 {
346
+ firstArg = args [0 ]
347
+ }
348
+
349
+ absStartPath , err := filepath .Abs (firstArg )
350
+ if err != nil {
351
+ logrus .Infof ("Can't make abs path for %q: %s" , firstArg , err )
352
+ absStartPath = filepath .Clean (firstArg )
353
+ }
354
+
355
+ // start from it
356
+ var curDir string
357
+ if fsutils .IsDir (absStartPath ) {
358
+ curDir = absStartPath
359
+ } else {
360
+ curDir = filepath .Dir (absStartPath )
361
+ }
362
+
363
+ // find all dirs from it up to the root
364
+ configSearchPaths := []string {"./" }
365
+ for {
366
+ configSearchPaths = append (configSearchPaths , curDir )
367
+ newCurDir := filepath .Dir (curDir )
368
+ if curDir == newCurDir || newCurDir == "" {
369
+ break
370
+ }
371
+ curDir = newCurDir
372
+ }
373
+
374
+ logrus .Infof ("Config search paths: %s" , configSearchPaths )
375
+ viper .SetConfigName (".golangci" )
376
+ for _ , p := range configSearchPaths {
377
+ viper .AddConfigPath (p )
378
+ }
379
+ }
380
+
381
+ func getRelPath (p string ) string {
382
+ wd , err := os .Getwd ()
383
+ if err != nil {
384
+ logrus .Infof ("Can't get wd: %s" , err )
385
+ return p
386
+ }
387
+
388
+ r , err := filepath .Rel (wd , p )
389
+ if err != nil {
390
+ logrus .Infof ("Can't make path %s relative to %s: %s" , p , wd , err )
391
+ return p
392
+ }
393
+
394
+ return r
395
+ }
396
+
331
397
func (e * Executor ) parseConfigImpl () {
332
398
commandLineConfig := * e .cfg // make copy
333
399
@@ -338,13 +404,24 @@ func (e *Executor) parseConfigImpl() {
338
404
logrus .Fatalf ("Can't read viper config: %s" , err )
339
405
}
340
406
407
+ usedConfigFile := viper .ConfigFileUsed ()
408
+ if usedConfigFile == "" {
409
+ return
410
+ }
411
+ logrus .Infof ("Used config file %s" , getRelPath (usedConfigFile ))
412
+
341
413
if err := viper .Unmarshal (& e .cfg ); err != nil {
342
414
logrus .Fatalf ("Can't unmarshal config by viper: %s" , err )
343
415
}
344
416
345
417
if err := e .validateConfig (& commandLineConfig ); err != nil {
346
418
logrus .Fatal (err )
347
419
}
420
+
421
+ if e .cfg .InternalTest { // just for testing purposes: to detect config file usage
422
+ fmt .Fprintln (printers .StdOut , "test" )
423
+ os .Exit (0 )
424
+ }
348
425
}
349
426
350
427
func (e * Executor ) validateConfig (commandLineConfig * config.Config ) error {
0 commit comments