diff options
-rw-r--r-- | bug/snapshot.go | 8 | ||||
-rw-r--r-- | cache/bug_excerpt.go | 8 | ||||
-rw-r--r-- | cache/filter.go | 15 | ||||
-rw-r--r-- | cache/filter_test.go | 34 | ||||
-rw-r--r-- | cache/query.go | 4 | ||||
-rw-r--r-- | cache/query_test.go | 3 | ||||
-rw-r--r-- | commands/ls.go | 31 | ||||
-rw-r--r-- | doc/man/git-bug-ls.1 | 4 | ||||
-rw-r--r-- | doc/md/git-bug_ls.md | 1 | ||||
-rw-r--r-- | doc/queries.md | 10 | ||||
-rw-r--r-- | input/input.go | 1 | ||||
-rw-r--r-- | misc/bash_completion/git-bug | 3 |
12 files changed, 96 insertions, 26 deletions
diff --git a/bug/snapshot.go b/bug/snapshot.go index 46618ebd..83b94416 100644 --- a/bug/snapshot.go +++ b/bug/snapshot.go @@ -34,14 +34,6 @@ func (snap *Snapshot) HumanId() string { return FormatHumanID(snap.id) } -// Deprecated:should be moved in UI code -func (snap *Snapshot) Summary() string { - return fmt.Sprintf("C:%d L:%d", - len(snap.Comments)-1, - len(snap.Labels), - ) -} - // Return the last time a bug was modified func (snap *Snapshot) LastEditTime() time.Time { if len(snap.Operations) == 0 { diff --git a/cache/bug_excerpt.go b/cache/bug_excerpt.go index fd06e51b..a50d8c66 100644 --- a/cache/bug_excerpt.go +++ b/cache/bug_excerpt.go @@ -23,8 +23,10 @@ type BugExcerpt struct { CreateUnixTime int64 EditUnixTime int64 - Status bug.Status - Labels []bug.Label + Status bug.Status + Labels []bug.Label + Title string + LenComments int // If author is identity.Bare, LegacyAuthor is set // If author is identity.Identity, AuthorId is set and data is deported @@ -50,6 +52,8 @@ func NewBugExcerpt(b bug.Interface, snap *bug.Snapshot) *BugExcerpt { EditUnixTime: snap.LastEditUnix(), Status: snap.Status, Labels: snap.Labels, + Title: snap.Title, + LenComments: len(snap.Comments), CreateMetadata: b.FirstOp().AllMetadata(), } diff --git a/cache/filter.go b/cache/filter.go index 022a8ff2..b6872508 100644 --- a/cache/filter.go +++ b/cache/filter.go @@ -55,6 +55,16 @@ func LabelFilter(label string) Filter { } } +// TitleFilter return a Filter that match if the title contains the given query +func TitleFilter(query string) Filter { + return func(repo *RepoCache, excerpt *BugExcerpt) bool { + return strings.Contains( + strings.ToLower(excerpt.Title), + strings.ToLower(query), + ) + } +} + // NoLabelFilter return a Filter that match the absence of labels func NoLabelFilter() Filter { return func(repoCache *RepoCache, excerpt *BugExcerpt) bool { @@ -67,6 +77,7 @@ type Filters struct { Status []Filter Author []Filter Label []Filter + Title []Filter NoFilters []Filter } @@ -88,6 +99,10 @@ func (f *Filters) Match(repoCache *RepoCache, excerpt *BugExcerpt) bool { return false } + if match := f.andMatch(f.Title, repoCache, excerpt); !match { + return false + } + return true } diff --git a/cache/filter_test.go b/cache/filter_test.go new file mode 100644 index 00000000..a47d2ad7 --- /dev/null +++ b/cache/filter_test.go @@ -0,0 +1,34 @@ +package cache + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestTitleFilter(t *testing.T) { + tests := []struct { + name string + title string + query string + match bool + }{ + {name: "complete match", title: "hello world", query: "hello world", match: true}, + {name: "partial match", title: "hello world", query: "hello", match: true}, + {name: "no match", title: "hello world", query: "foo", match: false}, + {name: "cased title", title: "Hello World", query: "hello", match: true}, + {name: "cased query", title: "hello world", query: "Hello", match: true}, + + // Those following tests should work eventually but are left for a future iteration. + + // {name: "cased accents", title: "ÑOÑO", query: "ñoño", match: true}, + // {name: "natural language matching", title: "Århus", query: "Aarhus", match: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + filter := TitleFilter(tt.query) + excerpt := &BugExcerpt{Title: tt.title} + assert.Equal(t, tt.match, filter(nil, excerpt)) + }) + } +} diff --git a/cache/query.go b/cache/query.go index 6ffa6510..39815d32 100644 --- a/cache/query.go +++ b/cache/query.go @@ -60,6 +60,10 @@ func ParseQuery(query string) (*Query, error) { f := LabelFilter(qualifierQuery) result.Label = append(result.Label, f) + case "title": + f := TitleFilter(qualifierQuery) + result.Label = append(result.Title, f) + case "no": err := result.parseNoFilter(qualifierQuery) if err != nil { diff --git a/cache/query_test.go b/cache/query_test.go index 29d2f585..f34b3e6a 100644 --- a/cache/query_test.go +++ b/cache/query_test.go @@ -22,6 +22,9 @@ func TestQueryParse(t *testing.T) { {"label:hello", true}, {`label:"Good first issue"`, true}, + {"title:titleOne", true}, + {`title:"Bug titleTwo"`, true}, + {"sort:edit", true}, {"sort:unknown", false}, } diff --git a/commands/ls.go b/commands/ls.go index 75b7ceaf..75819f1a 100644 --- a/commands/ls.go +++ b/commands/ls.go @@ -5,7 +5,6 @@ import ( "strings" "github.com/MichaelMure/git-bug/cache" - "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/colors" "github.com/MichaelMure/git-bug/util/interrupt" "github.com/spf13/cobra" @@ -14,6 +13,7 @@ import ( var ( lsStatusQuery []string lsAuthorQuery []string + lsTitleQuery []string lsLabelQuery []string lsNoQuery []string lsSortBy string @@ -45,30 +45,22 @@ func runLsBug(cmd *cobra.Command, args []string) error { allIds := backend.QueryBugs(query) for _, id := range allIds { - b, err := backend.ResolveBug(id) + b, err := backend.ResolveBugExcerpt(id) if err != nil { return err } - snapshot := b.Snapshot() - - var author identity.Interface - - if len(snapshot.Comments) > 0 { - create := snapshot.Comments[0] - author = create.Author - } - // truncate + pad if needed - titleFmt := fmt.Sprintf("%-50.50s", snapshot.Title) - authorFmt := fmt.Sprintf("%-15.15s", author.DisplayName()) + titleFmt := fmt.Sprintf("%-50.50s", b.Title) + authorFmt := fmt.Sprintf("%-15.15s", b.LegacyAuthor.Name) - fmt.Printf("%s %s\t%s\t%s\t%s\n", + fmt.Printf("%s %s\t%s\t%s\tC:%d L:%d\n", colors.Cyan(b.HumanId()), - colors.Yellow(snapshot.Status), + colors.Yellow(b.Status), titleFmt, colors.Magenta(authorFmt), - snapshot.Summary(), + b.LenComments, + len(b.Labels), ) } @@ -87,6 +79,11 @@ func lsQueryFromFlags() (*cache.Query, error) { query.Status = append(query.Status, f) } + for _, title := range lsTitleQuery { + f := cache.TitleFilter(title) + query.Title = append(query.Title, f) + } + for _, author := range lsAuthorQuery { f := cache.AuthorFilter(author) query.Author = append(query.Author, f) @@ -156,6 +153,8 @@ func init() { "Filter by author") lsCmd.Flags().StringSliceVarP(&lsLabelQuery, "label", "l", nil, "Filter by label") + lsCmd.Flags().StringSliceVarP(&lsTitleQuery, "title", "t", nil, + "Filter by title") lsCmd.Flags().StringSliceVarP(&lsNoQuery, "no", "n", nil, "Filter by absence of something. Valid values are [label]") lsCmd.Flags().StringVarP(&lsSortBy, "by", "b", "creation", diff --git a/doc/man/git-bug-ls.1 b/doc/man/git-bug-ls.1 index eb985fd2..7b3a0aa6 100644 --- a/doc/man/git-bug-ls.1 +++ b/doc/man/git-bug-ls.1 @@ -35,6 +35,10 @@ You can pass an additional query to filter and order the list. This query can be Filter by label .PP +\fB\-t\fP, \fB\-\-title\fP=[] + Filter by title + +.PP \fB\-n\fP, \fB\-\-no\fP=[] Filter by absence of something. Valid values are [label] diff --git a/doc/md/git-bug_ls.md b/doc/md/git-bug_ls.md index 18ac5d61..9ab71884 100644 --- a/doc/md/git-bug_ls.md +++ b/doc/md/git-bug_ls.md @@ -29,6 +29,7 @@ git bug ls --status closed --by creation -s, --status strings Filter by status. Valid values are [open,closed] -a, --author strings Filter by author -l, --label strings Filter by label + -t, --title strings Filter by title -n, --no strings Filter by absence of something. Valid values are [label] -b, --by string Sort the results by a characteristic. Valid values are [id,creation,edit] (default "creation") -d, --direction string Select the sorting direction. Valid values are [asc,desc] (default "asc") diff --git a/doc/queries.md b/doc/queries.md index 93135070..224b59a0 100644 --- a/doc/queries.md +++ b/doc/queries.md @@ -42,6 +42,16 @@ You can filter based on the bug's label. | `label:LABEL` | `label:prod` matches bugs with the label `prod` | | | `label:"Good first issue"` matches bugs with the label `Good first issue` | +### Filtering by title + +You can filter based on the bug's title. + +| Qualifier | Example | +| --- | --- | +| `title:TITLE` | `title:Critical` matches bugs with a title containing `Critical` | +| | `title:"Typo in string"` matches bugs with a title containing `Typo in string` | + + ### Filtering by missing feature You can filter bugs based on the absence of something. diff --git a/input/input.go b/input/input.go index c36b9046..789373b0 100644 --- a/input/input.go +++ b/input/input.go @@ -193,6 +193,7 @@ const queryTemplate = `%s # # - status:open, status:closed # - author:<query> +# - title:<title> # - label:<label> # - no:label # diff --git a/misc/bash_completion/git-bug b/misc/bash_completion/git-bug index a0ac545c..ec8c64ea 100644 --- a/misc/bash_completion/git-bug +++ b/misc/bash_completion/git-bug @@ -535,6 +535,9 @@ _git-bug_ls() flags+=("--label=") two_word_flags+=("-l") local_nonpersistent_flags+=("--label=") + flags+=("--title=") + two_word_flags+=("-t") + local_nonpersistent_flags+=("--title=") flags+=("--no=") two_word_flags+=("-n") local_nonpersistent_flags+=("--no=") |