Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Leopard <mleopard@gitlab.com>2019-04-10 15:15:13 +0300
committerJacob Vosmaer <jacob@gitlab.com>2019-04-10 15:15:13 +0300
commit14c69d1950a82893ac1baed25686d9a0c8170386 (patch)
tree2cb80c6cda8ee206c4c16f3f88759f29d160c131
parentb97345604f05c9d983da00b3caf573c9ed49689f (diff)
Implement ListRemotes
-rw-r--r--changelogs/unreleased/list-git-remotes.yml5
-rw-r--r--internal/service/remote/list_remotes.go9
-rw-r--r--internal/service/remote/remotes.go80
-rw-r--r--internal/service/remote/remotes_test.go149
4 files changed, 233 insertions, 10 deletions
diff --git a/changelogs/unreleased/list-git-remotes.yml b/changelogs/unreleased/list-git-remotes.yml
new file mode 100644
index 000000000..60d5c9d2a
--- /dev/null
+++ b/changelogs/unreleased/list-git-remotes.yml
@@ -0,0 +1,5 @@
+---
+title: Implement ListRemotes
+merge_request: 1019
+author:
+type: added
diff --git a/internal/service/remote/list_remotes.go b/internal/service/remote/list_remotes.go
deleted file mode 100644
index 8e4119cd9..000000000
--- a/internal/service/remote/list_remotes.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package remote
-
-import (
- "gitlab.com/gitlab-org/gitaly-proto/go/gitalypb"
-)
-
-func (s *server) ListRemotes(*gitalypb.ListRemotesRequest, gitalypb.RemoteService_ListRemotesServer) error {
- return nil
-}
diff --git a/internal/service/remote/remotes.go b/internal/service/remote/remotes.go
index ea77c2030..f680a3492 100644
--- a/internal/service/remote/remotes.go
+++ b/internal/service/remote/remotes.go
@@ -1,17 +1,19 @@
package remote
import (
+ "bufio"
"bytes"
"context"
"fmt"
"io/ioutil"
"strings"
+ "gitlab.com/gitlab-org/gitaly/internal/git/remote"
"gitlab.com/gitlab-org/gitaly/internal/rubyserver"
"gitlab.com/gitlab-org/gitaly-proto/go/gitalypb"
"gitlab.com/gitlab-org/gitaly/internal/git"
- "gitlab.com/gitlab-org/gitaly/internal/git/remote"
+ "gitlab.com/gitlab-org/gitaly/internal/helper/chunk"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@@ -102,3 +104,79 @@ func validateRemoveRemoteRequest(req *gitalypb.RemoveRemoteRequest) error {
return nil
}
+
+func (s *server) ListRemotes(req *gitalypb.ListRemotesRequest, stream gitalypb.RemoteService_ListRemotesServer) error {
+ repo := req.GetRepository()
+
+ ctx := stream.Context()
+ cmd, err := git.Command(ctx, repo, "remote", "-v")
+ if err != nil {
+ return err
+ }
+
+ scanner := bufio.NewScanner(cmd)
+ remotesMap := make(map[string]*gitalypb.ListRemotesResponse_Remote)
+
+ for scanner.Scan() {
+ text := scanner.Text()
+ splitLine := strings.Fields(text)
+ if len(splitLine) != 3 {
+ continue
+ }
+
+ remote := &gitalypb.ListRemotesResponse_Remote{Name: splitLine[0]}
+ if splitLine[2] == "(fetch)" {
+ remote.FetchUrl = splitLine[1]
+ } else if splitLine[2] == "(push)" {
+ remote.PushUrl = splitLine[1]
+ }
+
+ oldRemote := remotesMap[splitLine[0]]
+ remotesMap[splitLine[0]] = mergeGitalyRemote(oldRemote, remote)
+ }
+
+ sender := chunk.New(&listRemotesSender{stream: stream})
+ for _, remote := range remotesMap {
+ if err := sender.Send(remote); err != nil {
+ return err
+ }
+ }
+
+ return sender.Flush()
+}
+
+func mergeGitalyRemote(oldRemote *gitalypb.ListRemotesResponse_Remote, newRemote *gitalypb.ListRemotesResponse_Remote) *gitalypb.ListRemotesResponse_Remote {
+ if oldRemote == nil {
+ return &gitalypb.ListRemotesResponse_Remote{Name: newRemote.Name, FetchUrl: newRemote.FetchUrl, PushUrl: newRemote.PushUrl}
+ }
+
+ newRemoteInstance := &gitalypb.ListRemotesResponse_Remote{Name: oldRemote.Name, FetchUrl: oldRemote.FetchUrl, PushUrl: oldRemote.PushUrl}
+ if newRemote.Name != "" {
+ newRemoteInstance.Name = newRemote.Name
+ }
+
+ if newRemote.PushUrl != "" {
+ newRemoteInstance.PushUrl = newRemote.PushUrl
+ }
+
+ if newRemote.FetchUrl != "" {
+ newRemoteInstance.FetchUrl = newRemote.PushUrl
+ }
+
+ return newRemoteInstance
+}
+
+type listRemotesSender struct {
+ stream gitalypb.RemoteService_ListRemotesServer
+ remotes []*gitalypb.ListRemotesResponse_Remote
+}
+
+func (l *listRemotesSender) Append(it chunk.Item) {
+ l.remotes = append(l.remotes, it.(*gitalypb.ListRemotesResponse_Remote))
+}
+
+func (l *listRemotesSender) Send() error {
+ return l.stream.Send(&gitalypb.ListRemotesResponse{Remotes: l.remotes})
+}
+
+func (l *listRemotesSender) Reset() { l.remotes = nil }
diff --git a/internal/service/remote/remotes_test.go b/internal/service/remote/remotes_test.go
index b90d8c8b4..80c1e6dbb 100644
--- a/internal/service/remote/remotes_test.go
+++ b/internal/service/remote/remotes_test.go
@@ -270,3 +270,152 @@ func TestFailedFindRemoteRepository(t *testing.T) {
require.Equal(t, tc.exists, resp.GetExists(), tc.description)
}
}
+
+func TestListDifferentPushUrlRemote(t *testing.T) {
+ server, serverSocketPath := runRemoteServiceServer(t)
+ defer server.Stop()
+
+ client, conn := NewRemoteClient(t, serverSocketPath)
+ defer conn.Close()
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ testRepo, testRepoPath, cleanupFn := testhelper.NewTestRepo(t)
+ defer cleanupFn()
+
+ client.RemoveRemote(ctx, &gitalypb.RemoveRemoteRequest{
+ Repository: testRepo,
+ Name: "origin",
+ })
+
+ branchName := "my-remote"
+ fetchURL := "http://my-repo.git"
+ pushURL := "http://my-other-repo.git"
+
+ testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "remote", "add", branchName, fetchURL)
+ testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "remote", "set-url", "--push", branchName, pushURL)
+
+ testCases := []*gitalypb.ListRemotesResponse_Remote{
+ {
+ Name: branchName,
+ FetchUrl: fetchURL,
+ PushUrl: pushURL,
+ },
+ }
+
+ request := &gitalypb.ListRemotesRequest{Repository: testRepo}
+
+ resp, err := client.ListRemotes(ctx, request)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ receivedRemotes := consumeListRemotesResponse(t, resp)
+ require.NoError(t, err)
+
+ require.Len(t, receivedRemotes, len(testCases))
+ require.ElementsMatch(t, testCases, receivedRemotes)
+
+}
+
+func TestListRemotes(t *testing.T) {
+ server, serverSocketPath := runRemoteServiceServer(t)
+ defer server.Stop()
+
+ client, conn := NewRemoteClient(t, serverSocketPath)
+ defer conn.Close()
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ repoWithSingleRemote, _, cleanupFn := testhelper.NewTestRepo(t)
+ defer cleanupFn()
+
+ repoWithMultipleRemotes, _, cleanupFn := testhelper.NewTestRepo(t)
+ defer cleanupFn()
+
+ repoWithEmptyRemote, _, cleanupFn := testhelper.NewTestRepo(t)
+ defer cleanupFn()
+
+ singleRemote := []*gitalypb.ListRemotesResponse_Remote{
+ {Name: "my-remote", FetchUrl: "http://my-repo.git", PushUrl: "http://my-repo.git"},
+ }
+
+ multipleRemotes := []*gitalypb.ListRemotesResponse_Remote{
+ {Name: "my-other-remote", FetchUrl: "johndoe@host:my-new-repo.git", PushUrl: "johndoe@host:my-new-repo.git"},
+ {Name: "my-remote", FetchUrl: "http://my-repo.git", PushUrl: "http://my-repo.git"},
+ }
+
+ testCases := []struct {
+ description string
+ repository *gitalypb.Repository
+ remotes []*gitalypb.ListRemotesResponse_Remote
+ }{
+ {
+ description: "empty remote",
+ repository: repoWithEmptyRemote,
+ remotes: []*gitalypb.ListRemotesResponse_Remote{},
+ },
+ {
+ description: "single remote",
+ repository: repoWithSingleRemote,
+ remotes: singleRemote,
+ },
+ {
+ description: "multiple remotes",
+ repository: repoWithMultipleRemotes,
+ remotes: multipleRemotes,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.description, func(t *testing.T) {
+ client.RemoveRemote(ctx, &gitalypb.RemoveRemoteRequest{
+ Repository: tc.repository,
+ Name: "origin",
+ })
+
+ for _, r := range tc.remotes {
+ request := &gitalypb.AddRemoteRequest{
+ Repository: tc.repository,
+ Name: r.Name,
+ Url: r.FetchUrl,
+ }
+
+ _, err := client.AddRemote(ctx, request)
+ require.NoError(t, err)
+ }
+
+ request := &gitalypb.ListRemotesRequest{Repository: tc.repository}
+
+ resp, err := client.ListRemotes(ctx, request)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ receivedRemotes := consumeListRemotesResponse(t, resp)
+ require.NoError(t, err)
+
+ require.Len(t, receivedRemotes, len(tc.remotes))
+ require.ElementsMatch(t, tc.remotes, receivedRemotes)
+ })
+ }
+
+}
+
+func consumeListRemotesResponse(t *testing.T, l gitalypb.RemoteService_ListRemotesClient) []*gitalypb.ListRemotesResponse_Remote {
+ receivedRemotes := []*gitalypb.ListRemotesResponse_Remote{}
+ for {
+ resp, err := l.Recv()
+ if err == io.EOF {
+ break
+ }
+
+ require.NoError(t, err)
+
+ receivedRemotes = append(receivedRemotes, resp.GetRemotes()...)
+ }
+
+ return receivedRemotes
+}