Skip to content

Commit

Permalink
#30: support --skip-files and --skip-dirs options: they skip files an…
Browse files Browse the repository at this point in the history
…d dirs by regexps
  • Loading branch information
jirfag committed Jun 7, 2018
1 parent 110f584 commit d006560
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 17 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ Flags:
--print-resources-usage Print avg and max memory usage of golangci-lint and total time
-c, --config PATH Read config from file path PATH
--no-config Don't read config
--skip-dirs strings Regexps of directory names to skip
--skip-files strings Regexps of file names to skip
-E, --enable strings Enable specific linter
-D, --disable strings Disable specific linter
--enable-all Enable all linters
Expand Down
13 changes: 12 additions & 1 deletion pkg/commands/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config) {
fs.BoolVar(&rc.PrintResourcesUsage, "print-resources-usage", false, wh("Print avg and max memory usage of golangci-lint and total time"))
fs.StringVarP(&rc.Config, "config", "c", "", wh("Read config from file path `PATH`"))
fs.BoolVar(&rc.NoConfig, "no-config", false, wh("Don't read config"))
fs.StringSliceVar(&rc.SkipDirs, "skip-dirs", nil, wh("Regexps of directory names to skip"))
fs.StringSliceVar(&rc.SkipFiles, "skip-files", nil, wh("Regexps of file names to skip"))

// Linters settings config
lsc := &cfg.LintersSettings
Expand Down Expand Up @@ -194,12 +196,21 @@ func (e *Executor) runAnalysis(ctx context.Context, args []string) (<-chan resul
if lintCtx.Program != nil {
fset = lintCtx.Program.Fset
}

skipFilesProcessor, err := processors.NewSkipFiles(e.cfg.Run.SkipFiles)
if err != nil {
return nil, err
}

runner := lint.SimpleRunner{
Processors: []processors.Processor{
processors.NewPathPrettifier(), // must be before diff processor at least
processors.NewExclude(excludeTotalPattern),
processors.NewCgo(),
skipFilesProcessor,

processors.NewExclude(excludeTotalPattern),
processors.NewNolint(fset),

processors.NewUniqByLine(),
processors.NewDiff(e.cfg.Issues.Diff, e.cfg.Issues.DiffFromRevision, e.cfg.Issues.DiffPatchFilePath),
processors.NewMaxPerFileFromLinter(),
Expand Down
3 changes: 3 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ type Run struct {
AnalyzeTests bool `mapstructure:"tests"`
Deadline time.Duration
PrintVersion bool

SkipFiles []string `mapstructure:"skip-files"`
SkipDirs []string `mapstructure:"skip-dirs"`
}

type LintersSettings struct {
Expand Down
17 changes: 14 additions & 3 deletions pkg/fsutils/fsutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ import (
"github.com/sirupsen/logrus"
)

var stdExcludeDirs = []string{"vendor", "testdata", "examples", "Godeps", "builtin"}
var stdExcludeDirRegexps = []string{
"^vendor$", "^third_party$",
"^testdata$", "^examples$",
"^Godeps$",
"^builtin$",
}

func GetProjectRoot() string {
return path.Join(build.Default.GOPATH, "src", "github.com", "golangci", "golangci-worker")
Expand Down Expand Up @@ -101,7 +106,7 @@ func processResolvedPaths(paths *PathResolveResult) (*ProjectPaths, error) {
}, nil
}

func GetPathsForAnalysis(ctx context.Context, inputPaths []string, includeTests bool) (ret *ProjectPaths, err error) {
func GetPathsForAnalysis(ctx context.Context, inputPaths []string, includeTests bool, skipDirRegexps []string) (ret *ProjectPaths, err error) {
defer func(startedAt time.Time) {
if ret != nil {
logrus.Infof("Found paths for analysis for %s: %s", time.Since(startedAt), ret.MixedPaths())
Expand All @@ -114,7 +119,13 @@ func GetPathsForAnalysis(ctx context.Context, inputPaths []string, includeTests
}
}

pr := NewPathResolver(stdExcludeDirs, []string{".go"}, includeTests)
// TODO: don't analyze skipped files also, when be able to do it
excludeDirs := append([]string{}, stdExcludeDirRegexps...)
excludeDirs = append(excludeDirs, skipDirRegexps...)
pr, err := NewPathResolver(excludeDirs, []string{".go"}, includeTests)
if err != nil {
return nil, fmt.Errorf("can't make path resolver: %s", err)
}
paths, err := pr.Resolve(inputPaths...)
if err != nil {
return nil, fmt.Errorf("can't resolve paths %v: %s", inputPaths, err)
Expand Down
24 changes: 18 additions & 6 deletions pkg/fsutils/path_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import (
"fmt"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
)

type PathResolver struct {
excludeDirs map[string]bool
excludeDirs map[string]*regexp.Regexp
allowedFileExtensions map[string]bool
includeTests bool
}
Expand Down Expand Up @@ -57,10 +58,15 @@ func (s pathResolveState) toResult() *PathResolveResult {
return res
}

func NewPathResolver(excludeDirs, allowedFileExtensions []string, includeTests bool) *PathResolver {
excludeDirsMap := map[string]bool{}
func NewPathResolver(excludeDirs, allowedFileExtensions []string, includeTests bool) (*PathResolver, error) {
excludeDirsMap := map[string]*regexp.Regexp{}
for _, dir := range excludeDirs {
excludeDirsMap[dir] = true
re, err := regexp.Compile(dir)
if err != nil {
return nil, fmt.Errorf("can't compile regexp %q: %s", dir, err)
}

excludeDirsMap[dir] = re
}

allowedFileExtensionsMap := map[string]bool{}
Expand All @@ -72,7 +78,7 @@ func NewPathResolver(excludeDirs, allowedFileExtensions []string, includeTests b
excludeDirs: excludeDirsMap,
allowedFileExtensions: allowedFileExtensionsMap,
includeTests: includeTests,
}
}, nil
}

func (pr PathResolver) isIgnoredDir(dir string) bool {
Expand All @@ -87,7 +93,13 @@ func (pr PathResolver) isIgnoredDir(dir string) bool {
return true
}

return pr.excludeDirs[dirName]
for _, dirExludeRe := range pr.excludeDirs {
if dirExludeRe.MatchString(dirName) {
return true
}
}

return false
}

func (pr PathResolver) isAllowedFile(path string) bool {
Expand Down
20 changes: 15 additions & 5 deletions pkg/fsutils/path_resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,23 @@ func prepareFS(t *testing.T, paths ...string) *fsPreparer {
}
}

func newPR() *PathResolver {
return NewPathResolver([]string{}, []string{}, false)
func newPR(t *testing.T) *PathResolver {
pr, err := NewPathResolver([]string{}, []string{}, false)
assert.NoError(t, err)

return pr
}

func TestPathResolverNoPaths(t *testing.T) {
_, err := newPR().Resolve()
_, err := newPR(t).Resolve()
assert.EqualError(t, err, "no paths are set")
}

func TestPathResolverNotExistingPath(t *testing.T) {
fp := prepareFS(t)
defer fp.clean()

_, err := newPR().Resolve("a")
_, err := newPR(t).Resolve("a")
assert.EqualError(t, err, "can't find path a: stat a: no such file or directory")
}

Expand Down Expand Up @@ -187,14 +190,21 @@ func TestPathResolverCommonCases(t *testing.T) {
expDirs: []string{".", "a/c"},
expFiles: []string{"a/c/d.go", "e.go"},
},
{
name: "vendor dir is excluded by regexp, not the exact match",
prepare: []string{"vendors/a.go", "novendor/b.go"},
resolve: []string{"./..."},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
fp := prepareFS(t, tc.prepare...)
defer fp.clean()

pr := NewPathResolver([]string{"vendor"}, []string{".go"}, tc.includeTests)
pr, err := NewPathResolver([]string{"vendor"}, []string{".go"}, tc.includeTests)
assert.NoError(t, err)

res, err := pr.Resolve(tc.resolve...)
assert.NoError(t, err)

Expand Down
2 changes: 1 addition & 1 deletion pkg/lint/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func LoadContext(ctx context.Context, linters []linter.Config, cfg *config.Confi
args = []string{"./..."}
}

paths, err := fsutils.GetPathsForAnalysis(ctx, args, cfg.Run.AnalyzeTests)
paths, err := fsutils.GetPathsForAnalysis(ctx, args, cfg.Run.AnalyzeTests, cfg.Run.SkipDirs)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/lint/load_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestASTCacheLoading(t *testing.T) {

inputPaths := []string{"./...", "./", "./load.go", "load.go"}
for _, inputPath := range inputPaths {
paths, err := fsutils.GetPathsForAnalysis(ctx, []string{inputPath}, true)
paths, err := fsutils.GetPathsForAnalysis(ctx, []string{inputPath}, true, nil)
assert.NoError(t, err)
assert.NotEmpty(t, paths.Files)

Expand Down
53 changes: 53 additions & 0 deletions pkg/result/processors/skip_files.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package processors

import (
"fmt"
"path/filepath"
"regexp"

"github.com/golangci/golangci-lint/pkg/result"
)

type SkipFiles struct {
patterns []*regexp.Regexp
}

var _ Processor = SkipFiles{}

func NewSkipFiles(patterns []string) (*SkipFiles, error) {
var patternsRe []*regexp.Regexp
for _, p := range patterns {
patternRe, err := regexp.Compile(p)
if err != nil {
return nil, fmt.Errorf("can't compile regexp %q: %s", p, err)
}
patternsRe = append(patternsRe, patternRe)
}

return &SkipFiles{
patterns: patternsRe,
}, nil
}

func (p SkipFiles) Name() string {
return "skip_files"
}

func (p SkipFiles) Process(issues []result.Issue) ([]result.Issue, error) {
if len(p.patterns) == 0 {
return issues, nil
}

return filterIssues(issues, func(i *result.Issue) bool {
fileName := filepath.Base(i.FilePath())
for _, p := range p.patterns {
if p.MatchString(fileName) {
return false
}
}

return true
}), nil
}

func (p SkipFiles) Finish() {}
43 changes: 43 additions & 0 deletions pkg/result/processors/skip_files_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package processors

import (
"go/token"
"testing"

"github.com/golangci/golangci-lint/pkg/result"
"github.com/stretchr/testify/assert"
)

func newFileIssue(file string) result.Issue {
return result.Issue{
Pos: token.Position{
Filename: file,
},
}
}

func newTestSkipFiles(t *testing.T, patterns ...string) *SkipFiles {
p, err := NewSkipFiles(patterns)
assert.NoError(t, err)
return p
}

func TestSkipFiles(t *testing.T) {
p := newTestSkipFiles(t)
processAssertSame(t, p, newFileIssue("any.go"))

p = newTestSkipFiles(t, "file")
processAssertEmpty(t, p,
newFileIssue("file.go"),
newFileIssue("file"),
newFileIssue("nofile.go"))

p = newTestSkipFiles(t, ".*")
processAssertEmpty(t, p, newFileIssue("any.go"))
}

func TestSkipFilesInvalidPattern(t *testing.T) {
p, err := NewSkipFiles([]string{"\\o"})
assert.Error(t, err)
assert.Nil(t, p)
}

0 comments on commit d006560

Please sign in to comment.