@@ -8,12 +8,14 @@ import (
88	"io/ioutil" 
99	"log" 
1010	"os" 
11+ 	"path/filepath" 
1112	"runtime" 
1213	"strings" 
1314	"time" 
1415
1516	"github.com/fatih/color" 
1617	"github.com/golangci/golangci-lint/pkg/config" 
18+ 	"github.com/golangci/golangci-lint/pkg/fsutils" 
1719	"github.com/golangci/golangci-lint/pkg/lint" 
1820	"github.com/golangci/golangci-lint/pkg/lint/lintersdb" 
1921	"github.com/golangci/golangci-lint/pkg/printers" 
@@ -318,16 +320,80 @@ func (e *Executor) parseConfig() {
318320		return 
319321	}
320322
321- 	if  configFile  ==  ""  {
322- 		viper .SetConfigName (".golangci" )
323- 		viper .AddConfigPath ("./" )
324- 	} else  {
323+ 	if  configFile  !=  ""  {
325324		viper .SetConfigFile (configFile )
325+ 	} else  {
326+ 		setupConfigFileSearch (fs .Args ())
326327	}
327328
328329	e .parseConfigImpl ()
329330}
330331
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+ 
331397func  (e  * Executor ) parseConfigImpl () {
332398	commandLineConfig  :=  * e .cfg  // make copy 
333399
@@ -338,13 +404,24 @@ func (e *Executor) parseConfigImpl() {
338404		logrus .Fatalf ("Can't read viper config: %s" , err )
339405	}
340406
407+ 	usedConfigFile  :=  viper .ConfigFileUsed ()
408+ 	if  usedConfigFile  ==  ""  {
409+ 		return 
410+ 	}
411+ 	logrus .Infof ("Used config file %s" , getRelPath (usedConfigFile ))
412+ 
341413	if  err  :=  viper .Unmarshal (& e .cfg ); err  !=  nil  {
342414		logrus .Fatalf ("Can't unmarshal config by viper: %s" , err )
343415	}
344416
345417	if  err  :=  e .validateConfig (& commandLineConfig ); err  !=  nil  {
346418		logrus .Fatal (err )
347419	}
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+ 	}
348425}
349426
350427func  (e  * Executor ) validateConfig (commandLineConfig  * config.Config ) error  {
0 commit comments