Skip to content

Commit

Permalink
Allows repo search to match against "owner/repo" pattern strings (go-…
Browse files Browse the repository at this point in the history
…gitea#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
  • Loading branch information
Eekle authored and AbdulrhmnGhanem committed Aug 23, 2022
1 parent 107794f commit e7ae5b4
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 1 deletion.
13 changes: 13 additions & 0 deletions models/repo_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)})
}
Expand Down Expand Up @@ -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)
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

0 comments on commit e7ae5b4

Please sign in to comment.