mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-04 08:34:30 +01:00 
			
		
		
		
	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
					
				@ -459,6 +459,15 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
 | 
				
			|||||||
			likes := builder.NewCond()
 | 
								likes := builder.NewCond()
 | 
				
			||||||
			for _, v := range strings.Split(opts.Keyword, ",") {
 | 
								for _, v := range strings.Split(opts.Keyword, ",") {
 | 
				
			||||||
				likes = likes.Or(builder.Like{"lower_name", strings.ToLower(v)})
 | 
									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 {
 | 
									if opts.IncludeDescription {
 | 
				
			||||||
					likes = likes.Or(builder.Like{"LOWER(description)", strings.ToLower(v)})
 | 
										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 {
 | 
						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))
 | 
							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)
 | 
						sess := db.GetEngine(ctx)
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@
 | 
				
			|||||||
package models
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models/db"
 | 
						"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},
 | 
								opts:  &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Template: util.OptionalBoolTrue},
 | 
				
			||||||
			count: 2,
 | 
								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 {
 | 
						for _, testCase := range testCases {
 | 
				
			||||||
@ -285,8 +296,22 @@ func TestSearchRepository(t *testing.T) {
 | 
				
			|||||||
					assert.NotEmpty(t, repo.Name)
 | 
										assert.NotEmpty(t, repo.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					if len(testCase.opts.Keyword) > 0 {
 | 
										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)
 | 
												assert.Contains(t, repo.Name, testCase.opts.Keyword)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					if !testCase.opts.Private {
 | 
										if !testCase.opts.Private {
 | 
				
			||||||
						assert.False(t, repo.IsPrivate)
 | 
											assert.False(t, repo.IsPrivate)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user