Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions models/repo_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,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)})
}
Expand Down Expand Up @@ -547,6 +556,10 @@ func searchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond) (db

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(db.DefaultContext)
Expand Down
27 changes: 26 additions & 1 deletion models/repo_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package models

import (
"strings"
"testing"

"code.gitea.io/gitea/models/db"
Expand Down Expand Up @@ -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 {
Expand All @@ -285,7 +296,21 @@ func TestSearchRepository(t *testing.T) {
assert.NotEmpty(t, repo.Name)

if len(testCase.opts.Keyword) > 0 {
assert.Contains(t, repo.Name, testCase.opts.Keyword)
// 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 {
Expand Down