Skip to content

Commit

Permalink
feat: auto-exclude gitignore patterns (#109)
Browse files Browse the repository at this point in the history
  • Loading branch information
twelvelabs committed Dec 26, 2023
1 parent 22fd462 commit e815ad3
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 63 deletions.
4 changes: 0 additions & 4 deletions .stylist.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
excludes:
- dist/**
- .cspellcache
- coverage.out
output:
show_context: true
show_url: true
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ BUILD_DIR := ./dist
DST_DIR := /usr/local/bin

CURRENT_SHA = $(shell git rev-parse --short HEAD)
CURRENT_TS = $(shell date -I seconds)
CURRENT_TS = $(shell date -Iseconds)

##@ App

Expand Down
1 change: 1 addition & 0 deletions cspell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ words:
- gopls
- goreleaser
- gosec
- gostub
- hadolint
- infof
- iostreams
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ require (
github.com/alecthomas/chroma/v2 v2.12.0
github.com/bmatcuk/doublestar/v4 v4.6.1
github.com/deckarep/golang-set/v2 v2.5.0
github.com/denormal/go-gitignore v0.0.0-20180930084346-ae8ad1d07817
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/imdario/mergo v1.0.0
github.com/owenrumney/go-sarif/v2 v2.3.0
github.com/prashantv/gostub v1.1.0
github.com/sirupsen/logrus v1.9.3
github.com/sourcegraph/go-diff v0.7.0
github.com/spf13/cobra v1.8.0
Expand All @@ -28,6 +30,7 @@ require (
github.com/briandowns/spinner v1.23.0 // indirect
github.com/caarlos0/env/v8 v8.0.0 // indirect
github.com/creasty/defaults v1.7.0 // indirect
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/fatih/color v1.16.0 // indirect
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,15 @@ github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/creasty/defaults v1.7.0 h1:eNdqZvc5B509z18lD8yc212CAqJNvfT1Jq6L8WowdBA=
github.com/creasty/defaults v1.7.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set/v2 v2.5.0 h1:hn6cEZtQ0h3J8kFrHR/NrzyOoTnjgW1+FmNJzQ7y/sA=
github.com/deckarep/golang-set/v2 v2.5.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/denormal/go-gitignore v0.0.0-20180930084346-ae8ad1d07817 h1:0nsrg//Dc7xC74H/TZ5sYR8uk4UQRNjsw8zejqH5a4Q=
github.com/denormal/go-gitignore v0.0.0-20180930084346-ae8ad1d07817/go.mod h1:C/+sI4IFnEpCn6VQ3GIPEp+FrQnQw+YQP3+n+GdGq7o=
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
Expand Down Expand Up @@ -97,6 +101,7 @@ github.com/owenrumney/go-sarif/v2 v2.3.0/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDN
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
Expand Down
2 changes: 1 addition & 1 deletion internal/stylist/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type Config struct {
LogLevel LogLevel `yaml:"log_level,omitempty" default:"warn"`
Output OutputConfig `yaml:"output,omitempty"`

Excludes []string `yaml:"excludes,omitempty" default:"[\".git\", \"node_modules\"]"`
Excludes []string `yaml:"excludes,omitempty"`
Processors []*Processor `yaml:"processors,omitempty"`
}

Expand Down
68 changes: 68 additions & 0 deletions internal/stylist/path_ignorer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package stylist

import (
"fmt"
"path/filepath"
"strings"

"github.com/bmatcuk/doublestar/v4"
"github.com/denormal/go-gitignore"

"github.com/twelvelabs/stylist/internal/fsutils"
)

var (
newGitIgnoreParser = gitignore.NewFromFile
)

// NewPathIgnorer returns a new path ignorer.
func NewPathIgnorer(gitIgnorePath string, patterns []string) (*PathIgnorer, error) {
cleanPatterns := []string{}
for _, pattern := range patterns {
p := strings.ReplaceAll(pattern, "\\", "/")
if !doublestar.ValidatePattern(p) {
return nil, doublestar.ErrBadPattern
}
cleanPatterns = append(cleanPatterns, p)
}

pi := &PathIgnorer{
patterns: cleanPatterns,
}
if gitIgnorePath != "" && fsutils.PathExists(gitIgnorePath) {
gitIgnore, err := newGitIgnoreParser(gitIgnorePath)
if err != nil {
return nil, fmt.Errorf("gitignore parse: %w", err)
}
pi.gitIgnore = gitIgnore
pi.gitIgnorePath = gitIgnorePath
}
return pi, nil
}

// PathIgnorer is responsible for ignoring paths during the index process.
type PathIgnorer struct {
gitIgnore gitignore.GitIgnore
gitIgnorePath string
patterns []string
}

// ShouldIgnore returns true if path should be ignored.
func (pi *PathIgnorer) ShouldIgnore(path string, isDir bool) bool {
if pi.gitIgnore != nil {
// Note: Specifically using `.Relative` for speed.
// The higher level GitIgnore methods (Ignore, Match)
// stat the path to figure out isDir.
if match := pi.gitIgnore.Relative(path, isDir); match != nil {
if match.Ignore() {
return true
}
}
}
for _, pattern := range pi.patterns {
if ok, _ := doublestar.Match(pattern, filepath.ToSlash(path)); ok {
return true
}
}
return false
}
98 changes: 98 additions & 0 deletions internal/stylist/path_ignorer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package stylist

import (
"errors"
"testing"

"github.com/prashantv/gostub"
"github.com/stretchr/testify/require"
)

func TestNewPathIgnorer(t *testing.T) {
require := require.New(t)

ignorer, err := NewPathIgnorer("", nil)
require.NoError(err)
require.Empty(ignorer.gitIgnore)
require.Empty(ignorer.gitIgnorePath)
require.Empty(ignorer.patterns)

ignorer, err = NewPathIgnorer("testdata/.gitignore", []string{
`\Documents\**\*.bat`,
})
require.NoError(err)
require.NotNil(ignorer.gitIgnore)
require.Equal("testdata/.gitignore", ignorer.gitIgnorePath)
require.Equal([]string{
"/Documents/**/*.bat",
}, ignorer.patterns)
}

func TestNewPathIgnorer_WhenGitIgnoreParseError(t *testing.T) {
stubs := gostub.StubFunc(&newGitIgnoreParser, nil, errors.New("boom"))
defer stubs.Reset()

require := require.New(t)

ignorer, err := NewPathIgnorer("testdata/.gitignore", nil)
require.ErrorContains(err, "boom")
require.Nil(ignorer)
}

func TestNewPathIgnorer_WhenPatternValidateError(t *testing.T) {
require := require.New(t)

ignorer, err := NewPathIgnorer("", []string{
`*{{*}`,
})
require.ErrorContains(err, "error in pattern")
require.Nil(ignorer)
}

func TestPathIgnorer_ShouldIgnore(t *testing.T) {
tests := []struct {
path string
dir bool
expected bool
}{
{
path: "example.json",
expected: false,
},
{
path: "example.yaml",
expected: true,
},
{
path: "ignored_file.txt",
expected: true,
},
{
path: "ignored_dir",
dir: true,
expected: true,
},
{
path: "ignored_dir",
dir: false,
expected: false,
},
{
path: "ignored_dir/allowed.txt",
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.path, func(t *testing.T) {
require := require.New(t)

ignorer, err := NewPathIgnorer("testdata/.gitignore", []string{
"**/*.{yaml,yml}",
})
require.NoError(err)

actual := ignorer.ShouldIgnore(tt.path, tt.dir)
require.Equal(tt.expected, actual)
})
}
}
Loading

0 comments on commit e815ad3

Please sign in to comment.