Skip to content

Commit

Permalink
feat: Add --exclude and --exclude-dir (#372)
Browse files Browse the repository at this point in the history
Fixes #63

---------

Signed-off-by: Ian Lewis <ianlewis@google.com>
  • Loading branch information
Ian Lewis authored Aug 25, 2023
1 parent 97e3608 commit 0d16b5b
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 2 deletions.
2 changes: 2 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ linters-settings:

# Dependencies.
- "github.com/fatih/color"
- "github.com/gobwas/glob"
- "github.com/google/go-github"
- "github.com/ianlewis/linguist"
- "github.com/saintfish/chardet"
Expand All @@ -118,6 +119,7 @@ linters-settings:
- "github.com/ianlewis/todos"

# Dependencies.
- "github.com/gobwas/glob"
- "github.com/google/go-cmp/cmp"
- "github.com/google/go-github"
- "github.com/urfave/cli/v2"
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Support for Erlang, Haskell, R, and SQL programming languages has been added.
- A new `exclude-dir` flag was added to `todos` that allows for excluding
matching directories from the search.

## [0.4.0] - 2023-08-23

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.20

require (
github.com/fatih/color v1.15.0
github.com/gobwas/glob v0.2.3
github.com/google/go-cmp v0.5.9
github.com/google/go-github/v52 v52.0.0
github.com/ianlewis/linguist v0.0.0-20220509081505-4e84ef081328
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
Expand Down
29 changes: 27 additions & 2 deletions internal/cmd/todos/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"strings"

"github.com/fatih/color"
"github.com/gobwas/glob"
"github.com/urfave/cli/v2"
"sigs.k8s.io/release-utils/version"

Expand Down Expand Up @@ -65,6 +66,14 @@ func newTODOsApp() *cli.App {
Usage: "Exclude hidden files and directories",
DisableDefaultText: true,
},
&cli.StringSliceFlag{
Name: "exclude",
Usage: "Exclude files that match `GLOB`",
},
&cli.StringSliceFlag{
Name: "exclude-dir",
Usage: "Exclude directories that match `GLOB`",
},
&cli.BoolFlag{
Name: "include-vcs",
Usage: "Include version control directories (.git, .hg, .svn)",
Expand All @@ -77,12 +86,12 @@ func newTODOsApp() *cli.App {
},
&cli.StringFlag{
Name: "todo-types",
Usage: "Comma separated list of TODO types",
Usage: "Comma separated list of TODO `TYPES`",
Value: strings.Join(todos.DefaultTypes, ","),
},
&cli.StringFlag{
Name: "output",
Usage: "Output type (default, github, json)",
Usage: "Output `TYPE` (default, github, json)",
Value: "default",
Aliases: []string{"o"},
},
Expand Down Expand Up @@ -231,6 +240,22 @@ var outTypes = map[string]func(io.Writer) walker.TODOHandler{
func walkerOptionsFromContext(c *cli.Context) (*walker.Options, error) {
o := walker.Options{}

for _, gs := range c.StringSlice("exclude") {
g, err := glob.Compile(gs)
if err != nil {
return nil, fmt.Errorf("%w: exclude: %w", ErrFlagParse, err)
}
o.ExcludeGlobs = append(o.ExcludeGlobs, g)
}

for _, gs := range c.StringSlice("exclude-dir") {
g, err := glob.Compile(gs)
if err != nil {
return nil, fmt.Errorf("%w: exclude-dir: %w", ErrFlagParse, err)
}
o.ExcludeDirGlobs = append(o.ExcludeDirGlobs, g)
}

o.IncludeHidden = !c.Bool("exclude-hidden")
o.IncludeVCS = c.Bool("include-vcs")
o.IncludeVendored = c.Bool("include-vendored")
Expand Down
29 changes: 29 additions & 0 deletions internal/cmd/todos/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"strings"
"testing"

"github.com/gobwas/glob"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/urfave/cli/v2"
Expand Down Expand Up @@ -445,6 +446,34 @@ func Test_walkerOptionsFromContext(t *testing.T) {
Paths: []string{"/path/to/code", "/other/path"},
},
},
"exclude-multiple": {
args: []string{"--exclude=exclude.*", "--exclude=foo"},
flags: []cli.Flag{
&cli.StringSliceFlag{
Name: "exclude",
},
},
expected: &walker.Options{
Config: &todos.Config{},
IncludeHidden: true,
ExcludeGlobs: []glob.Glob{glob.MustCompile("exclude.*"), glob.MustCompile("foo")},
Paths: []string{"."},
},
},
"exclude-dir-multiple": {
args: []string{"--exclude-dir=exclude?", "--exclude-dir=foo"},
flags: []cli.Flag{
&cli.StringSliceFlag{
Name: "exclude-dir",
},
},
expected: &walker.Options{
Config: &todos.Config{},
IncludeHidden: true,
ExcludeDirGlobs: []glob.Glob{glob.MustCompile("exclude?"), glob.MustCompile("foo")},
Paths: []string{"."},
},
},
}

for name, tc := range testCases {
Expand Down
22 changes: 22 additions & 0 deletions internal/walker/walker.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"path/filepath"
"strings"

"github.com/gobwas/glob"
"github.com/ianlewis/linguist"

"github.com/ianlewis/todos/internal/scanner"
Expand Down Expand Up @@ -51,6 +52,12 @@ type Options struct {
// Config is the config for scanning todos.
Config *todos.Config

// ExcludeGlobs is a list of Glob that matches excluded files.
ExcludeGlobs []glob.Glob

// ExcludeDirGlobs is a list of Glob that matches excluded dirs.
ExcludeDirGlobs []glob.Glob

// IncludeHidden indicates whether hidden paths should be processed. Hidden
// paths are always processed if there are specified explicitly in `paths`.
IncludeHidden bool
Expand Down Expand Up @@ -192,6 +199,13 @@ func (w *TODOWalker) processDir(path, fullPath string) error {
return nil
}

// Exclude directories that match one of the given glob patterns.
for _, g := range w.options.ExcludeDirGlobs {
if g.Match(filepath.Base(fullPath)) {
return fs.SkipDir
}
}

hdn, err := isHidden(fullPath)
if err != nil {
if herr := w.handleErr(path, err); herr != nil {
Expand Down Expand Up @@ -224,6 +238,14 @@ func (w *TODOWalker) processDir(path, fullPath string) error {
}

func (w *TODOWalker) processFile(path, fullPath string, f *os.File) error {
// Exclude files that match one of the given glob patterns.
for _, g := range w.options.ExcludeGlobs {
if g.Match(filepath.Base(fullPath)) {
// Skip file.
return nil
}
}

hdn, err := isHidden(fullPath)
if err != nil {
return w.handleErr(path, err)
Expand Down
95 changes: 95 additions & 0 deletions internal/walker/walker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"path/filepath"
"testing"

"github.com/gobwas/glob"
"github.com/google/go-cmp/cmp"

"github.com/ianlewis/todos/internal/testutils"
Expand Down Expand Up @@ -661,6 +662,100 @@ var testCases = []struct {
},
},
},
{
name: "exclude file",
files: []*testutils.File{
{
Path: "line_comments.go",
Contents: []byte(`package foo
// package comment
// TODO is a function.
// TODO: some task.
func TODO() {
return // Random comment
}`),
Mode: 0o600,
},
{
Path: "excluded.go",
Contents: []byte(`package foo
// package comment
// TODO is a function.
// TODO: some task.
func TODO() {
return // Random comment
}`),
Mode: 0o600,
},
},
opts: &Options{
Config: &todos.Config{
Types: []string{"TODO"},
},
ExcludeGlobs: []glob.Glob{glob.MustCompile("excluded.*")},
},
expected: []*TODORef{
{
FileName: "line_comments.go",
TODO: &todos.TODO{
Type: "TODO",
Text: "// TODO: some task.",
Message: "some task.",
Line: 5,
CommentLine: 5,
},
},
},
},
{
name: "exclude dir",
files: []*testutils.File{
{
Path: filepath.Join("src", "line_comments.go"),
Contents: []byte(`package foo
// package comment
// TODO is a function.
// TODO: some task.
func TODO() {
return // Random comment
}`),
Mode: 0o600,
},
{
Path: filepath.Join("excluded", "more_line_comments.go"),
Contents: []byte(`package foo
// package comment
// TODO is a function.
// TODO: some task.
func TODO() {
return // Random comment
}`),
Mode: 0o600,
},
},
opts: &Options{
Config: &todos.Config{
Types: []string{"TODO"},
},
ExcludeDirGlobs: []glob.Glob{glob.MustCompile("exclude?")},
},
expected: []*TODORef{
{
FileName: filepath.Join("src", "line_comments.go"),
TODO: &todos.TODO{
Type: "TODO",
Text: "// TODO: some task.",
Message: "some task.",
Line: 5,
CommentLine: 5,
},
},
},
},
}

type fixture struct {
Expand Down

0 comments on commit 0d16b5b

Please sign in to comment.