Skip to content

Commit

Permalink
gitserver: grpc: add new ChangedFiles method to gitserver client
Browse files Browse the repository at this point in the history
  • Loading branch information
ggilmore committed May 7, 2024
1 parent 5f81856 commit a54db0c
Show file tree
Hide file tree
Showing 8 changed files with 727 additions and 6 deletions.
10 changes: 4 additions & 6 deletions cmd/gitserver/internal/server_grpc_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,15 @@ import (
"sync/atomic"
"time"

"google.golang.org/grpc/codes"

"github.com/sourcegraph/sourcegraph/cmd/gitserver/internal/urlredactor"
"github.com/sourcegraph/sourcegraph/internal/grpc/grpcutil"
"github.com/sourcegraph/sourcegraph/internal/vcs"

"github.com/sourcegraph/log"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

"github.com/sourcegraph/sourcegraph/cmd/gitserver/internal/urlredactor"
proto "github.com/sourcegraph/sourcegraph/internal/gitserver/v1"
"github.com/sourcegraph/sourcegraph/internal/grpc/grpcutil"
"github.com/sourcegraph/sourcegraph/internal/trace"
"github.com/sourcegraph/sourcegraph/internal/vcs"
)

// loggingGRPCServer is a wrapper around the provided GitserverServiceServer
Expand Down
131 changes: 131 additions & 0 deletions internal/batches/sources/mocks_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 66 additions & 0 deletions internal/gitserver/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io"
"io/fs"
"strings"
"sync"
"testing"
"time"

Expand Down Expand Up @@ -439,6 +440,14 @@ type Client interface {
// If the specified commit does not exist, a RevisionNotFoundError is returned.
NewFileReader(ctx context.Context, repo api.RepoName, commit api.CommitID, name string) (io.ReadCloser, error)

// ChangedFiles returns the list of files that have been added, modified, or
// deleted in the entire repository between the two given <tree-ish> identifiers (e.g., commit, branch, tag).
//
// If base is omitted, the parent of head is used as the base.
//
// If either the base or head <tree-ish> id does not exist, a gitdomain.RevisionNotFoundError is returned.
ChangedFiles(ctx context.Context, repo api.RepoName, base, head string) (ChangedFilesIterator, error)

// DiffSymbols performs a diff command which is expected to be parsed by our symbols package
DiffSymbols(ctx context.Context, repo api.RepoName, commitA, commitB api.CommitID) ([]byte, error)

Expand Down Expand Up @@ -1190,3 +1199,60 @@ func (c *clientImplementor) ListGitoliteRepos(ctx context.Context, gitoliteHost

return list, nil
}

// ChangedFilesIterator is an iterator for retrieving the status of changed files in a Git repository.
// It allows iterating over the changed files and retrieving their paths and statuses.
//
// The caller must ensure that they call Close() when the iterator is no longer needed to release any associated resources.
type ChangedFilesIterator interface {
// Next returns the next changed file's path and status.
//
// If there are no more changed files, Next returns an io.EOF error.
// If an error occurs during iteration, Next returns the error that occurred.
Next() (gitdomain.PathStatus, error)

// Close closes the iterator and releases any associated resources.
//
// It is important to call Close when the iterator is no longer needed to avoid resource leaks.
// After calling Close, any subsequent calls to Next will return an io.EOF error.
Close()
}

// NewChangedFilesIteratorFromSlice returns a new ChangedFilesIterator that iterates over the given slice of changed files (in order),
// which is useful for testing.
func NewChangedFilesIteratorFromSlice(files []gitdomain.PathStatus) ChangedFilesIterator {
return &changedFilesSliceIterator{files: files}
}

type changedFilesSliceIterator struct {
mu sync.Mutex
files []gitdomain.PathStatus
closed bool
}

func (c *changedFilesSliceIterator) Next() (gitdomain.PathStatus, error) {
c.mu.Lock()
defer c.mu.Unlock()

if c.closed {
return gitdomain.PathStatus{}, io.EOF
}

if len(c.files) == 0 {
return gitdomain.PathStatus{}, io.EOF
}

file := c.files[0]
c.files = c.files[1:]

return file, nil
}

func (c *changedFilesSliceIterator) Close() {
c.mu.Lock()
defer c.mu.Unlock()

c.closed = true
}

var _ ChangedFilesIterator = &changedFilesSliceIterator{}
47 changes: 47 additions & 0 deletions internal/gitserver/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package gitserver_test

import (
"context"
"io"
"math/rand"
"os/exec"
"path/filepath"
Expand All @@ -20,6 +21,7 @@ import (
"github.com/sourcegraph/sourcegraph/internal/api"
"github.com/sourcegraph/sourcegraph/internal/extsvc/gitolite"
"github.com/sourcegraph/sourcegraph/internal/gitserver"
"github.com/sourcegraph/sourcegraph/internal/gitserver/gitdomain"
"github.com/sourcegraph/sourcegraph/internal/gitserver/protocol"
proto "github.com/sourcegraph/sourcegraph/internal/gitserver/v1"
)
Expand Down Expand Up @@ -397,3 +399,48 @@ func (fuzzTime) Generate(rand *rand.Rand, _ int) reflect.Value {
}

var _ quick.Generator = fuzzTime{}

func TestNewChangedFilesIteratorFromSlice(t *testing.T) {
t.Run("IterateThroughFiles", func(t *testing.T) {
files := []gitdomain.PathStatus{
{Path: "file1.txt", Status: gitdomain.AddedAMD},
{Path: "file2.txt", Status: gitdomain.ModifiedAMD},
{Path: "file3.txt", Status: gitdomain.DeletedAMD},
}

iter := gitserver.NewChangedFilesIteratorFromSlice(files)
defer iter.Close()

for i := 0; i < len(files); i++ {
file, err := iter.Next()
require.NoError(t, err)
require.Equal(t, files[i], file)
}

_, err := iter.Next()
require.Equal(t, io.EOF, err)
})

t.Run("EmptySlice", func(t *testing.T) {
iter := gitserver.NewChangedFilesIteratorFromSlice(nil)
defer iter.Close()

_, err := iter.Next()
require.Equal(t, io.EOF, err)
})

t.Run("Close", func(t *testing.T) {
files := []gitdomain.PathStatus{
{Path: "file1.txt", Status: gitdomain.AddedAMD},
}

iter := gitserver.NewChangedFilesIteratorFromSlice(files)

// Close should be idempotent
iter.Close()
iter.Close()

_, err := iter.Next()
require.Equal(t, io.EOF, err)
})
}

0 comments on commit a54db0c

Please sign in to comment.