Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: --label GLOB filter #1571

Merged
merged 5 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- A new `--label` flag was added to support filtering TODOs by label
([#1562](https://github.com/ianlewis/todos/issues/1562)).
- Support was added for
[MATLAB](https://www.mathworks.com/products/matlab.html)
- Support was added for
Expand All @@ -33,7 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Fixed a bug where TODOs were not being reported if they were located after a
multi-line comment with no TODOs in the same file
([#1520](https://github.com/ianlewis/todos/issues/1520))
([#1520](https://github.com/ianlewis/todos/issues/1520)).

## [0.8.0] - 2024-02-21

Expand Down
43 changes: 31 additions & 12 deletions internal/cmd/todos/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,11 @@
Name: filepath.Base(os.Args[0]),
Usage: "Search for TODOS in code.",
Flags: []cli.Flag{
// Flags for functionality are in alphabetical order.
&cli.BoolFlag{
Name: "exclude-hidden",
Usage: "exclude hidden files and directories",
Name: "blame",
Usage: "[BETA] attempt to find committer info",
Value: false,
DisableDefaultText: true,
},
&cli.StringFlag{
Expand All @@ -105,6 +107,11 @@
Name: "exclude-dir",
Usage: "exclude directories that match `GLOB`",
},
&cli.BoolFlag{
Name: "exclude-hidden",
Usage: "exclude hidden files and directories",
DisableDefaultText: true,
},
&cli.BoolFlag{
Name: "include-vcs",
Usage: "include version control directories (.git, .hg, .svn)",
Expand All @@ -122,23 +129,24 @@
Value: false,
DisableDefaultText: true,
},
&cli.BoolFlag{
Name: "blame",
Usage: "[BETA] attempt to find committer info",
Value: false,
DisableDefaultText: true,
},
&cli.StringFlag{
Name: "todo-types",
Usage: "comma separated list of TODO `TYPES`",
Value: strings.Join(todos.DefaultTypes, ","),
&cli.StringSliceFlag{
Name: "label",
Usage: "only output TODOs that match `GLOB`",
Aliases: []string{"l"},
},
&cli.StringFlag{
Name: "output",
Usage: "output `TYPE` (default, github, json)",
Value: defaultOutput,
Aliases: []string{"o"},
},
&cli.StringFlag{
Name: "todo-types",
Usage: "comma separated list of TODO `TYPES`",
Value: strings.Join(todos.DefaultTypes, ","),
},

// Special flags are shown at the end.
&cli.BoolFlag{
Name: "help",
Usage: "print this help text and exit",
Expand Down Expand Up @@ -358,11 +366,22 @@
}

o.Blame = c.Bool("blame")

// File Includes
o.IncludeGenerated = c.Bool("include-generated")
o.IncludeHidden = !c.Bool("exclude-hidden")
o.IncludeVCS = c.Bool("include-vcs")
o.IncludeVendored = c.Bool("include-vendored")

// Filters
for _, label := range c.StringSlice("label") {
g, err := glob.Compile(label)
if err != nil {
return nil, fmt.Errorf("%w: label: %w", ErrFlagParse, err)
}

Check warning on line 381 in internal/cmd/todos/app.go

View check run for this annotation

Codecov / codecov/patch

internal/cmd/todos/app.go#L380-L381

Added lines #L380 - L381 were not covered by tests
o.LabelGlobs = append(o.LabelGlobs, g)
}

outType := c.String("output")
outFunc, ok := outTypes[outType]
if !ok {
Expand Down
12 changes: 12 additions & 0 deletions internal/cmd/todos/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,18 @@ func Test_walkerOptionsFromContext(t *testing.T) {
args: []string{"--charset=invalid"},
err: ErrFlagParse,
},
"label": {
args: []string{"--label=foo", "--label=bar-*"},
expected: &walker.Options{
Config: &todos.Config{
Types: todos.DefaultTypes,
},
LabelGlobs: []glob.Glob{glob.MustCompile("foo"), glob.MustCompile("bar-*")},
Charset: defaultCharset,
IncludeHidden: true,
Paths: []string{"."},
},
},
}

for name, tc := range testCases {
Expand Down
24 changes: 21 additions & 3 deletions internal/walker/walker.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ type Options struct {
// ErrorFunc handles when errors are found.
ErrorFunc ErrorHandler

// Blame indicates that the walker should attempt to find the git committer
// that committed each TODO.
Blame bool

// Config is the config for scanning todos.
Config *todos.Config

Expand Down Expand Up @@ -93,9 +97,8 @@ type Options struct {
// IncludeVCS indicates that VCS paths (.git, .hg, .svn, etc.) should be included.
IncludeVCS bool

// Blame indicates that the walker should attempt to find the git committer
// that committed each TODO.
Blame bool
// LabelGlobs is a list of Glob to filter TODOs by label.
LabelGlobs []glob.Glob

// Paths are the paths to walk to look for TODOs.
Paths []string
Expand Down Expand Up @@ -315,6 +318,21 @@ func (w *TODOWalker) scanFile(f *os.File, force bool) error {
t := todos.NewTODOScanner(s, w.options.Config)
for t.Scan() {
todo := t.Next()

// Check the label globs to see if any match.
if len(w.options.LabelGlobs) > 0 {
labelMatch := false
for _, g := range w.options.LabelGlobs {
if g.Match(todo.Label) {
labelMatch = true
break
}
}
if !labelMatch {
continue
}
}

if w.options.TODOFunc != nil {
var gitUser *GitUser
repo, br, gitUser, err = w.gitUser(f.Name(), repo, br, todo.Line)
Expand Down
54 changes: 54 additions & 0 deletions internal/walker/walker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,60 @@ var testCases = []testCase{
},
},
},
{
name: "label glob filter",
files: []*testutils.File{
{
Path: "line_comments.go",
Contents: []byte(`package foo
// package comment

// TODO: no label
// TODO(no-match): no match

// TODO is a function.
// TODO(todo-label): some task.
func TODO() {
return // TODO(other-label): Return comment
}`),
Mode: 0o600,
},
},
opts: &Options{
Config: &todos.Config{
Types: []string{"TODO"},
},
LabelGlobs: []glob.Glob{
glob.MustCompile("todo-*"),
glob.MustCompile("other-*"),
},
Charset: "UTF-8",
},
expected: []*TODORef{
{
FileName: "line_comments.go",
TODO: &todos.TODO{
Type: "TODO",
Text: "// TODO(todo-label): some task.",
Message: "some task.",
Label: "todo-label",
Line: 8,
CommentLine: 8,
},
},
{
FileName: "line_comments.go",
TODO: &todos.TODO{
Type: "TODO",
Text: "// TODO(other-label): Return comment",
Message: "Return comment",
Label: "other-label",
Line: 10,
CommentLine: 10,
},
},
},
},
}

type blameTestCase struct {
Expand Down
Loading