Allows repo search to match against "owner/repo" pattern strings (#19754)
* Allows repo search to match against "owner/repo" pattern strings * Gofumpt * Adds test case for "owner/repo" style repo search * With "owner/repo" search terms, prioritise results which match the owner field * Fixes unquoted SQL string in repo search
This commit is contained in:
parent
ba7750d6e7
commit
876cad0064
2 changed files with 39 additions and 1 deletions
|
@ -459,6 +459,15 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
|
|||
likes := builder.NewCond()
|
||||
for _, v := range strings.Split(opts.Keyword, ",") {
|
||||
likes = likes.Or(builder.Like{"lower_name", strings.ToLower(v)})
|
||||
|
||||
// If the string looks like "org/repo", match against that pattern too
|
||||
if opts.TeamID == 0 && strings.Count(opts.Keyword, "/") == 1 {
|
||||
pieces := strings.Split(opts.Keyword, "/")
|
||||
ownerName := pieces[0]
|
||||
repoName := pieces[1]
|
||||
likes = likes.Or(builder.And(builder.Like{"owner_name", strings.ToLower(ownerName)}, builder.Like{"lower_name", strings.ToLower(repoName)}))
|
||||
}
|
||||
|
||||
if opts.IncludeDescription {
|
||||
likes = likes.Or(builder.Like{"LOWER(description)", strings.ToLower(v)})
|
||||
}
|
||||
|
@ -549,6 +558,10 @@ func searchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, c
|
|||
|
||||
if opts.PriorityOwnerID > 0 {
|
||||
opts.OrderBy = db.SearchOrderBy(fmt.Sprintf("CASE WHEN owner_id = %d THEN 0 ELSE owner_id END, %s", opts.PriorityOwnerID, opts.OrderBy))
|
||||
} else if strings.Count(opts.Keyword, "/") == 1 {
|
||||
// With "owner/repo" search times, prioritise results which match the owner field
|
||||
orgName := strings.Split(opts.Keyword, "/")[0]
|
||||
opts.OrderBy = db.SearchOrderBy(fmt.Sprintf("CASE WHEN owner_name LIKE '%s' THEN 0 ELSE 1 END, %s", orgName, opts.OrderBy))
|
||||
}
|
||||
|
||||
sess := db.GetEngine(ctx)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
|
@ -261,6 +262,16 @@ func TestSearchRepository(t *testing.T) {
|
|||
opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Template: util.OptionalBoolTrue},
|
||||
count: 2,
|
||||
},
|
||||
{
|
||||
name: "OwnerSlashRepoSearch",
|
||||
opts: &SearchRepoOptions{Keyword: "user/repo2", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, OwnerID: 0},
|
||||
count: 3,
|
||||
},
|
||||
{
|
||||
name: "OwnerSlashSearch",
|
||||
opts: &SearchRepoOptions{Keyword: "user20/", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, OwnerID: 0},
|
||||
count: 4,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
|
@ -285,8 +296,22 @@ func TestSearchRepository(t *testing.T) {
|
|||
assert.NotEmpty(t, repo.Name)
|
||||
|
||||
if len(testCase.opts.Keyword) > 0 {
|
||||
// Keyword match condition is different for search terms of form "owner/repo"
|
||||
if strings.Count(testCase.opts.Keyword, "/") == 1 {
|
||||
// May still match as a whole...
|
||||
wholeMatch := strings.Contains(repo.Name, testCase.opts.Keyword)
|
||||
|
||||
pieces := strings.Split(testCase.opts.Keyword, "/")
|
||||
ownerName := pieces[0]
|
||||
repoName := pieces[1]
|
||||
// ... or match in parts
|
||||
splitMatch := strings.Contains(repo.OwnerName, ownerName) && strings.Contains(repo.Name, repoName)
|
||||
|
||||
assert.True(t, wholeMatch || splitMatch, "Keyword '%s' does not match repo '%s/%s'", testCase.opts.Keyword, repo.Owner.Name, repo.Name)
|
||||
} else {
|
||||
assert.Contains(t, repo.Name, testCase.opts.Keyword)
|
||||
}
|
||||
}
|
||||
|
||||
if !testCase.opts.Private {
|
||||
assert.False(t, repo.IsPrivate)
|
||||
|
|
Reference in a new issue