aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bug/snapshot.go8
-rw-r--r--cache/bug_excerpt.go8
-rw-r--r--cache/filter.go15
-rw-r--r--cache/filter_test.go34
-rw-r--r--cache/query.go4
-rw-r--r--cache/query_test.go3
-rw-r--r--commands/ls.go31
-rw-r--r--doc/man/git-bug-ls.14
-rw-r--r--doc/md/git-bug_ls.md1
-rw-r--r--doc/queries.md10
-rw-r--r--input/input.go1
-rw-r--r--misc/bash_completion/git-bug3
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=")