Skip to content

Commit 0b62d43

Browse files
committed
#60: search config file in directories from file path up to root
1 parent b082671 commit 0b62d43

File tree

5 files changed

+109
-9
lines changed

5 files changed

+109
-9
lines changed

pkg/commands/run.go

+81-4
Original file line numberDiff line numberDiff line change
@@ -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+
331397
func (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

350427
func (e *Executor) validateConfig(commandLineConfig *config.Config) error {

pkg/config/config.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ type Issues struct {
164164
Diff bool `mapstructure:"new"`
165165
}
166166

167-
type Config struct { // nolint:maligned
167+
type Config struct { //nolint:maligned
168168
Run Run
169169

170170
Output struct {
@@ -177,4 +177,6 @@ type Config struct { // nolint:maligned
177177
LintersSettings LintersSettings `mapstructure:"linters-settings"`
178178
Linters Linters
179179
Issues Issues
180+
181+
InternalTest bool // Option is used only for testing golangci-lint code, don't use it
180182
}

test/run_test.go

+21-4
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,18 @@ func installBinary(t assert.TestingT) {
1919
})
2020
}
2121

22-
func TestCongratsMessageIfNoIssues(t *testing.T) {
23-
out, exitCode := runGolangciLint(t, "../...")
22+
func checkNoIssuesRun(t *testing.T, out string, exitCode int) {
2423
assert.Equal(t, 0, exitCode)
2524
assert.Equal(t, "Congrats! No issues were found.\n", out)
2625
}
2726

27+
func TestCongratsMessageIfNoIssues(t *testing.T) {
28+
out, exitCode := runGolangciLint(t, "../...")
29+
checkNoIssuesRun(t, out, exitCode)
30+
}
31+
2832
func TestDeadline(t *testing.T) {
29-
out, exitCode := runGolangciLint(t, "--no-config", "--deadline=1ms", "../...")
33+
out, exitCode := runGolangciLint(t, "--deadline=1ms", "../...")
3034
assert.Equal(t, 4, exitCode)
3135
assert.Equal(t, "", out) // no 'Congrats! No issues were found.'
3236
}
@@ -54,6 +58,19 @@ func runGolangciLint(t *testing.T, args ...string) (string, int) {
5458
}
5559

5660
func TestTestsAreLintedByDefault(t *testing.T) {
57-
out, exitCode := runGolangciLint(t, "--no-config", "./testdata/withtests")
61+
out, exitCode := runGolangciLint(t, "./testdata/withtests")
5862
assert.Equal(t, 0, exitCode, out)
5963
}
64+
65+
func TestConfigFileIsDetected(t *testing.T) {
66+
checkGotConfig := func(out string, exitCode int) {
67+
assert.Equal(t, 0, exitCode, out)
68+
assert.Equal(t, "test\n", out) // test config contains InternalTest: true, it triggers such output
69+
}
70+
71+
checkGotConfig(runGolangciLint(t, "testdata/withconfig/pkg"))
72+
checkGotConfig(runGolangciLint(t, "testdata/withconfig/..."))
73+
74+
out, exitCode := runGolangciLint(t) // doesn't detect when no args
75+
checkNoIssuesRun(t, out, exitCode)
76+
}
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
InternalTest: true

test/testdata/withconfig/pkg/pkg.go

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package pkg
2+
3+
func SomeTestFunc() {}

0 commit comments

Comments
 (0)