mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 16:51:55 +00:00
f:has.owners supports assigned owners (#52219)
This pull request integrates assigned owners (and the `Bag` into search filtering). <img width="1125" alt="Screenshot 2023-05-19 at 9 47 20 PM" src="https://github.com/sourcegraph/sourcegraph/assets/153410/5f6b1579-9d48-49fc-8629-cfe396554a14"> ## Test plan Extend filter_job_test.go.
This commit is contained in:
parent
e349ccfd3b
commit
2bc23d7a71
@ -92,7 +92,6 @@ type Bag interface {
|
||||
func ByTextReference(ctx context.Context, db edb.EnterpriseDB, text ...string) (Bag, error) {
|
||||
var multiBag bag
|
||||
for _, t := range text {
|
||||
t = strings.TrimPrefix(t, "@")
|
||||
if _, err := mail.ParseAddress(t); err == nil {
|
||||
b, err := ByEmailReference(ctx, db, t)
|
||||
if err != nil {
|
||||
@ -100,7 +99,7 @@ func ByTextReference(ctx context.Context, db edb.EnterpriseDB, text ...string) (
|
||||
}
|
||||
multiBag = append(multiBag, b...)
|
||||
}
|
||||
b, err := ByUserHandleReference(ctx, db, t)
|
||||
b, err := ByUserHandleReference(ctx, db, strings.TrimPrefix(t, "@"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
2
enterprise/internal/own/search/BUILD.bazel
generated
2
enterprise/internal/own/search/BUILD.bazel
generated
@ -10,6 +10,7 @@ go_library(
|
||||
importpath = "github.com/sourcegraph/sourcegraph/enterprise/internal/own/search",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//enterprise/internal/database",
|
||||
"//enterprise/internal/own",
|
||||
"//enterprise/internal/own/codeowners",
|
||||
"//enterprise/internal/own/codeowners/v1:codeowners",
|
||||
@ -35,6 +36,7 @@ go_test(
|
||||
embed = [":search"],
|
||||
deps = [
|
||||
"//enterprise/internal/database",
|
||||
"//enterprise/internal/own",
|
||||
"//internal/api",
|
||||
"//internal/authz",
|
||||
"//internal/database",
|
||||
|
||||
@ -3,12 +3,12 @@ package search
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
|
||||
codeownerspb "github.com/sourcegraph/sourcegraph/enterprise/internal/own/codeowners/v1"
|
||||
"github.com/sourcegraph/sourcegraph/enterprise/internal/database"
|
||||
"github.com/sourcegraph/sourcegraph/enterprise/internal/own"
|
||||
"github.com/sourcegraph/sourcegraph/internal/search"
|
||||
"github.com/sourcegraph/sourcegraph/internal/search/job"
|
||||
"github.com/sourcegraph/sourcegraph/internal/search/result"
|
||||
@ -55,9 +55,19 @@ func (s *fileHasOwnersJob) Run(ctx context.Context, clients job.RuntimeClients,
|
||||
|
||||
rules := NewRulesCache(clients.Gitserver, clients.DB)
|
||||
|
||||
// Bag the search terms
|
||||
includeBag, err := own.ByTextReference(ctx, database.NewEnterpriseDB(clients.DB), s.includeOwners...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failure trying to resolve search term")
|
||||
}
|
||||
excludeBag, err := own.ByTextReference(ctx, database.NewEnterpriseDB(clients.DB), s.excludeOwners...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failure trying to resolve search term")
|
||||
}
|
||||
|
||||
filteredStream := streaming.StreamFunc(func(event streaming.SearchEvent) {
|
||||
var err error
|
||||
event.Results, err = applyCodeOwnershipFiltering(ctx, &rules, s.includeOwners, s.excludeOwners, event.Results)
|
||||
event.Results, err = applyCodeOwnershipFiltering(ctx, &rules, includeBag, s.includeOwners, excludeBag, s.excludeOwners, event.Results)
|
||||
if err != nil {
|
||||
mu.Lock()
|
||||
errs = errors.Append(errs, err)
|
||||
@ -103,8 +113,10 @@ func (s *fileHasOwnersJob) MapChildren(fn job.MapFunc) job.Job {
|
||||
func applyCodeOwnershipFiltering(
|
||||
ctx context.Context,
|
||||
rules *RulesCache,
|
||||
includeOwners,
|
||||
excludeOwners []string,
|
||||
include own.Bag,
|
||||
includeTerms []string,
|
||||
exclude own.Bag,
|
||||
excludeTerms []string,
|
||||
matches []result.Match,
|
||||
) ([]result.Match, error) {
|
||||
var errs error
|
||||
@ -124,21 +136,12 @@ matchesLoop:
|
||||
errs = errors.Append(errs, err)
|
||||
continue matchesLoop
|
||||
}
|
||||
rule := file.Match(mm.File.Path)
|
||||
var owners []*codeownerspb.Owner
|
||||
// If match.
|
||||
if rule != nil {
|
||||
owners = rule.GetOwner()
|
||||
fileOwners := file.Match(mm.File.Path)
|
||||
if len(includeTerms) > 0 && !containsOwner(fileOwners, includeTerms, include) {
|
||||
continue matchesLoop
|
||||
}
|
||||
for _, owner := range includeOwners {
|
||||
if !containsOwner(owners, owner) {
|
||||
continue matchesLoop
|
||||
}
|
||||
}
|
||||
for _, notOwner := range excludeOwners {
|
||||
if containsOwner(owners, notOwner) {
|
||||
continue matchesLoop
|
||||
}
|
||||
if len(excludeTerms) > 0 && containsOwner(fileOwners, excludeTerms, exclude) {
|
||||
continue matchesLoop
|
||||
}
|
||||
|
||||
filtered = append(filtered, m)
|
||||
@ -150,21 +153,10 @@ matchesLoop:
|
||||
// containsOwner searches within emails and handles in a case-insensitive
|
||||
// manner. Empty string passed as search term means any, so the predicate
|
||||
// returns true if there is at least one owner, and false otherwise.
|
||||
func containsOwner(owners []*codeownerspb.Owner, owner string) bool {
|
||||
if owner == "" {
|
||||
return len(owners) > 0
|
||||
func containsOwner(owners fileOwnershipData, searchTerms []string, bag own.Bag) bool {
|
||||
// Empty search terms means any owner matches.
|
||||
if len(searchTerms) == 1 && searchTerms[0] == "" {
|
||||
return owners.NonEmpty()
|
||||
}
|
||||
isHandle := strings.HasPrefix(owner, "@")
|
||||
owner = strings.ToLower(strings.TrimPrefix(owner, "@"))
|
||||
for _, o := range owners {
|
||||
if strings.ToLower(o.Handle) == owner {
|
||||
return true
|
||||
}
|
||||
// Prefixing the search term with `@` indicates intent to match a handle,
|
||||
// so we do not match email in that case.
|
||||
if !isHandle && (strings.ToLower(o.Email) == owner) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return owners.Contains(bag)
|
||||
}
|
||||
|
||||
@ -11,12 +11,15 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
edb "github.com/sourcegraph/sourcegraph/enterprise/internal/database"
|
||||
"github.com/sourcegraph/sourcegraph/enterprise/internal/own"
|
||||
"github.com/sourcegraph/sourcegraph/internal/api"
|
||||
"github.com/sourcegraph/sourcegraph/internal/authz"
|
||||
"github.com/sourcegraph/sourcegraph/internal/database"
|
||||
"github.com/sourcegraph/sourcegraph/internal/gitserver"
|
||||
"github.com/sourcegraph/sourcegraph/internal/search"
|
||||
"github.com/sourcegraph/sourcegraph/internal/search/job"
|
||||
"github.com/sourcegraph/sourcegraph/internal/search/result"
|
||||
"github.com/sourcegraph/sourcegraph/internal/types"
|
||||
)
|
||||
|
||||
func TestFeatureFlaggedFileHasOwnerJob(t *testing.T) {
|
||||
@ -45,9 +48,10 @@ func TestApplyCodeOwnershipFiltering(t *testing.T) {
|
||||
repoContent map[string]string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want autogold.Value
|
||||
name string
|
||||
args args
|
||||
setup func(db *edb.MockEnterpriseDB)
|
||||
want autogold.Value
|
||||
}{
|
||||
{
|
||||
// TODO: We should display an error in search describing why the result is empty.
|
||||
@ -285,6 +289,48 @@ func TestApplyCodeOwnershipFiltering(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "selects result with assigned owner",
|
||||
args: args{
|
||||
includeOwners: []string{"test"},
|
||||
excludeOwners: []string{},
|
||||
matches: []result.Match{
|
||||
&result.FileMatch{
|
||||
File: result.File{
|
||||
Path: "src/main/README.md",
|
||||
},
|
||||
},
|
||||
},
|
||||
// No CODEOWNERS
|
||||
repoContent: map[string]string{},
|
||||
},
|
||||
setup: func(db *edb.MockEnterpriseDB) {
|
||||
user := &types.User{
|
||||
ID: 42,
|
||||
Username: "test",
|
||||
}
|
||||
assignedOwners := []*database.AssignedOwnerSummary{
|
||||
{
|
||||
OwnerUserID: user.ID,
|
||||
FilePath: "src/main",
|
||||
},
|
||||
}
|
||||
usersStore := database.NewMockUserStore()
|
||||
usersStore.GetByUsernameFunc.SetDefaultReturn(user, nil)
|
||||
usersStore.GetByVerifiedEmailFunc.SetDefaultReturn(nil, nil)
|
||||
db.UsersFunc.SetDefaultReturn(usersStore)
|
||||
assignedOwnersStore := database.NewMockAssignedOwnersStore()
|
||||
assignedOwnersStore.ListAssignedOwnersForRepoFunc.SetDefaultReturn(assignedOwners, nil)
|
||||
db.AssignedOwnersFunc.SetDefaultReturn(assignedOwnersStore)
|
||||
},
|
||||
want: autogold.Expect([]result.Match{
|
||||
&result.FileMatch{
|
||||
File: result.File{
|
||||
Path: "src/main/README.md",
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@ -303,11 +349,38 @@ func TestApplyCodeOwnershipFiltering(t *testing.T) {
|
||||
codeownersStore.GetCodeownersForRepoFunc.SetDefaultReturn(nil, nil)
|
||||
db := edb.NewMockEnterpriseDB()
|
||||
db.CodeownersFunc.SetDefaultReturn(codeownersStore)
|
||||
usersStore := database.NewMockUserStore()
|
||||
usersStore.GetByUsernameFunc.SetDefaultReturn(nil, nil)
|
||||
usersStore.GetByVerifiedEmailFunc.SetDefaultReturn(nil, nil)
|
||||
db.UsersFunc.SetDefaultReturn(usersStore)
|
||||
usersEmailsStore := database.NewMockUserEmailsStore()
|
||||
usersEmailsStore.GetVerifiedEmailsFunc.SetDefaultReturn(nil, nil)
|
||||
db.UserEmailsFunc.SetDefaultReturn(usersEmailsStore)
|
||||
assignedOwnersStore := database.NewMockAssignedOwnersStore()
|
||||
assignedOwnersStore.ListAssignedOwnersForRepoFunc.SetDefaultReturn(nil, nil)
|
||||
db.AssignedOwnersFunc.SetDefaultReturn(assignedOwnersStore)
|
||||
userExternalAccountsStore := database.NewMockUserExternalAccountsStore()
|
||||
userExternalAccountsStore.ListFunc.SetDefaultReturn(nil, nil)
|
||||
db.UserExternalAccountsFunc.SetDefaultReturn(userExternalAccountsStore)
|
||||
if tt.setup != nil {
|
||||
tt.setup(db)
|
||||
}
|
||||
|
||||
rules := NewRulesCache(gitserverClient, db)
|
||||
|
||||
matches, _ := applyCodeOwnershipFiltering(ctx, &rules, tt.args.includeOwners, tt.args.excludeOwners, tt.args.matches)
|
||||
|
||||
include, err := own.ByTextReference(ctx, db, tt.args.includeOwners...)
|
||||
require.NoError(t, err)
|
||||
exclude, err := own.ByTextReference(ctx, db, tt.args.excludeOwners...)
|
||||
require.NoError(t, err)
|
||||
matches, _ := applyCodeOwnershipFiltering(
|
||||
ctx,
|
||||
&rules,
|
||||
include,
|
||||
tt.args.includeOwners,
|
||||
exclude,
|
||||
tt.args.excludeOwners,
|
||||
tt.args.matches)
|
||||
//require.NoError(t, err)
|
||||
tt.want.Equal(t, matches)
|
||||
})
|
||||
}
|
||||
|
||||
@ -17,30 +17,73 @@ type RulesKey struct {
|
||||
commitID api.CommitID
|
||||
}
|
||||
|
||||
type AssignedKey struct {
|
||||
repoID api.RepoID
|
||||
}
|
||||
|
||||
type RulesCache struct {
|
||||
rules map[RulesKey]*codeowners.Ruleset
|
||||
assigned map[AssignedKey]own.AssignedOwners
|
||||
ownService own.Service
|
||||
|
||||
mu sync.RWMutex
|
||||
rulesMu sync.RWMutex
|
||||
assignedMu sync.RWMutex
|
||||
}
|
||||
|
||||
func NewRulesCache(gs gitserver.Client, db database.DB) RulesCache {
|
||||
return RulesCache{
|
||||
rules: make(map[RulesKey]*codeowners.Ruleset),
|
||||
assigned: make(map[AssignedKey]own.AssignedOwners),
|
||||
ownService: own.NewService(gs, db),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RulesCache) GetFromCacheOrFetch(ctx context.Context, repoName api.RepoName, repoID api.RepoID, commitID api.CommitID) (*codeowners.Ruleset, error) {
|
||||
c.mu.RLock()
|
||||
func (c *RulesCache) GetFromCacheOrFetch(ctx context.Context, repoName api.RepoName, repoID api.RepoID, commitID api.CommitID) (repoOwnershipData, error) {
|
||||
assigned, err := c.AssignedOwners(ctx, repoID, commitID)
|
||||
if err != nil {
|
||||
return repoOwnershipData{}, err
|
||||
}
|
||||
codeowners, err := c.Codeowners(ctx, repoName, repoID, commitID)
|
||||
if err != nil {
|
||||
return repoOwnershipData{}, err
|
||||
}
|
||||
return repoOwnershipData{
|
||||
assigned: assigned,
|
||||
codeowners: codeowners,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *RulesCache) AssignedOwners(ctx context.Context, repoID api.RepoID, commitID api.CommitID) (own.AssignedOwners, error) {
|
||||
c.assignedMu.RLock()
|
||||
key := AssignedKey{repoID}
|
||||
if v, ok := c.assigned[key]; ok {
|
||||
defer c.assignedMu.RUnlock()
|
||||
return v, nil
|
||||
}
|
||||
c.assignedMu.RUnlock()
|
||||
c.assignedMu.Lock()
|
||||
defer c.assignedMu.Unlock()
|
||||
if _, ok := c.assigned[key]; !ok {
|
||||
assigned, err := c.ownService.AssignedOwnership(ctx, repoID, commitID)
|
||||
if err != nil {
|
||||
// TODO: Consider error condition
|
||||
return nil, err
|
||||
}
|
||||
c.assigned[key] = assigned
|
||||
}
|
||||
return c.assigned[key], nil
|
||||
}
|
||||
|
||||
func (c *RulesCache) Codeowners(ctx context.Context, repoName api.RepoName, repoID api.RepoID, commitID api.CommitID) (*codeowners.Ruleset, error) {
|
||||
c.rulesMu.RLock()
|
||||
key := RulesKey{repoName, commitID}
|
||||
if _, ok := c.rules[key]; ok {
|
||||
defer c.mu.RUnlock()
|
||||
defer c.rulesMu.RUnlock()
|
||||
return c.rules[key], nil
|
||||
}
|
||||
c.mu.RUnlock()
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.rulesMu.RUnlock()
|
||||
c.rulesMu.Lock()
|
||||
defer c.rulesMu.Unlock()
|
||||
// Recheck condition.
|
||||
if _, ok := c.rules[key]; !ok {
|
||||
file, err := c.ownService.RulesetForRepo(ctx, repoName, repoID, commitID)
|
||||
@ -55,3 +98,51 @@ func (c *RulesCache) GetFromCacheOrFetch(ctx context.Context, repoName api.RepoN
|
||||
}
|
||||
return c.rules[key], nil
|
||||
}
|
||||
|
||||
type repoOwnershipData struct {
|
||||
codeowners *codeowners.Ruleset
|
||||
assigned own.AssignedOwners
|
||||
}
|
||||
|
||||
func (o repoOwnershipData) Match(path string) fileOwnershipData {
|
||||
var rule *codeownerspb.Rule
|
||||
if o.codeowners != nil {
|
||||
rule = o.codeowners.Match(path)
|
||||
}
|
||||
return fileOwnershipData{
|
||||
rule: rule,
|
||||
assignedOwners: o.assigned.Match(path),
|
||||
}
|
||||
}
|
||||
|
||||
type fileOwnershipData struct {
|
||||
rule *codeownerspb.Rule
|
||||
assignedOwners []database.AssignedOwnerSummary
|
||||
}
|
||||
|
||||
func (d fileOwnershipData) NonEmpty() bool {
|
||||
if d.rule != nil && len(d.rule.Owner) > 0 {
|
||||
return true
|
||||
}
|
||||
if len(d.assignedOwners) > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (d fileOwnershipData) Contains(bag own.Bag) bool {
|
||||
for _, o := range d.rule.GetOwner() {
|
||||
if bag.Contains(own.Reference{
|
||||
Handle: o.Handle,
|
||||
Email: o.Email,
|
||||
}) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, o := range d.assignedOwners {
|
||||
if bag.Contains(own.Reference{UserID: o.OwnerUserID}) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@ -115,7 +115,7 @@ func getCodeOwnersFromMatches(
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
rs, err := rules.GetFromCacheOrFetch(ctx, mm.Repo.Name, mm.Repo.ID, mm.CommitID)
|
||||
rs, err := rules.Codeowners(ctx, mm.Repo.Name, mm.Repo.ID, mm.CommitID)
|
||||
if err != nil {
|
||||
errs = errors.Append(errs, err)
|
||||
continue
|
||||
|
||||
@ -2811,6 +2811,425 @@ func (c AccessTokenStoreWithTransactFuncCall) Results() []interface{} {
|
||||
return []interface{}{c.Result0}
|
||||
}
|
||||
|
||||
// MockAssignedOwnersStore is a mock implementation of the
|
||||
// AssignedOwnersStore interface (from the package
|
||||
// github.com/sourcegraph/sourcegraph/internal/database) used for unit
|
||||
// testing.
|
||||
type MockAssignedOwnersStore struct {
|
||||
// DeleteOwnerFunc is an instance of a mock function object controlling
|
||||
// the behavior of the method DeleteOwner.
|
||||
DeleteOwnerFunc *AssignedOwnersStoreDeleteOwnerFunc
|
||||
// InsertFunc is an instance of a mock function object controlling the
|
||||
// behavior of the method Insert.
|
||||
InsertFunc *AssignedOwnersStoreInsertFunc
|
||||
// ListAssignedOwnersForRepoFunc is an instance of a mock function
|
||||
// object controlling the behavior of the method
|
||||
// ListAssignedOwnersForRepo.
|
||||
ListAssignedOwnersForRepoFunc *AssignedOwnersStoreListAssignedOwnersForRepoFunc
|
||||
}
|
||||
|
||||
// NewMockAssignedOwnersStore creates a new mock of the AssignedOwnersStore
|
||||
// interface. All methods return zero values for all results, unless
|
||||
// overwritten.
|
||||
func NewMockAssignedOwnersStore() *MockAssignedOwnersStore {
|
||||
return &MockAssignedOwnersStore{
|
||||
DeleteOwnerFunc: &AssignedOwnersStoreDeleteOwnerFunc{
|
||||
defaultHook: func(context.Context, int32, api.RepoID, string) (r0 error) {
|
||||
return
|
||||
},
|
||||
},
|
||||
InsertFunc: &AssignedOwnersStoreInsertFunc{
|
||||
defaultHook: func(context.Context, int32, api.RepoID, string, int32) (r0 error) {
|
||||
return
|
||||
},
|
||||
},
|
||||
ListAssignedOwnersForRepoFunc: &AssignedOwnersStoreListAssignedOwnersForRepoFunc{
|
||||
defaultHook: func(context.Context, api.RepoID) (r0 []*AssignedOwnerSummary, r1 error) {
|
||||
return
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewStrictMockAssignedOwnersStore creates a new mock of the
|
||||
// AssignedOwnersStore interface. All methods panic on invocation, unless
|
||||
// overwritten.
|
||||
func NewStrictMockAssignedOwnersStore() *MockAssignedOwnersStore {
|
||||
return &MockAssignedOwnersStore{
|
||||
DeleteOwnerFunc: &AssignedOwnersStoreDeleteOwnerFunc{
|
||||
defaultHook: func(context.Context, int32, api.RepoID, string) error {
|
||||
panic("unexpected invocation of MockAssignedOwnersStore.DeleteOwner")
|
||||
},
|
||||
},
|
||||
InsertFunc: &AssignedOwnersStoreInsertFunc{
|
||||
defaultHook: func(context.Context, int32, api.RepoID, string, int32) error {
|
||||
panic("unexpected invocation of MockAssignedOwnersStore.Insert")
|
||||
},
|
||||
},
|
||||
ListAssignedOwnersForRepoFunc: &AssignedOwnersStoreListAssignedOwnersForRepoFunc{
|
||||
defaultHook: func(context.Context, api.RepoID) ([]*AssignedOwnerSummary, error) {
|
||||
panic("unexpected invocation of MockAssignedOwnersStore.ListAssignedOwnersForRepo")
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewMockAssignedOwnersStoreFrom creates a new mock of the
|
||||
// MockAssignedOwnersStore interface. All methods delegate to the given
|
||||
// implementation, unless overwritten.
|
||||
func NewMockAssignedOwnersStoreFrom(i AssignedOwnersStore) *MockAssignedOwnersStore {
|
||||
return &MockAssignedOwnersStore{
|
||||
DeleteOwnerFunc: &AssignedOwnersStoreDeleteOwnerFunc{
|
||||
defaultHook: i.DeleteOwner,
|
||||
},
|
||||
InsertFunc: &AssignedOwnersStoreInsertFunc{
|
||||
defaultHook: i.Insert,
|
||||
},
|
||||
ListAssignedOwnersForRepoFunc: &AssignedOwnersStoreListAssignedOwnersForRepoFunc{
|
||||
defaultHook: i.ListAssignedOwnersForRepo,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// AssignedOwnersStoreDeleteOwnerFunc describes the behavior when the
|
||||
// DeleteOwner method of the parent MockAssignedOwnersStore instance is
|
||||
// invoked.
|
||||
type AssignedOwnersStoreDeleteOwnerFunc struct {
|
||||
defaultHook func(context.Context, int32, api.RepoID, string) error
|
||||
hooks []func(context.Context, int32, api.RepoID, string) error
|
||||
history []AssignedOwnersStoreDeleteOwnerFuncCall
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// DeleteOwner delegates to the next hook function in the queue and stores
|
||||
// the parameter and result values of this invocation.
|
||||
func (m *MockAssignedOwnersStore) DeleteOwner(v0 context.Context, v1 int32, v2 api.RepoID, v3 string) error {
|
||||
r0 := m.DeleteOwnerFunc.nextHook()(v0, v1, v2, v3)
|
||||
m.DeleteOwnerFunc.appendCall(AssignedOwnersStoreDeleteOwnerFuncCall{v0, v1, v2, v3, r0})
|
||||
return r0
|
||||
}
|
||||
|
||||
// SetDefaultHook sets function that is called when the DeleteOwner method
|
||||
// of the parent MockAssignedOwnersStore instance is invoked and the hook
|
||||
// queue is empty.
|
||||
func (f *AssignedOwnersStoreDeleteOwnerFunc) SetDefaultHook(hook func(context.Context, int32, api.RepoID, string) error) {
|
||||
f.defaultHook = hook
|
||||
}
|
||||
|
||||
// PushHook adds a function to the end of hook queue. Each invocation of the
|
||||
// DeleteOwner method of the parent MockAssignedOwnersStore instance invokes
|
||||
// the hook at the front of the queue and discards it. After the queue is
|
||||
// empty, the default hook function is invoked for any future action.
|
||||
func (f *AssignedOwnersStoreDeleteOwnerFunc) PushHook(hook func(context.Context, int32, api.RepoID, string) error) {
|
||||
f.mutex.Lock()
|
||||
f.hooks = append(f.hooks, hook)
|
||||
f.mutex.Unlock()
|
||||
}
|
||||
|
||||
// SetDefaultReturn calls SetDefaultHook with a function that returns the
|
||||
// given values.
|
||||
func (f *AssignedOwnersStoreDeleteOwnerFunc) SetDefaultReturn(r0 error) {
|
||||
f.SetDefaultHook(func(context.Context, int32, api.RepoID, string) error {
|
||||
return r0
|
||||
})
|
||||
}
|
||||
|
||||
// PushReturn calls PushHook with a function that returns the given values.
|
||||
func (f *AssignedOwnersStoreDeleteOwnerFunc) PushReturn(r0 error) {
|
||||
f.PushHook(func(context.Context, int32, api.RepoID, string) error {
|
||||
return r0
|
||||
})
|
||||
}
|
||||
|
||||
func (f *AssignedOwnersStoreDeleteOwnerFunc) nextHook() func(context.Context, int32, api.RepoID, string) error {
|
||||
f.mutex.Lock()
|
||||
defer f.mutex.Unlock()
|
||||
|
||||
if len(f.hooks) == 0 {
|
||||
return f.defaultHook
|
||||
}
|
||||
|
||||
hook := f.hooks[0]
|
||||
f.hooks = f.hooks[1:]
|
||||
return hook
|
||||
}
|
||||
|
||||
func (f *AssignedOwnersStoreDeleteOwnerFunc) appendCall(r0 AssignedOwnersStoreDeleteOwnerFuncCall) {
|
||||
f.mutex.Lock()
|
||||
f.history = append(f.history, r0)
|
||||
f.mutex.Unlock()
|
||||
}
|
||||
|
||||
// History returns a sequence of AssignedOwnersStoreDeleteOwnerFuncCall
|
||||
// objects describing the invocations of this function.
|
||||
func (f *AssignedOwnersStoreDeleteOwnerFunc) History() []AssignedOwnersStoreDeleteOwnerFuncCall {
|
||||
f.mutex.Lock()
|
||||
history := make([]AssignedOwnersStoreDeleteOwnerFuncCall, len(f.history))
|
||||
copy(history, f.history)
|
||||
f.mutex.Unlock()
|
||||
|
||||
return history
|
||||
}
|
||||
|
||||
// AssignedOwnersStoreDeleteOwnerFuncCall is an object that describes an
|
||||
// invocation of method DeleteOwner on an instance of
|
||||
// MockAssignedOwnersStore.
|
||||
type AssignedOwnersStoreDeleteOwnerFuncCall struct {
|
||||
// Arg0 is the value of the 1st argument passed to this method
|
||||
// invocation.
|
||||
Arg0 context.Context
|
||||
// Arg1 is the value of the 2nd argument passed to this method
|
||||
// invocation.
|
||||
Arg1 int32
|
||||
// Arg2 is the value of the 3rd argument passed to this method
|
||||
// invocation.
|
||||
Arg2 api.RepoID
|
||||
// Arg3 is the value of the 4th argument passed to this method
|
||||
// invocation.
|
||||
Arg3 string
|
||||
// Result0 is the value of the 1st result returned from this method
|
||||
// invocation.
|
||||
Result0 error
|
||||
}
|
||||
|
||||
// Args returns an interface slice containing the arguments of this
|
||||
// invocation.
|
||||
func (c AssignedOwnersStoreDeleteOwnerFuncCall) Args() []interface{} {
|
||||
return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3}
|
||||
}
|
||||
|
||||
// Results returns an interface slice containing the results of this
|
||||
// invocation.
|
||||
func (c AssignedOwnersStoreDeleteOwnerFuncCall) Results() []interface{} {
|
||||
return []interface{}{c.Result0}
|
||||
}
|
||||
|
||||
// AssignedOwnersStoreInsertFunc describes the behavior when the Insert
|
||||
// method of the parent MockAssignedOwnersStore instance is invoked.
|
||||
type AssignedOwnersStoreInsertFunc struct {
|
||||
defaultHook func(context.Context, int32, api.RepoID, string, int32) error
|
||||
hooks []func(context.Context, int32, api.RepoID, string, int32) error
|
||||
history []AssignedOwnersStoreInsertFuncCall
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// Insert delegates to the next hook function in the queue and stores the
|
||||
// parameter and result values of this invocation.
|
||||
func (m *MockAssignedOwnersStore) Insert(v0 context.Context, v1 int32, v2 api.RepoID, v3 string, v4 int32) error {
|
||||
r0 := m.InsertFunc.nextHook()(v0, v1, v2, v3, v4)
|
||||
m.InsertFunc.appendCall(AssignedOwnersStoreInsertFuncCall{v0, v1, v2, v3, v4, r0})
|
||||
return r0
|
||||
}
|
||||
|
||||
// SetDefaultHook sets function that is called when the Insert method of the
|
||||
// parent MockAssignedOwnersStore instance is invoked and the hook queue is
|
||||
// empty.
|
||||
func (f *AssignedOwnersStoreInsertFunc) SetDefaultHook(hook func(context.Context, int32, api.RepoID, string, int32) error) {
|
||||
f.defaultHook = hook
|
||||
}
|
||||
|
||||
// PushHook adds a function to the end of hook queue. Each invocation of the
|
||||
// Insert method of the parent MockAssignedOwnersStore instance invokes the
|
||||
// hook at the front of the queue and discards it. After the queue is empty,
|
||||
// the default hook function is invoked for any future action.
|
||||
func (f *AssignedOwnersStoreInsertFunc) PushHook(hook func(context.Context, int32, api.RepoID, string, int32) error) {
|
||||
f.mutex.Lock()
|
||||
f.hooks = append(f.hooks, hook)
|
||||
f.mutex.Unlock()
|
||||
}
|
||||
|
||||
// SetDefaultReturn calls SetDefaultHook with a function that returns the
|
||||
// given values.
|
||||
func (f *AssignedOwnersStoreInsertFunc) SetDefaultReturn(r0 error) {
|
||||
f.SetDefaultHook(func(context.Context, int32, api.RepoID, string, int32) error {
|
||||
return r0
|
||||
})
|
||||
}
|
||||
|
||||
// PushReturn calls PushHook with a function that returns the given values.
|
||||
func (f *AssignedOwnersStoreInsertFunc) PushReturn(r0 error) {
|
||||
f.PushHook(func(context.Context, int32, api.RepoID, string, int32) error {
|
||||
return r0
|
||||
})
|
||||
}
|
||||
|
||||
func (f *AssignedOwnersStoreInsertFunc) nextHook() func(context.Context, int32, api.RepoID, string, int32) error {
|
||||
f.mutex.Lock()
|
||||
defer f.mutex.Unlock()
|
||||
|
||||
if len(f.hooks) == 0 {
|
||||
return f.defaultHook
|
||||
}
|
||||
|
||||
hook := f.hooks[0]
|
||||
f.hooks = f.hooks[1:]
|
||||
return hook
|
||||
}
|
||||
|
||||
func (f *AssignedOwnersStoreInsertFunc) appendCall(r0 AssignedOwnersStoreInsertFuncCall) {
|
||||
f.mutex.Lock()
|
||||
f.history = append(f.history, r0)
|
||||
f.mutex.Unlock()
|
||||
}
|
||||
|
||||
// History returns a sequence of AssignedOwnersStoreInsertFuncCall objects
|
||||
// describing the invocations of this function.
|
||||
func (f *AssignedOwnersStoreInsertFunc) History() []AssignedOwnersStoreInsertFuncCall {
|
||||
f.mutex.Lock()
|
||||
history := make([]AssignedOwnersStoreInsertFuncCall, len(f.history))
|
||||
copy(history, f.history)
|
||||
f.mutex.Unlock()
|
||||
|
||||
return history
|
||||
}
|
||||
|
||||
// AssignedOwnersStoreInsertFuncCall is an object that describes an
|
||||
// invocation of method Insert on an instance of MockAssignedOwnersStore.
|
||||
type AssignedOwnersStoreInsertFuncCall struct {
|
||||
// Arg0 is the value of the 1st argument passed to this method
|
||||
// invocation.
|
||||
Arg0 context.Context
|
||||
// Arg1 is the value of the 2nd argument passed to this method
|
||||
// invocation.
|
||||
Arg1 int32
|
||||
// Arg2 is the value of the 3rd argument passed to this method
|
||||
// invocation.
|
||||
Arg2 api.RepoID
|
||||
// Arg3 is the value of the 4th argument passed to this method
|
||||
// invocation.
|
||||
Arg3 string
|
||||
// Arg4 is the value of the 5th argument passed to this method
|
||||
// invocation.
|
||||
Arg4 int32
|
||||
// Result0 is the value of the 1st result returned from this method
|
||||
// invocation.
|
||||
Result0 error
|
||||
}
|
||||
|
||||
// Args returns an interface slice containing the arguments of this
|
||||
// invocation.
|
||||
func (c AssignedOwnersStoreInsertFuncCall) Args() []interface{} {
|
||||
return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3, c.Arg4}
|
||||
}
|
||||
|
||||
// Results returns an interface slice containing the results of this
|
||||
// invocation.
|
||||
func (c AssignedOwnersStoreInsertFuncCall) Results() []interface{} {
|
||||
return []interface{}{c.Result0}
|
||||
}
|
||||
|
||||
// AssignedOwnersStoreListAssignedOwnersForRepoFunc describes the behavior
|
||||
// when the ListAssignedOwnersForRepo method of the parent
|
||||
// MockAssignedOwnersStore instance is invoked.
|
||||
type AssignedOwnersStoreListAssignedOwnersForRepoFunc struct {
|
||||
defaultHook func(context.Context, api.RepoID) ([]*AssignedOwnerSummary, error)
|
||||
hooks []func(context.Context, api.RepoID) ([]*AssignedOwnerSummary, error)
|
||||
history []AssignedOwnersStoreListAssignedOwnersForRepoFuncCall
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// ListAssignedOwnersForRepo delegates to the next hook function in the
|
||||
// queue and stores the parameter and result values of this invocation.
|
||||
func (m *MockAssignedOwnersStore) ListAssignedOwnersForRepo(v0 context.Context, v1 api.RepoID) ([]*AssignedOwnerSummary, error) {
|
||||
r0, r1 := m.ListAssignedOwnersForRepoFunc.nextHook()(v0, v1)
|
||||
m.ListAssignedOwnersForRepoFunc.appendCall(AssignedOwnersStoreListAssignedOwnersForRepoFuncCall{v0, v1, r0, r1})
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// SetDefaultHook sets function that is called when the
|
||||
// ListAssignedOwnersForRepo method of the parent MockAssignedOwnersStore
|
||||
// instance is invoked and the hook queue is empty.
|
||||
func (f *AssignedOwnersStoreListAssignedOwnersForRepoFunc) SetDefaultHook(hook func(context.Context, api.RepoID) ([]*AssignedOwnerSummary, error)) {
|
||||
f.defaultHook = hook
|
||||
}
|
||||
|
||||
// PushHook adds a function to the end of hook queue. Each invocation of the
|
||||
// ListAssignedOwnersForRepo method of the parent MockAssignedOwnersStore
|
||||
// instance invokes the hook at the front of the queue and discards it.
|
||||
// After the queue is empty, the default hook function is invoked for any
|
||||
// future action.
|
||||
func (f *AssignedOwnersStoreListAssignedOwnersForRepoFunc) PushHook(hook func(context.Context, api.RepoID) ([]*AssignedOwnerSummary, error)) {
|
||||
f.mutex.Lock()
|
||||
f.hooks = append(f.hooks, hook)
|
||||
f.mutex.Unlock()
|
||||
}
|
||||
|
||||
// SetDefaultReturn calls SetDefaultHook with a function that returns the
|
||||
// given values.
|
||||
func (f *AssignedOwnersStoreListAssignedOwnersForRepoFunc) SetDefaultReturn(r0 []*AssignedOwnerSummary, r1 error) {
|
||||
f.SetDefaultHook(func(context.Context, api.RepoID) ([]*AssignedOwnerSummary, error) {
|
||||
return r0, r1
|
||||
})
|
||||
}
|
||||
|
||||
// PushReturn calls PushHook with a function that returns the given values.
|
||||
func (f *AssignedOwnersStoreListAssignedOwnersForRepoFunc) PushReturn(r0 []*AssignedOwnerSummary, r1 error) {
|
||||
f.PushHook(func(context.Context, api.RepoID) ([]*AssignedOwnerSummary, error) {
|
||||
return r0, r1
|
||||
})
|
||||
}
|
||||
|
||||
func (f *AssignedOwnersStoreListAssignedOwnersForRepoFunc) nextHook() func(context.Context, api.RepoID) ([]*AssignedOwnerSummary, error) {
|
||||
f.mutex.Lock()
|
||||
defer f.mutex.Unlock()
|
||||
|
||||
if len(f.hooks) == 0 {
|
||||
return f.defaultHook
|
||||
}
|
||||
|
||||
hook := f.hooks[0]
|
||||
f.hooks = f.hooks[1:]
|
||||
return hook
|
||||
}
|
||||
|
||||
func (f *AssignedOwnersStoreListAssignedOwnersForRepoFunc) appendCall(r0 AssignedOwnersStoreListAssignedOwnersForRepoFuncCall) {
|
||||
f.mutex.Lock()
|
||||
f.history = append(f.history, r0)
|
||||
f.mutex.Unlock()
|
||||
}
|
||||
|
||||
// History returns a sequence of
|
||||
// AssignedOwnersStoreListAssignedOwnersForRepoFuncCall objects describing
|
||||
// the invocations of this function.
|
||||
func (f *AssignedOwnersStoreListAssignedOwnersForRepoFunc) History() []AssignedOwnersStoreListAssignedOwnersForRepoFuncCall {
|
||||
f.mutex.Lock()
|
||||
history := make([]AssignedOwnersStoreListAssignedOwnersForRepoFuncCall, len(f.history))
|
||||
copy(history, f.history)
|
||||
f.mutex.Unlock()
|
||||
|
||||
return history
|
||||
}
|
||||
|
||||
// AssignedOwnersStoreListAssignedOwnersForRepoFuncCall is an object that
|
||||
// describes an invocation of method ListAssignedOwnersForRepo on an
|
||||
// instance of MockAssignedOwnersStore.
|
||||
type AssignedOwnersStoreListAssignedOwnersForRepoFuncCall struct {
|
||||
// Arg0 is the value of the 1st argument passed to this method
|
||||
// invocation.
|
||||
Arg0 context.Context
|
||||
// Arg1 is the value of the 2nd argument passed to this method
|
||||
// invocation.
|
||||
Arg1 api.RepoID
|
||||
// Result0 is the value of the 1st result returned from this method
|
||||
// invocation.
|
||||
Result0 []*AssignedOwnerSummary
|
||||
// Result1 is the value of the 2nd result returned from this method
|
||||
// invocation.
|
||||
Result1 error
|
||||
}
|
||||
|
||||
// Args returns an interface slice containing the arguments of this
|
||||
// invocation.
|
||||
func (c AssignedOwnersStoreListAssignedOwnersForRepoFuncCall) Args() []interface{} {
|
||||
return []interface{}{c.Arg0, c.Arg1}
|
||||
}
|
||||
|
||||
// Results returns an interface slice containing the results of this
|
||||
// invocation.
|
||||
func (c AssignedOwnersStoreListAssignedOwnersForRepoFuncCall) Results() []interface{} {
|
||||
return []interface{}{c.Result0, c.Result1}
|
||||
}
|
||||
|
||||
// MockAuthzStore is a mock implementation of the AuthzStore interface (from
|
||||
// the package github.com/sourcegraph/sourcegraph/internal/database) used
|
||||
// for unit testing.
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
interfaces:
|
||||
- AccessRequestStore
|
||||
- AccessTokenStore
|
||||
- AssignedOwnersStore
|
||||
- AuthzStore
|
||||
- BitbucketProjectPermissionsStore
|
||||
- ConfStore
|
||||
|
||||
Loading…
Reference in New Issue
Block a user