mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 19:21:50 +00:00
gitserver: Utilize Commits method for RevList (#62369)
This PR replaces the gitserver client method RevList by the Commits method. The Commits method can do the same, but it saves us from implementing and testing a second API. Also, the name RevList sounded very generic but it was super opinionated in the flags it uses, so it was really "ListCommitsForRockskip" but that is too application-specific so Commits is probably just as good. We'll learn a bunch about our API endpoints as we finish migrating them all, so we can do proper optimizations afterwards. Closes https://github.com/sourcegraph/sourcegraph/issues/62098 Test plan: Integration and unit test for rockskip are still passing.
This commit is contained in:
parent
186f4a212c
commit
75afb74586
@ -28,5 +28,12 @@ go_test(
|
||||
timeout = "short",
|
||||
srcs = ["client_test.go"],
|
||||
embed = [":gitserver"],
|
||||
deps = ["@com_github_google_go_cmp//cmp"],
|
||||
deps = [
|
||||
"//internal/api",
|
||||
"//internal/gitserver",
|
||||
"//internal/gitserver/gitdomain",
|
||||
"//internal/observation",
|
||||
"@com_github_google_go_cmp//cmp",
|
||||
"@com_github_stretchr_testify//require",
|
||||
],
|
||||
)
|
||||
|
||||
@ -108,7 +108,7 @@ func (c *gitserverClient) RevList(ctx context.Context, repo string, commit strin
|
||||
for {
|
||||
var commits []api.CommitID
|
||||
var err error
|
||||
commits, nextCursor, err = c.innerClient.RevList(ctx, api.RepoName(repo), nextCursor, revListPageSize)
|
||||
commits, nextCursor, err = c.paginatedRevList(ctx, api.RepoName(repo), nextCursor, revListPageSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -127,6 +127,31 @@ func (c *gitserverClient) RevList(ctx context.Context, repo string, commit strin
|
||||
}
|
||||
}
|
||||
|
||||
func (c *gitserverClient) paginatedRevList(ctx context.Context, repo api.RepoName, commit string, count int) ([]api.CommitID, string, error) {
|
||||
commits, err := c.innerClient.Commits(ctx, repo, gitserver.CommitsOptions{
|
||||
N: uint(count + 1),
|
||||
Range: commit,
|
||||
FirstParent: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
commitIDs := make([]api.CommitID, 0, count+1)
|
||||
|
||||
for _, commit := range commits {
|
||||
commitIDs = append(commitIDs, commit.ID)
|
||||
}
|
||||
|
||||
var nextCursor string
|
||||
if len(commitIDs) > count {
|
||||
nextCursor = string(commitIDs[len(commitIDs)-1])
|
||||
commitIDs = commitIDs[:count]
|
||||
}
|
||||
|
||||
return commitIDs, nextCursor, nil
|
||||
}
|
||||
|
||||
var NUL = []byte{0}
|
||||
|
||||
// parseGitDiffOutput parses the output of a git diff command, which consists
|
||||
|
||||
@ -1,9 +1,16 @@
|
||||
package gitserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/internal/api"
|
||||
"github.com/sourcegraph/sourcegraph/internal/gitserver"
|
||||
"github.com/sourcegraph/sourcegraph/internal/gitserver/gitdomain"
|
||||
"github.com/sourcegraph/sourcegraph/internal/observation"
|
||||
)
|
||||
|
||||
func TestParseGitDiffOutput(t *testing.T) {
|
||||
@ -66,3 +73,56 @@ func combineBytes(bss ...[]byte) (combined []byte) {
|
||||
|
||||
return combined
|
||||
}
|
||||
|
||||
func TestGitserverClient_PaginatedRevList(t *testing.T) {
|
||||
allCommits := []*gitdomain.Commit{
|
||||
{ID: "4ac04f2761285633cd35188c696a6e08de03c00c"},
|
||||
{ID: "e7d0b23cb4e2e975ad657b163793bc83926c21b2"},
|
||||
{ID: "a04652fa1998a0a7d2f2f77ecb7021de943d3aab"},
|
||||
}
|
||||
|
||||
allCommitIDs := []api.CommitID{}
|
||||
for _, c := range allCommits {
|
||||
allCommitIDs = append(allCommitIDs, c.ID)
|
||||
}
|
||||
|
||||
t.Run("returns commits in reverse chronological order", func(t *testing.T) {
|
||||
inner := gitserver.NewMockClient()
|
||||
inner.CommitsFunc.SetDefaultReturn(allCommits, nil)
|
||||
client := &gitserverClient{
|
||||
innerClient: inner,
|
||||
operations: newOperations(&observation.TestContext),
|
||||
}
|
||||
commits, _, err := client.paginatedRevList(context.Background(), "repo", "HEAD", 999)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, allCommitIDs, commits)
|
||||
})
|
||||
|
||||
t.Run("returns next cursor when more commits exist", func(t *testing.T) {
|
||||
inner := gitserver.NewMockClient()
|
||||
for i := range allCommits {
|
||||
if len(allCommits) > i+1 {
|
||||
inner.CommitsFunc.PushReturn(allCommits[i:i+2], nil)
|
||||
} else {
|
||||
inner.CommitsFunc.PushReturn(allCommits[i:i+1], nil)
|
||||
}
|
||||
}
|
||||
client := &gitserverClient{
|
||||
innerClient: inner,
|
||||
operations: newOperations(&observation.TestContext),
|
||||
}
|
||||
|
||||
nextCursor := "HEAD"
|
||||
haveCommits := []api.CommitID{}
|
||||
for {
|
||||
commits, next, err := client.paginatedRevList(context.Background(), "repo", nextCursor, 1)
|
||||
require.NoError(t, err)
|
||||
nextCursor = next
|
||||
haveCommits = append(haveCommits, commits...)
|
||||
if nextCursor == "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
require.Equal(t, allCommitIDs, haveCommits)
|
||||
})
|
||||
}
|
||||
|
||||
133
internal/batches/sources/mocks_test.go
generated
133
internal/batches/sources/mocks_test.go
generated
@ -11085,9 +11085,6 @@ type MockGitserverClient struct {
|
||||
// RevAtTimeFunc is an instance of a mock function object controlling
|
||||
// the behavior of the method RevAtTime.
|
||||
RevAtTimeFunc *GitserverClientRevAtTimeFunc
|
||||
// RevListFunc is an instance of a mock function object controlling the
|
||||
// behavior of the method RevList.
|
||||
RevListFunc *GitserverClientRevListFunc
|
||||
// ScopedFunc is an instance of a mock function object controlling the
|
||||
// behavior of the method Scoped.
|
||||
ScopedFunc *GitserverClientScopedFunc
|
||||
@ -11287,11 +11284,6 @@ func NewMockGitserverClient() *MockGitserverClient {
|
||||
return
|
||||
},
|
||||
},
|
||||
RevListFunc: &GitserverClientRevListFunc{
|
||||
defaultHook: func(context.Context, api.RepoName, string, int) (r0 []api.CommitID, r1 string, r2 error) {
|
||||
return
|
||||
},
|
||||
},
|
||||
ScopedFunc: &GitserverClientScopedFunc{
|
||||
defaultHook: func(string) (r0 gitserver.Client) {
|
||||
return
|
||||
@ -11504,11 +11496,6 @@ func NewStrictMockGitserverClient() *MockGitserverClient {
|
||||
panic("unexpected invocation of MockGitserverClient.RevAtTime")
|
||||
},
|
||||
},
|
||||
RevListFunc: &GitserverClientRevListFunc{
|
||||
defaultHook: func(context.Context, api.RepoName, string, int) ([]api.CommitID, string, error) {
|
||||
panic("unexpected invocation of MockGitserverClient.RevList")
|
||||
},
|
||||
},
|
||||
ScopedFunc: &GitserverClientScopedFunc{
|
||||
defaultHook: func(string) gitserver.Client {
|
||||
panic("unexpected invocation of MockGitserverClient.Scoped")
|
||||
@ -11652,9 +11639,6 @@ func NewMockGitserverClientFrom(i gitserver.Client) *MockGitserverClient {
|
||||
RevAtTimeFunc: &GitserverClientRevAtTimeFunc{
|
||||
defaultHook: i.RevAtTime,
|
||||
},
|
||||
RevListFunc: &GitserverClientRevListFunc{
|
||||
defaultHook: i.RevList,
|
||||
},
|
||||
ScopedFunc: &GitserverClientScopedFunc{
|
||||
defaultHook: i.Scoped,
|
||||
},
|
||||
@ -15637,123 +15621,6 @@ func (c GitserverClientRevAtTimeFuncCall) Results() []interface{} {
|
||||
return []interface{}{c.Result0, c.Result1, c.Result2}
|
||||
}
|
||||
|
||||
// GitserverClientRevListFunc describes the behavior when the RevList method
|
||||
// of the parent MockGitserverClient instance is invoked.
|
||||
type GitserverClientRevListFunc struct {
|
||||
defaultHook func(context.Context, api.RepoName, string, int) ([]api.CommitID, string, error)
|
||||
hooks []func(context.Context, api.RepoName, string, int) ([]api.CommitID, string, error)
|
||||
history []GitserverClientRevListFuncCall
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// RevList delegates to the next hook function in the queue and stores the
|
||||
// parameter and result values of this invocation.
|
||||
func (m *MockGitserverClient) RevList(v0 context.Context, v1 api.RepoName, v2 string, v3 int) ([]api.CommitID, string, error) {
|
||||
r0, r1, r2 := m.RevListFunc.nextHook()(v0, v1, v2, v3)
|
||||
m.RevListFunc.appendCall(GitserverClientRevListFuncCall{v0, v1, v2, v3, r0, r1, r2})
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// SetDefaultHook sets function that is called when the RevList method of
|
||||
// the parent MockGitserverClient instance is invoked and the hook queue is
|
||||
// empty.
|
||||
func (f *GitserverClientRevListFunc) SetDefaultHook(hook func(context.Context, api.RepoName, string, int) ([]api.CommitID, string, error)) {
|
||||
f.defaultHook = hook
|
||||
}
|
||||
|
||||
// PushHook adds a function to the end of hook queue. Each invocation of the
|
||||
// RevList method of the parent MockGitserverClient 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 *GitserverClientRevListFunc) PushHook(hook func(context.Context, api.RepoName, string, int) ([]api.CommitID, 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 *GitserverClientRevListFunc) SetDefaultReturn(r0 []api.CommitID, r1 string, r2 error) {
|
||||
f.SetDefaultHook(func(context.Context, api.RepoName, string, int) ([]api.CommitID, string, error) {
|
||||
return r0, r1, r2
|
||||
})
|
||||
}
|
||||
|
||||
// PushReturn calls PushHook with a function that returns the given values.
|
||||
func (f *GitserverClientRevListFunc) PushReturn(r0 []api.CommitID, r1 string, r2 error) {
|
||||
f.PushHook(func(context.Context, api.RepoName, string, int) ([]api.CommitID, string, error) {
|
||||
return r0, r1, r2
|
||||
})
|
||||
}
|
||||
|
||||
func (f *GitserverClientRevListFunc) nextHook() func(context.Context, api.RepoName, string, int) ([]api.CommitID, 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 *GitserverClientRevListFunc) appendCall(r0 GitserverClientRevListFuncCall) {
|
||||
f.mutex.Lock()
|
||||
f.history = append(f.history, r0)
|
||||
f.mutex.Unlock()
|
||||
}
|
||||
|
||||
// History returns a sequence of GitserverClientRevListFuncCall objects
|
||||
// describing the invocations of this function.
|
||||
func (f *GitserverClientRevListFunc) History() []GitserverClientRevListFuncCall {
|
||||
f.mutex.Lock()
|
||||
history := make([]GitserverClientRevListFuncCall, len(f.history))
|
||||
copy(history, f.history)
|
||||
f.mutex.Unlock()
|
||||
|
||||
return history
|
||||
}
|
||||
|
||||
// GitserverClientRevListFuncCall is an object that describes an invocation
|
||||
// of method RevList on an instance of MockGitserverClient.
|
||||
type GitserverClientRevListFuncCall 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.RepoName
|
||||
// Arg2 is the value of the 3rd argument passed to this method
|
||||
// invocation.
|
||||
Arg2 string
|
||||
// Arg3 is the value of the 4th argument passed to this method
|
||||
// invocation.
|
||||
Arg3 int
|
||||
// Result0 is the value of the 1st result returned from this method
|
||||
// invocation.
|
||||
Result0 []api.CommitID
|
||||
// Result1 is the value of the 2nd result returned from this method
|
||||
// invocation.
|
||||
Result1 string
|
||||
// Result2 is the value of the 3rd result returned from this method
|
||||
// invocation.
|
||||
Result2 error
|
||||
}
|
||||
|
||||
// Args returns an interface slice containing the arguments of this
|
||||
// invocation.
|
||||
func (c GitserverClientRevListFuncCall) 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 GitserverClientRevListFuncCall) Results() []interface{} {
|
||||
return []interface{}{c.Result0, c.Result1, c.Result2}
|
||||
}
|
||||
|
||||
// GitserverClientScopedFunc describes the behavior when the Scoped method
|
||||
// of the parent MockGitserverClient instance is invoked.
|
||||
type GitserverClientScopedFunc struct {
|
||||
|
||||
@ -23,7 +23,6 @@ go_library(
|
||||
"//internal/actor",
|
||||
"//internal/api",
|
||||
"//internal/authz",
|
||||
"//internal/byteutils",
|
||||
"//internal/conf",
|
||||
"//internal/conf/conftypes",
|
||||
"//internal/extsvc/gitolite",
|
||||
|
||||
@ -488,11 +488,6 @@ type Client interface {
|
||||
// LogReverseEach runs git log in reverse order and calls the given callback for each entry.
|
||||
LogReverseEach(ctx context.Context, repo string, commit string, n int, onLogEntry func(entry gitdomain.LogEntry) error) error
|
||||
|
||||
// RevList makes a git rev-list call and returns up to count commits. if nextCursor
|
||||
// is non-empty, it is used as the starting point for the next call, use it to iterate
|
||||
// to iterate over the whole history.
|
||||
RevList(ctx context.Context, repo api.RepoName, commit string, count int) (_ []api.CommitID, nextCursor string, err error)
|
||||
|
||||
// SystemsInfo returns information about all gitserver instances associated with a Sourcegraph instance.
|
||||
SystemsInfo(ctx context.Context) ([]protocol.SystemInfo, error)
|
||||
|
||||
|
||||
@ -28,7 +28,6 @@ import (
|
||||
"github.com/sourcegraph/sourcegraph/internal/actor"
|
||||
"github.com/sourcegraph/sourcegraph/internal/api"
|
||||
"github.com/sourcegraph/sourcegraph/internal/authz"
|
||||
"github.com/sourcegraph/sourcegraph/internal/byteutils"
|
||||
"github.com/sourcegraph/sourcegraph/internal/fileutil"
|
||||
"github.com/sourcegraph/sourcegraph/internal/gitserver/gitdomain"
|
||||
proto "github.com/sourcegraph/sourcegraph/internal/gitserver/v1"
|
||||
@ -1063,53 +1062,6 @@ func (c *clientImplementor) MergeBase(ctx context.Context, repo api.RepoName, ba
|
||||
return api.CommitID(res.GetMergeBaseCommitSha()), nil
|
||||
}
|
||||
|
||||
func (c *clientImplementor) RevList(ctx context.Context, repo api.RepoName, commit string, count int) (_ []api.CommitID, nextCursor string, err error) {
|
||||
ctx, _, endObservation := c.operations.revList.With(ctx, &err, observation.Args{
|
||||
MetricLabelValues: []string{c.scope},
|
||||
Attrs: []attribute.KeyValue{
|
||||
repo.Attr(),
|
||||
attribute.String("commit", commit),
|
||||
},
|
||||
})
|
||||
defer endObservation(1, observation.Args{})
|
||||
|
||||
command := c.gitCommand(repo, revListArgs(count, commit)...)
|
||||
|
||||
stdout, err := command.Output(ctx)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
commits := make([]api.CommitID, 0, count+1)
|
||||
|
||||
lr := byteutils.NewLineReader(stdout)
|
||||
for lr.Scan() {
|
||||
line := lr.Line()
|
||||
line = bytes.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
commit := api.CommitID(line)
|
||||
commits = append(commits, commit)
|
||||
}
|
||||
|
||||
if len(commits) > count {
|
||||
nextCursor = string(commits[len(commits)-1])
|
||||
commits = commits[:count]
|
||||
}
|
||||
|
||||
return commits, nextCursor, nil
|
||||
}
|
||||
|
||||
func revListArgs(count int, givenCommit string) []string {
|
||||
return []string{
|
||||
"rev-list",
|
||||
"--first-parent",
|
||||
fmt.Sprintf("--max-count=%d", count+1),
|
||||
givenCommit,
|
||||
}
|
||||
}
|
||||
|
||||
// BehindAhead returns the behind/ahead commit counts information for right vs. left (both Git
|
||||
// revspecs).
|
||||
func (c *clientImplementor) BehindAhead(ctx context.Context, repo api.RepoName, left, right string) (_ *gitdomain.BehindAhead, err error) {
|
||||
@ -1307,6 +1259,14 @@ type CommitsOptions struct {
|
||||
|
||||
Follow bool // follow the history of the path beyond renames (works only for a single path)
|
||||
|
||||
// When finding commits to include, follow only the first parent commit upon
|
||||
// seeing a merge commit. This option can give a better overview when viewing
|
||||
// the evolution of a particular topic branch, because merges into a topic
|
||||
// branch tend to be only about adjusting to updated upstream from time to time,
|
||||
// and this option allows you to ignore the individual commits brought in to
|
||||
// your history by such a merge.
|
||||
FirstParent bool
|
||||
|
||||
// When true return the names of the files changed in the commit
|
||||
NameOnly bool
|
||||
}
|
||||
@ -1747,6 +1707,10 @@ func commitLogArgs(initialArgs []string, opt CommitsOptions) (args []string, err
|
||||
args = append(args, "--fixed-strings", "--regexp-ignore-case", "--grep="+opt.MessageQuery)
|
||||
}
|
||||
|
||||
if opt.FirstParent {
|
||||
args = append(args, "--first-parent")
|
||||
}
|
||||
|
||||
if opt.Range != "" {
|
||||
args = append(args, opt.Range)
|
||||
}
|
||||
|
||||
@ -2324,57 +2324,3 @@ func TestClient_GetBehindAhead(t *testing.T) {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestRevList(t *testing.T) {
|
||||
ClientMocks.LocalGitserver = true
|
||||
defer ResetClientMocks()
|
||||
|
||||
gitCommands := []string{
|
||||
"git commit --allow-empty -m commit1",
|
||||
"git commit --allow-empty -m commit2",
|
||||
"git commit --allow-empty -m commit3",
|
||||
}
|
||||
repo := MakeGitRepository(t, gitCommands...)
|
||||
allCommits := []api.CommitID{
|
||||
"4ac04f2761285633cd35188c696a6e08de03c00c",
|
||||
"e7d0b23cb4e2e975ad657b163793bc83926c21b2",
|
||||
"a04652fa1998a0a7d2f2f77ecb7021de943d3aab",
|
||||
}
|
||||
|
||||
t.Run("returns commits in reverse chronological order", func(t *testing.T) {
|
||||
client := NewTestClient(t)
|
||||
commits, _, err := client.RevList(context.Background(), repo, "HEAD", 999)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, allCommits, commits)
|
||||
})
|
||||
|
||||
t.Run("returns next cursor when more commits exist", func(t *testing.T) {
|
||||
gitCommands := []string{
|
||||
"git commit --allow-empty -m commit1",
|
||||
"git commit --allow-empty -m commit2",
|
||||
"git commit --allow-empty -m commit3",
|
||||
}
|
||||
repo := MakeGitRepository(t, gitCommands...)
|
||||
client := NewTestClient(t)
|
||||
nextCursor := "HEAD"
|
||||
haveCommits := []api.CommitID{}
|
||||
for {
|
||||
commits, next, err := client.RevList(context.Background(), repo, nextCursor, 1)
|
||||
require.NoError(t, err)
|
||||
nextCursor = next
|
||||
haveCommits = append(haveCommits, commits...)
|
||||
if nextCursor == "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
require.Equal(t, allCommits, haveCommits)
|
||||
})
|
||||
|
||||
t.Run("returns error when commit does not exist", func(t *testing.T) {
|
||||
repo := MakeGitRepository(t)
|
||||
client := NewTestClient(t)
|
||||
_, _, err := client.RevList(context.Background(), repo, "nonexistent", 10)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "exit status 128")
|
||||
})
|
||||
}
|
||||
|
||||
@ -129,9 +129,6 @@ type MockClient struct {
|
||||
// RevAtTimeFunc is an instance of a mock function object controlling
|
||||
// the behavior of the method RevAtTime.
|
||||
RevAtTimeFunc *ClientRevAtTimeFunc
|
||||
// RevListFunc is an instance of a mock function object controlling the
|
||||
// behavior of the method RevList.
|
||||
RevListFunc *ClientRevListFunc
|
||||
// ScopedFunc is an instance of a mock function object controlling the
|
||||
// behavior of the method Scoped.
|
||||
ScopedFunc *ClientScopedFunc
|
||||
@ -331,11 +328,6 @@ func NewMockClient() *MockClient {
|
||||
return
|
||||
},
|
||||
},
|
||||
RevListFunc: &ClientRevListFunc{
|
||||
defaultHook: func(context.Context, api.RepoName, string, int) (r0 []api.CommitID, r1 string, r2 error) {
|
||||
return
|
||||
},
|
||||
},
|
||||
ScopedFunc: &ClientScopedFunc{
|
||||
defaultHook: func(string) (r0 Client) {
|
||||
return
|
||||
@ -548,11 +540,6 @@ func NewStrictMockClient() *MockClient {
|
||||
panic("unexpected invocation of MockClient.RevAtTime")
|
||||
},
|
||||
},
|
||||
RevListFunc: &ClientRevListFunc{
|
||||
defaultHook: func(context.Context, api.RepoName, string, int) ([]api.CommitID, string, error) {
|
||||
panic("unexpected invocation of MockClient.RevList")
|
||||
},
|
||||
},
|
||||
ScopedFunc: &ClientScopedFunc{
|
||||
defaultHook: func(string) Client {
|
||||
panic("unexpected invocation of MockClient.Scoped")
|
||||
@ -695,9 +682,6 @@ func NewMockClientFrom(i Client) *MockClient {
|
||||
RevAtTimeFunc: &ClientRevAtTimeFunc{
|
||||
defaultHook: i.RevAtTime,
|
||||
},
|
||||
RevListFunc: &ClientRevListFunc{
|
||||
defaultHook: i.RevList,
|
||||
},
|
||||
ScopedFunc: &ClientScopedFunc{
|
||||
defaultHook: i.Scoped,
|
||||
},
|
||||
@ -4613,122 +4597,6 @@ func (c ClientRevAtTimeFuncCall) Results() []interface{} {
|
||||
return []interface{}{c.Result0, c.Result1, c.Result2}
|
||||
}
|
||||
|
||||
// ClientRevListFunc describes the behavior when the RevList method of the
|
||||
// parent MockClient instance is invoked.
|
||||
type ClientRevListFunc struct {
|
||||
defaultHook func(context.Context, api.RepoName, string, int) ([]api.CommitID, string, error)
|
||||
hooks []func(context.Context, api.RepoName, string, int) ([]api.CommitID, string, error)
|
||||
history []ClientRevListFuncCall
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// RevList delegates to the next hook function in the queue and stores the
|
||||
// parameter and result values of this invocation.
|
||||
func (m *MockClient) RevList(v0 context.Context, v1 api.RepoName, v2 string, v3 int) ([]api.CommitID, string, error) {
|
||||
r0, r1, r2 := m.RevListFunc.nextHook()(v0, v1, v2, v3)
|
||||
m.RevListFunc.appendCall(ClientRevListFuncCall{v0, v1, v2, v3, r0, r1, r2})
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// SetDefaultHook sets function that is called when the RevList method of
|
||||
// the parent MockClient instance is invoked and the hook queue is empty.
|
||||
func (f *ClientRevListFunc) SetDefaultHook(hook func(context.Context, api.RepoName, string, int) ([]api.CommitID, string, error)) {
|
||||
f.defaultHook = hook
|
||||
}
|
||||
|
||||
// PushHook adds a function to the end of hook queue. Each invocation of the
|
||||
// RevList method of the parent MockClient 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 *ClientRevListFunc) PushHook(hook func(context.Context, api.RepoName, string, int) ([]api.CommitID, 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 *ClientRevListFunc) SetDefaultReturn(r0 []api.CommitID, r1 string, r2 error) {
|
||||
f.SetDefaultHook(func(context.Context, api.RepoName, string, int) ([]api.CommitID, string, error) {
|
||||
return r0, r1, r2
|
||||
})
|
||||
}
|
||||
|
||||
// PushReturn calls PushHook with a function that returns the given values.
|
||||
func (f *ClientRevListFunc) PushReturn(r0 []api.CommitID, r1 string, r2 error) {
|
||||
f.PushHook(func(context.Context, api.RepoName, string, int) ([]api.CommitID, string, error) {
|
||||
return r0, r1, r2
|
||||
})
|
||||
}
|
||||
|
||||
func (f *ClientRevListFunc) nextHook() func(context.Context, api.RepoName, string, int) ([]api.CommitID, 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 *ClientRevListFunc) appendCall(r0 ClientRevListFuncCall) {
|
||||
f.mutex.Lock()
|
||||
f.history = append(f.history, r0)
|
||||
f.mutex.Unlock()
|
||||
}
|
||||
|
||||
// History returns a sequence of ClientRevListFuncCall objects describing
|
||||
// the invocations of this function.
|
||||
func (f *ClientRevListFunc) History() []ClientRevListFuncCall {
|
||||
f.mutex.Lock()
|
||||
history := make([]ClientRevListFuncCall, len(f.history))
|
||||
copy(history, f.history)
|
||||
f.mutex.Unlock()
|
||||
|
||||
return history
|
||||
}
|
||||
|
||||
// ClientRevListFuncCall is an object that describes an invocation of method
|
||||
// RevList on an instance of MockClient.
|
||||
type ClientRevListFuncCall 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.RepoName
|
||||
// Arg2 is the value of the 3rd argument passed to this method
|
||||
// invocation.
|
||||
Arg2 string
|
||||
// Arg3 is the value of the 4th argument passed to this method
|
||||
// invocation.
|
||||
Arg3 int
|
||||
// Result0 is the value of the 1st result returned from this method
|
||||
// invocation.
|
||||
Result0 []api.CommitID
|
||||
// Result1 is the value of the 2nd result returned from this method
|
||||
// invocation.
|
||||
Result1 string
|
||||
// Result2 is the value of the 3rd result returned from this method
|
||||
// invocation.
|
||||
Result2 error
|
||||
}
|
||||
|
||||
// Args returns an interface slice containing the arguments of this
|
||||
// invocation.
|
||||
func (c ClientRevListFuncCall) 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 ClientRevListFuncCall) Results() []interface{} {
|
||||
return []interface{}{c.Result0, c.Result1, c.Result2}
|
||||
}
|
||||
|
||||
// ClientScopedFunc describes the behavior when the Scoped method of the
|
||||
// parent MockClient instance is invoked.
|
||||
type ClientScopedFunc struct {
|
||||
|
||||
@ -28,7 +28,6 @@ type operations struct {
|
||||
readDir *observation.Operation
|
||||
resolveRevision *observation.Operation
|
||||
revAtTime *observation.Operation
|
||||
revList *observation.Operation
|
||||
search *observation.Operation
|
||||
stat *observation.Operation
|
||||
streamBlameFile *observation.Operation
|
||||
@ -117,7 +116,6 @@ func newOperations(observationCtx *observation.Context) *operations {
|
||||
readDir: op("ReadDir"),
|
||||
resolveRevision: resolveRevisionOperation,
|
||||
revAtTime: op("RevAtTime"),
|
||||
revList: op("RevList"),
|
||||
search: op("Search"),
|
||||
stat: op("Stat"),
|
||||
streamBlameFile: op("StreamBlameFile"),
|
||||
|
||||
@ -246,7 +246,7 @@ func (g *SubprocessGit) RevList(ctx context.Context, repo string, commit string,
|
||||
for {
|
||||
var commits []api.CommitID
|
||||
var err error
|
||||
commits, nextCursor, err = g.gs.RevList(ctx, api.RepoName(repo), nextCursor, 100)
|
||||
commits, nextCursor, err = g.paginatedRevList(ctx, api.RepoName(repo), nextCursor, 100)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -265,6 +265,30 @@ func (g *SubprocessGit) RevList(ctx context.Context, repo string, commit string,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *SubprocessGit) paginatedRevList(ctx context.Context, repo api.RepoName, commit string, count int) (_ []api.CommitID, nextCursor string, _ error) {
|
||||
commits, err := g.gs.Commits(ctx, repo, gitserver.CommitsOptions{
|
||||
N: uint(count + 1),
|
||||
Range: commit,
|
||||
FirstParent: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
commitIDs := make([]api.CommitID, 0, count+1)
|
||||
|
||||
for _, commit := range commits {
|
||||
commitIDs = append(commitIDs, commit.ID)
|
||||
}
|
||||
|
||||
if len(commitIDs) > count {
|
||||
nextCursor = string(commitIDs[len(commitIDs)-1])
|
||||
commitIDs = commitIDs[:count]
|
||||
}
|
||||
|
||||
return commitIDs, nextCursor, nil
|
||||
}
|
||||
|
||||
func newMockRepositoryFetcher(git *SubprocessGit) fetcher.RepositoryFetcher {
|
||||
return &mockRepositoryFetcher{git: git}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user