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:
parent
222dcf402b
commit
4490cc9888
83
modules/qualify/qualify.go
Normal file
83
modules/qualify/qualify.go
Normal file
@ -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), `"`), `"`)
|
||||||
|
}
|
49
modules/qualify/qualify_test.go
Normal file
49
modules/qualify/qualify_test.go
Normal file
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user