mirror of
https://github.com/go-gitea/gitea
synced 2024-06-01 19:06:52 +02:00
Compare commits
3 Commits
3e2f801cd8
...
8082870e96
Author | SHA1 | Date | |
---|---|---|---|
|
8082870e96 | ||
|
1f9a9fab5f | ||
|
7ad2d039fd |
|
@ -29,6 +29,7 @@ type GrepOptions struct {
|
||||||
ContextLineNumber int
|
ContextLineNumber int
|
||||||
IsFuzzy bool
|
IsFuzzy bool
|
||||||
MaxLineLength int // the maximum length of a line to parse, exceeding chars will be truncated
|
MaxLineLength int // the maximum length of a line to parse, exceeding chars will be truncated
|
||||||
|
PathspecList []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepOptions) ([]*GrepResult, error) {
|
func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepOptions) ([]*GrepResult, error) {
|
||||||
|
@ -62,6 +63,7 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
|
||||||
cmd.AddOptionValues("-e", strings.TrimLeft(search, "-"))
|
cmd.AddOptionValues("-e", strings.TrimLeft(search, "-"))
|
||||||
}
|
}
|
||||||
cmd.AddDynamicArguments(util.IfZero(opts.RefName, "HEAD"))
|
cmd.AddDynamicArguments(util.IfZero(opts.RefName, "HEAD"))
|
||||||
|
cmd.AddDashesAndList(opts.PathspecList...)
|
||||||
opts.MaxResultLimit = util.IfZero(opts.MaxResultLimit, 50)
|
opts.MaxResultLimit = util.IfZero(opts.MaxResultLimit, 50)
|
||||||
stderr := bytes.Buffer{}
|
stderr := bytes.Buffer{}
|
||||||
err = cmd.Run(&RunOpts{
|
err = cmd.Run(&RunOpts{
|
||||||
|
|
|
@ -31,6 +31,26 @@ func TestGrepSearch(t *testing.T) {
|
||||||
},
|
},
|
||||||
}, res)
|
}, res)
|
||||||
|
|
||||||
|
res, err = GrepSearch(context.Background(), repo, "void", GrepOptions{PathspecList: []string{":(glob)java-hello/*"}})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []*GrepResult{
|
||||||
|
{
|
||||||
|
Filename: "java-hello/main.java",
|
||||||
|
LineNumbers: []int{3},
|
||||||
|
LineCodes: []string{" public static void main(String[] args)"},
|
||||||
|
},
|
||||||
|
}, res)
|
||||||
|
|
||||||
|
res, err = GrepSearch(context.Background(), repo, "void", GrepOptions{PathspecList: []string{":(glob,exclude)java-hello/*"}})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []*GrepResult{
|
||||||
|
{
|
||||||
|
Filename: "main.vendor.java",
|
||||||
|
LineNumbers: []int{3},
|
||||||
|
LineCodes: []string{" public static void main(String[] args)"},
|
||||||
|
},
|
||||||
|
}, res)
|
||||||
|
|
||||||
res, err = GrepSearch(context.Background(), repo, "void", GrepOptions{MaxResultLimit: 1})
|
res, err = GrepSearch(context.Background(), repo, "void", GrepOptions{MaxResultLimit: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, []*GrepResult{
|
assert.Equal(t, []*GrepResult{
|
||||||
|
|
32
modules/setting/glob.go
Normal file
32
modules/setting/glob.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package setting
|
||||||
|
|
||||||
|
import "github.com/gobwas/glob"
|
||||||
|
|
||||||
|
type GlobMatcher struct {
|
||||||
|
compiledGlob glob.Glob
|
||||||
|
patternString string
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ glob.Glob = (*GlobMatcher)(nil)
|
||||||
|
|
||||||
|
func (g *GlobMatcher) Match(s string) bool {
|
||||||
|
return g.compiledGlob.Match(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GlobMatcher) PatternString() string {
|
||||||
|
return g.patternString
|
||||||
|
}
|
||||||
|
|
||||||
|
func GlobMatcherCompile(pattern string, separators ...rune) (*GlobMatcher, error) {
|
||||||
|
g, err := glob.Compile(pattern, separators...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &GlobMatcher{
|
||||||
|
compiledGlob: g,
|
||||||
|
patternString: pattern,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -10,8 +10,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Indexer settings
|
// Indexer settings
|
||||||
|
@ -30,8 +28,8 @@ var Indexer = struct {
|
||||||
RepoConnStr string
|
RepoConnStr string
|
||||||
RepoIndexerName string
|
RepoIndexerName string
|
||||||
MaxIndexerFileSize int64
|
MaxIndexerFileSize int64
|
||||||
IncludePatterns []glob.Glob
|
IncludePatterns []*GlobMatcher
|
||||||
ExcludePatterns []glob.Glob
|
ExcludePatterns []*GlobMatcher
|
||||||
ExcludeVendored bool
|
ExcludeVendored bool
|
||||||
}{
|
}{
|
||||||
IssueType: "bleve",
|
IssueType: "bleve",
|
||||||
|
@ -93,12 +91,12 @@ func loadIndexerFrom(rootCfg ConfigProvider) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IndexerGlobFromString parses a comma separated list of patterns and returns a glob.Glob slice suited for repo indexing
|
// IndexerGlobFromString parses a comma separated list of patterns and returns a glob.Glob slice suited for repo indexing
|
||||||
func IndexerGlobFromString(globstr string) []glob.Glob {
|
func IndexerGlobFromString(globstr string) []*GlobMatcher {
|
||||||
extarr := make([]glob.Glob, 0, 10)
|
extarr := make([]*GlobMatcher, 0, 10)
|
||||||
for _, expr := range strings.Split(strings.ToLower(globstr), ",") {
|
for _, expr := range strings.Split(strings.ToLower(globstr), ",") {
|
||||||
expr = strings.TrimSpace(expr)
|
expr = strings.TrimSpace(expr)
|
||||||
if expr != "" {
|
if expr != "" {
|
||||||
if g, err := glob.Compile(expr, '.', '/'); err != nil {
|
if g, err := GlobMatcherCompile(expr, '.', '/'); err != nil {
|
||||||
log.Info("Invalid glob expression '%s' (skipped): %v", expr, err)
|
log.Info("Invalid glob expression '%s' (skipped): %v", expr, err)
|
||||||
} else {
|
} else {
|
||||||
extarr = append(extarr, g)
|
extarr = append(extarr, g)
|
||||||
|
|
|
@ -6,10 +6,8 @@ package user
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/perm"
|
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
unit_model "code.gitea.io/gitea/models/unit"
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
|
@ -44,7 +42,7 @@ func listUserRepos(ctx *context.APIContext, u *user_model.User, private bool) {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
|
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ctx.IsSigned && ctx.Doer.IsAdmin || permission.UnitAccessMode(unit_model.TypeCode) >= perm.AccessModeRead {
|
if ctx.IsSigned && ctx.Doer.IsAdmin || permission.HasAnyUnitAccess() {
|
||||||
apiRepos = append(apiRepos, convert.ToRepo(ctx, repos[i], permission))
|
apiRepos = append(apiRepos, convert.ToRepo(ctx, repos[i], permission))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,16 @@ import (
|
||||||
|
|
||||||
const tplSearch base.TplName = "repo/search"
|
const tplSearch base.TplName = "repo/search"
|
||||||
|
|
||||||
|
func indexSettingToGitGrepPathspecList() (list []string) {
|
||||||
|
for _, expr := range setting.Indexer.IncludePatterns {
|
||||||
|
list = append(list, ":(glob)"+expr.PatternString())
|
||||||
|
}
|
||||||
|
for _, expr := range setting.Indexer.ExcludePatterns {
|
||||||
|
list = append(list, ":(glob,exclude)"+expr.PatternString())
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
// Search render repository search page
|
// Search render repository search page
|
||||||
func Search(ctx *context.Context) {
|
func Search(ctx *context.Context) {
|
||||||
language := ctx.FormTrim("l")
|
language := ctx.FormTrim("l")
|
||||||
|
@ -65,8 +75,14 @@ func Search(ctx *context.Context) {
|
||||||
ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable(ctx)
|
ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable(ctx)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res, err := git.GrepSearch(ctx, ctx.Repo.GitRepo, keyword, git.GrepOptions{ContextLineNumber: 3, IsFuzzy: isFuzzy})
|
res, err := git.GrepSearch(ctx, ctx.Repo.GitRepo, keyword, git.GrepOptions{
|
||||||
|
ContextLineNumber: 1,
|
||||||
|
IsFuzzy: isFuzzy,
|
||||||
|
RefName: git.RefNameFromBranch(ctx.Repo.BranchName).String(), // BranchName should be default branch or the first existing branch
|
||||||
|
PathspecList: indexSettingToGitGrepPathspecList(),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// TODO: if no branch exists, it reports: exit status 128, fatal: this operation must be run in a work tree.
|
||||||
ctx.ServerError("GrepSearch", err)
|
ctx.ServerError("GrepSearch", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
19
routers/web/repo/search_test.go
Normal file
19
routers/web/repo/search_test.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIndexSettingToGitGrepPathspecList(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&setting.Indexer.IncludePatterns, setting.IndexerGlobFromString("a"))()
|
||||||
|
defer test.MockVariableValue(&setting.Indexer.ExcludePatterns, setting.IndexerGlobFromString("b"))()
|
||||||
|
assert.Equal(t, []string{":(glob)a", ":(glob,exclude)b"}, indexSettingToGitGrepPathspecList())
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
unit_model "code.gitea.io/gitea/models/unit"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
@ -326,6 +327,39 @@ func TestAPIOrgRepos(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See issue #28483. Tests to make sure we consider more than just code unit-enabled repositories.
|
||||||
|
func TestAPIOrgReposWithCodeUnitDisabled(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
repo21 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: "repo21"})
|
||||||
|
org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo21.OwnerID})
|
||||||
|
|
||||||
|
// Disable code repository unit.
|
||||||
|
var units []unit_model.Type
|
||||||
|
units = append(units, unit_model.TypeCode)
|
||||||
|
|
||||||
|
if err := repo_service.UpdateRepositoryUnits(db.DefaultContext, repo21, nil, units); err != nil {
|
||||||
|
assert.Fail(t, "should have been able to delete code repository unit; failed to %v", err)
|
||||||
|
}
|
||||||
|
assert.False(t, repo21.UnitEnabled(db.DefaultContext, unit_model.TypeCode))
|
||||||
|
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadOrganization)
|
||||||
|
|
||||||
|
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", org3.Name).
|
||||||
|
AddTokenAuth(token)
|
||||||
|
|
||||||
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
var apiRepos []*api.Repository
|
||||||
|
DecodeJSON(t, resp, &apiRepos)
|
||||||
|
|
||||||
|
var repoNames []string
|
||||||
|
for _, r := range apiRepos {
|
||||||
|
repoNames = append(repoNames, r.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Contains(t, repoNames, repo21.Name)
|
||||||
|
}
|
||||||
|
|
||||||
func TestAPIGetRepoByIDUnauthorized(t *testing.T) {
|
func TestAPIGetRepoByIDUnauthorized(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
|
||||||
|
|
Loading…
Reference in New Issue
Block a user