1
0
mirror of https://gitea.com/jolheiser/sip synced 2024-11-22 19:51:58 +01:00

Add qualifier module (#10)

Add qualify module

Signed-off-by: jolheiser <john.olheiser@gmail.com>

Co-authored-by: jolheiser <john.olheiser@gmail.com>
Reviewed-on: https://gitea.com/jolheiser/sip/pulls/10
This commit is contained in:
John Olheiser 2020-03-06 04:18:36 +00:00
parent 222dcf402b
commit 4490cc9888
4 changed files with 161 additions and 27 deletions

@ -0,0 +1,83 @@
package qualify
import (
"strings"
)
type Query map[string]Filter
type Filter []string
func (q Query) Query() string {
if query, ok := q["query"]; ok {
return strings.Join(query, " ")
}
return ""
}
func (f Filter) Last() string {
return f[len(f)-1]
}
func Parse(text string, qualifiers ...string) Query {
queries := make(map[string]Filter)
for _, field := range fields(text) {
var key, value string
if k, v, ok := qualified(field, qualifiers...); ok {
key = k
value = trim(v)
} else {
key = "query"
value = trim(field)
}
if queries[key] == nil {
queries[key] = make([]string, 0)
}
queries[key] = append(queries[key], value)
}
return queries
}
func qualified(text string, qualifiers ...string) (string, string, bool) {
if len(qualifiers) == 0 && strings.Contains(text, ":") {
kv := strings.SplitN(text, ":", 2)
return kv[0], kv[1], true
}
for _, qualifier := range qualifiers {
if strings.HasPrefix(text, qualifier+":") {
return text[:len(qualifier)], text[len(qualifier)+1:], true
}
}
return "", "", false
}
func fields(text string) []string {
var f []string
var quotes bool
var last int
for idx, char := range text {
if char == '"' {
quotes = !quotes
continue
}
if char == ' ' {
if quotes {
continue
}
f = append(f, text[last:idx])
last = idx + 1
}
}
f = append(f, strings.TrimSpace(text[last:]))
return f
}
func trim(text string) string {
return strings.TrimPrefix(strings.TrimSuffix(strings.TrimSpace(text), `"`), `"`)
}

@ -0,0 +1,49 @@
package qualify
import (
"fmt"
"os"
"strconv"
"strings"
"testing"
)
func TestMain(m *testing.M) {
os.Exit(m.Run())
}
func TestParse(t *testing.T) {
tt := []struct {
Query string
Result string
Qualifiers []string
}{
{"test", "query->test", nil},
{`"test"`, "query->test", nil},
{"author:jolheiser", "author->jolheiser", nil},
{`"this is a test" author:"jolheiser"`, "query->this is a test,author->jolheiser", nil},
{`"this is" "a test" query`, "query->this is|a test|query", nil},
{`label:"a bug" label:"a" label:"bug"`, "label->a bug|a|bug", nil},
{`author:"jolheiser""`, `author->jolheiser"`, nil},
{`author:""jolheiser""`, `author->"jolheiser"`, nil},
{"test:testing", "query->test:testing", []string{"label"}},
}
for idx, tc := range tt {
t.Run(strconv.Itoa(idx+1), func(t *testing.T) {
parsed := result(Parse(tc.Query, tc.Qualifiers...))
if parsed != tc.Result {
t.Logf("\nwant: %s\n got: %s", tc.Result, parsed)
t.Fail()
}
})
}
}
func result(parsed Query) string {
res := make([]string, 0, len(parsed))
for key, values := range parsed {
res = append(res, fmt.Sprintf("%s->%s", key, strings.Join(values, "|")))
}
return strings.Join(res, ",")
}

@ -2,6 +2,7 @@ package sdk
import ( import (
"code.gitea.io/sdk/gitea" "code.gitea.io/sdk/gitea"
"gitea.com/jolheiser/sip/modules/qualify"
"strings" "strings"
) )
@ -87,34 +88,34 @@ func (f *IssueFilter) Match(issue *gitea.Issue) bool {
func NewIssueFilter(query string) *IssueFilter { func NewIssueFilter(query string) *IssueFilter {
filter := &IssueFilter{} filter := &IssueFilter{}
for _, q := range strings.Split(query, " ") { filters := qualify.Parse(query, "is", "author", "label", "milestone")
kv := strings.Split(q, ":")
if len(kv) == 2 { if state, ok := filters["is"]; ok {
kv[0] = strings.ToLower(kv[0]) switch state.Last() {
kv[1] = strings.ToLower(kv[1]) case "open", "opened":
switch kv[0] { filter.State = Open
case "is": case "close", "closed":
switch kv[1] { filter.State = Closed
case "open", "opened": case "merge", "merged":
filter.State = Open filter.State = Merged
case "close", "closed": default:
filter.State = Closed filter.State = None
case "merge", "merged":
filter.State = Merged
default:
filter.State = None
}
case "author":
filter.Author = kv[1]
case "label":
filter.Labels = append(filter.Labels, kv[1])
case "milestone":
filter.Milestone = kv[1]
}
continue
} }
filter.Query += " " + q
} }
filter.Query = strings.TrimSpace(filter.Query)
if author, ok := filters["author"]; ok {
filter.Author = author.Last()
}
if label, ok := filters["label"]; ok {
filter.Labels = append(filter.Labels, label...)
}
if milestone, ok := filters["milestone"]; ok {
filter.Milestone = milestone.Last()
}
filter.Query = filters.Query()
return filter return filter
} }

@ -26,6 +26,7 @@ func TestIssueFilter(t *testing.T) {
{"is:closed milestone:0.1.0", &IssueFilter{State: Closed, Milestone: "0.1.0"}}, {"is:closed milestone:0.1.0", &IssueFilter{State: Closed, Milestone: "0.1.0"}},
{"milestone:v1.0.0 keyword", &IssueFilter{Query: "keyword", Milestone: "v1.0.0"}}, {"milestone:v1.0.0 keyword", &IssueFilter{Query: "keyword", Milestone: "v1.0.0"}},
{`label:"a bug" keyword`, &IssueFilter{Query: "keyword", Labels: []string{"a bug"}}},
} }
for idx, tc := range tt { for idx, tc := range tt {