Commit 2f07fa97 authored by Sean McGivern's avatar Sean McGivern

Merge branch 'gitaly-upload-archive' into 'master'

Add Gitaly git-upload-archive migrated command

See merge request gitlab-org/gitlab-shell!192
parents 9b9ada10 27bdba30
......@@ -14,3 +14,4 @@ hooks/*.d
/go_build
/bin/gitaly-upload-pack
/bin/gitaly-receive-pack
/bin/gitaly-upload-archive
v7.1.0
- Migrate `git-upload-archive` to gitaly
v7.0.0
- Switch to structured logging (!193)
......
package main
import (
"encoding/json"
"fmt"
"os"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/handler"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/logger"
pb "gitlab.com/gitlab-org/gitaly-proto/go"
)
func init() {
logger.ProgName = "gitaly-upload-archive"
}
type uploadArchiveHandler func(gitalyAddress string, request *pb.SSHUploadArchiveRequest) (int32, error)
func main() {
if err := handler.Prepare(); err != nil {
logger.Fatal("preparation failed", err)
}
code, err := uploadArchive(handler.UploadArchive, os.Args)
if err != nil {
logger.Fatal("upload-archive failed", err)
}
os.Exit(int(code))
}
func uploadArchive(handler uploadArchiveHandler, args []string) (int32, error) {
if n := len(args); n != 3 {
return 0, fmt.Errorf("wrong number of arguments: expected 2 arguments, got %v", args)
}
var request pb.SSHUploadArchiveRequest
if err := json.Unmarshal([]byte(args[2]), &request); err != nil {
return 0, fmt.Errorf("unmarshaling request json failed: %v", err)
}
return handler(args[1], &request)
}
package main
import (
"fmt"
"strings"
"testing"
pb "gitlab.com/gitlab-org/gitaly-proto/go"
)
var testGitalyAddress = "unix:gitaly.socket"
func TestUploadArchiveSuccess(t *testing.T) {
testRelativePath := "myrepo.git"
requestJSON := fmt.Sprintf(`{"repository":{"relative_path":"%s"}}`, testRelativePath)
mockHandler := func(gitalyAddress string, request *pb.SSHUploadArchiveRequest) (int32, error) {
if gitalyAddress != testGitalyAddress {
t.Fatalf("Expected gitaly address %s got %v", testGitalyAddress, gitalyAddress)
}
if relativePath := request.Repository.RelativePath; relativePath != testRelativePath {
t.Fatalf("Expected repository with relative path %s got %v", testRelativePath, request)
}
return 0, nil
}
code, err := uploadArchive(mockHandler, []string{"git-upload-archive", testGitalyAddress, requestJSON})
if err != nil {
t.Fatal(err)
}
if code != 0 {
t.Fatalf("Expected exit code 0, got %v", code)
}
}
func TestUploadArchiveFailure(t *testing.T) {
mockHandler := func(_ string, _ *pb.SSHUploadArchiveRequest) (int32, error) {
t.Fatal("Expected handler not to be called")
return 0, nil
}
tests := []struct {
desc string
args []string
err string
}{
{
desc: "With an invalid request json",
args: []string{"git-upload-archive", testGitalyAddress, "hello"},
err: "unmarshaling request json failed",
},
{
desc: "With an invalid argument count",
args: []string{"git-upload-archive", testGitalyAddress, "{}", "extra arg"},
err: "wrong number of arguments: expected 2 arguments",
},
}
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
_, err := uploadArchive(mockHandler, test.args)
if !strings.Contains(err.Error(), test.err) {
t.Fatalf("Expected error %v, got %v", test.err, err)
}
})
}
}
package handler
import (
"context"
"fmt"
"os"
pb "gitlab.com/gitlab-org/gitaly-proto/go"
"gitlab.com/gitlab-org/gitaly/client"
)
func UploadArchive(gitalyAddress string, request *pb.SSHUploadArchiveRequest) (int32, error) {
if gitalyAddress == "" {
return 0, fmt.Errorf("no gitaly_address given")
}
conn, err := client.Dial(gitalyAddress, dialOpts())
if err != nil {
return 0, err
}
defer conn.Close()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
return client.UploadArchive(ctx, conn, os.Stdin, os.Stdout, os.Stderr, request)
}
package helper
import (
"io"
pb "gitlab.com/gitlab-org/gitaly-proto/go"
)
type InfoRefsClient interface {
Recv() (*pb.InfoRefsResponse, error)
}
type InfoRefsClientWriterTo struct {
InfoRefsClient
}
func (clientReader *InfoRefsClientWriterTo) WriteTo(w io.Writer) (total int64, err error) {
for {
response, err := clientReader.Recv()
if err == io.EOF {
return total, nil
} else if err != nil {
return total, err
}
n, err := w.Write(response.GetData())
total += int64(n)
if err != nil {
return total, err
}
}
}
package helper
import (
"io"
)
// NewReceiveReader turns receiver into an io.Reader. Errors from the
// receiver function are passed on unmodified. This means receiver should
// emit io.EOF when done.
func NewReceiveReader(receiver func() ([]byte, error)) io.Reader {
return &receiveReader{receiver: receiver}
}
type receiveReader struct {
receiver func() ([]byte, error)
data []byte
err error
}
func (rr *receiveReader) Read(p []byte) (int, error) {
if len(rr.data) == 0 {
rr.data, rr.err = rr.receiver()
}
n := copy(p, rr.data)
rr.data = rr.data[n:]
if len(rr.data) == 0 {
return n, rr.err
}
return n, nil
}
// NewSendWriter turns sender into an io.Writer. The number of 'bytes
// written' reported back is always len(p).
func NewSendWriter(sender func(p []byte) error) io.Writer {
return &sendWriter{sender: sender}
}
type sendWriter struct {
sender func([]byte) error
}
func (sw *sendWriter) Write(p []byte) (int, error) {
return len(p), sw.sender(p)
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: server.proto
package gitaly
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type ServerInfoRequest struct {
}
func (m *ServerInfoRequest) Reset() { *m = ServerInfoRequest{} }
func (m *ServerInfoRequest) String() string { return proto.CompactTextString(m) }
func (*ServerInfoRequest) ProtoMessage() {}
func (*ServerInfoRequest) Descriptor() ([]byte, []int) { return fileDescriptor11, []int{0} }
type ServerInfoResponse struct {
ServerVersion string `protobuf:"bytes,1,opt,name=server_version,json=serverVersion" json:"server_version,omitempty"`
GitVersion string `protobuf:"bytes,2,opt,name=git_version,json=gitVersion" json:"git_version,omitempty"`
}
func (m *ServerInfoResponse) Reset() { *m = ServerInfoResponse{} }
func (m *ServerInfoResponse) String() string { return proto.CompactTextString(m) }
func (*ServerInfoResponse) ProtoMessage() {}
func (*ServerInfoResponse) Descriptor() ([]byte, []int) { return fileDescriptor11, []int{1} }
func (m *ServerInfoResponse) GetServerVersion() string {
if m != nil {
return m.ServerVersion
}
return ""
}
func (m *ServerInfoResponse) GetGitVersion() string {
if m != nil {
return m.GitVersion
}
return ""
}
func init() {
proto.RegisterType((*ServerInfoRequest)(nil), "gitaly.ServerInfoRequest")
proto.RegisterType((*ServerInfoResponse)(nil), "gitaly.ServerInfoResponse")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// Client API for ServerService service
type ServerServiceClient interface {
ServerInfo(ctx context.Context, in *ServerInfoRequest, opts ...grpc.CallOption) (*ServerInfoResponse, error)
}
type serverServiceClient struct {
cc *grpc.ClientConn
}
func NewServerServiceClient(cc *grpc.ClientConn) ServerServiceClient {
return &serverServiceClient{cc}
}
func (c *serverServiceClient) ServerInfo(ctx context.Context, in *ServerInfoRequest, opts ...grpc.CallOption) (*ServerInfoResponse, error) {
out := new(ServerInfoResponse)
err := grpc.Invoke(ctx, "/gitaly.ServerService/ServerInfo", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for ServerService service
type ServerServiceServer interface {
ServerInfo(context.Context, *ServerInfoRequest) (*ServerInfoResponse, error)
}
func RegisterServerServiceServer(s *grpc.Server, srv ServerServiceServer) {
s.RegisterService(&_ServerService_serviceDesc, srv)
}
func _ServerService_ServerInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ServerInfoRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ServerServiceServer).ServerInfo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/gitaly.ServerService/ServerInfo",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ServerServiceServer).ServerInfo(ctx, req.(*ServerInfoRequest))
}
return interceptor(ctx, in, info, handler)
}
var _ServerService_serviceDesc = grpc.ServiceDesc{
ServiceName: "gitaly.ServerService",
HandlerType: (*ServerServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ServerInfo",
Handler: _ServerService_ServerInfo_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "server.proto",
}
func init() { proto.RegisterFile("server.proto", fileDescriptor11) }
var fileDescriptor11 = []byte{
// 160 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0x4e, 0x2d, 0x2a,
0x4b, 0x2d, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x4b, 0xcf, 0x2c, 0x49, 0xcc, 0xa9,
0x54, 0x12, 0xe6, 0x12, 0x0c, 0x06, 0x8b, 0x7b, 0xe6, 0xa5, 0xe5, 0x07, 0xa5, 0x16, 0x96, 0xa6,
0x16, 0x97, 0x28, 0xc5, 0x70, 0x09, 0x21, 0x0b, 0x16, 0x17, 0xe4, 0xe7, 0x15, 0xa7, 0x0a, 0xa9,
0x72, 0xf1, 0x41, 0x8c, 0x88, 0x2f, 0x4b, 0x2d, 0x2a, 0xce, 0xcc, 0xcf, 0x93, 0x60, 0x54, 0x60,
0xd4, 0xe0, 0x0c, 0xe2, 0x85, 0x88, 0x86, 0x41, 0x04, 0x85, 0xe4, 0xb9, 0xb8, 0xd3, 0x33, 0x4b,
0xe0, 0x6a, 0x98, 0xc0, 0x6a, 0xb8, 0xd2, 0x33, 0x4b, 0xa0, 0x0a, 0x8c, 0xc2, 0xb8, 0x78, 0x21,
0xa6, 0x83, 0xc8, 0xcc, 0xe4, 0x54, 0x21, 0x57, 0x2e, 0x2e, 0x84, 0x75, 0x42, 0x92, 0x7a, 0x10,
0xa7, 0xe9, 0x61, 0xb8, 0x4b, 0x4a, 0x0a, 0x9b, 0x14, 0xc4, 0x75, 0x4a, 0x0c, 0x49, 0x6c, 0x60,
0x9f, 0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xa0, 0x30, 0xe2, 0x5e, 0xe9, 0x00, 0x00, 0x00,
}
......@@ -30,7 +30,7 @@ type Repository struct {
func (m *Repository) Reset() { *m = Repository{} }
func (m *Repository) String() string { return proto.CompactTextString(m) }
func (*Repository) ProtoMessage() {}
func (*Repository) Descriptor() ([]byte, []int) { return fileDescriptor11, []int{0} }
func (*Repository) Descriptor() ([]byte, []int) { return fileDescriptor12, []int{0} }
func (m *Repository) GetStorageName() string {
if m != nil {
......@@ -80,7 +80,7 @@ type GitCommit struct {
func (m *GitCommit) Reset() { *m = GitCommit{} }
func (m *GitCommit) String() string { return proto.CompactTextString(m) }
func (*GitCommit) ProtoMessage() {}
func (*GitCommit) Descriptor() ([]byte, []int) { return fileDescriptor11, []int{1} }
func (*GitCommit) Descriptor() ([]byte, []int) { return fileDescriptor12, []int{1} }
func (m *GitCommit) GetId() string {
if m != nil {
......@@ -133,7 +133,7 @@ type CommitAuthor struct {
func (m *CommitAuthor) Reset() { *m = CommitAuthor{} }
func (m *CommitAuthor) String() string { return proto.CompactTextString(m) }
func (*CommitAuthor) ProtoMessage() {}
func (*CommitAuthor) Descriptor() ([]byte, []int) { return fileDescriptor11, []int{2} }
func (*CommitAuthor) Descriptor() ([]byte, []int) { return fileDescriptor12, []int{2} }
func (m *CommitAuthor) GetName() []byte {
if m != nil {
......@@ -163,7 +163,7 @@ type ExitStatus struct {
func (m *ExitStatus) Reset() { *m = ExitStatus{} }
func (m *ExitStatus) String() string { return proto.CompactTextString(m) }
func (*ExitStatus) ProtoMessage() {}
func (*ExitStatus) Descriptor() ([]byte, []int) { return fileDescriptor11, []int{3} }
func (*ExitStatus) Descriptor() ([]byte, []int) { return fileDescriptor12, []int{3} }
func (m *ExitStatus) GetValue() int32 {
if m != nil {
......@@ -181,7 +181,7 @@ type Branch struct {
func (m *Branch) Reset() { *m = Branch{} }
func (m *Branch) String() string { return proto.CompactTextString(m) }
func (*Branch) ProtoMessage() {}
func (*Branch) Descriptor() ([]byte, []int) { return fileDescriptor11, []int{4} }
func (*Branch) Descriptor() ([]byte, []int) { return fileDescriptor12, []int{4} }
func (m *Branch) GetName() []byte {
if m != nil {
......@@ -207,7 +207,7 @@ type Tag struct {
func (m *Tag) Reset() { *m = Tag{} }
func (m *Tag) String() string { return proto.CompactTextString(m) }
func (*Tag) ProtoMessage() {}
func (*Tag) Descriptor() ([]byte, []int) { return fileDescriptor11, []int{5} }
func (*Tag) Descriptor() ([]byte, []int) { return fileDescriptor12, []int{5} }
func (m *Tag) GetName() []byte {
if m != nil {
......@@ -247,7 +247,7 @@ type User struct {
func (m *User) Reset() { *m = User{} }
func (m *User) String() string { return proto.CompactTextString(m) }
func (*User) ProtoMessage() {}
func (*User) Descriptor() ([]byte, []int) { return fileDescriptor11, []int{6} }
func (*User) Descriptor() ([]byte, []int) { return fileDescriptor12, []int{6} }
func (m *User) GetGlId() string {
if m != nil {
......@@ -287,9 +287,9 @@ func init() {
proto.RegisterType((*User)(nil), "gitaly.User")
}
func init() { proto.RegisterFile("shared.proto", fileDescriptor11) }
func init() { proto.RegisterFile("shared.proto", fileDescriptor12) }
var fileDescriptor11 = []byte{
var fileDescriptor12 = []byte{
// 518 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x4d, 0x6f, 0xd3, 0x40,
0x10, 0x55, 0x1c, 0xc7, 0x90, 0x89, 0x8b, 0x60, 0xc9, 0xc1, 0xaa, 0x54, 0x35, 0x98, 0x4b, 0x0f,
......
......@@ -26,7 +26,7 @@ type InfoRefsRequest struct {
func (m *InfoRefsRequest) Reset() { *m = InfoRefsRequest{} }
func (m *InfoRefsRequest) String() string { return proto.CompactTextString(m) }
func (*InfoRefsRequest) ProtoMessage() {}
func (*InfoRefsRequest) Descriptor() ([]byte, []int) { return fileDescriptor12, []int{0} }
func (*InfoRefsRequest) Descriptor() ([]byte, []int) { return fileDescriptor13, []int{0} }
func (m *InfoRefsRequest) GetRepository() *Repository {
if m != nil {
......@@ -49,7 +49,7 @@ type InfoRefsResponse struct {
func (m *InfoRefsResponse) Reset() { *m = InfoRefsResponse{} }
func (m *InfoRefsResponse) String() string { return proto.CompactTextString(m) }
func (*InfoRefsResponse) ProtoMessage() {}
func (*InfoRefsResponse) Descriptor() ([]byte, []int) { return fileDescriptor12, []int{1} }
func (*InfoRefsResponse) Descriptor() ([]byte, []int) { return fileDescriptor13, []int{1} }
func (m *InfoRefsResponse) GetData() []byte {
if m != nil {
......@@ -70,7 +70,7 @@ type PostUploadPackRequest struct {
func (m *PostUploadPackRequest) Reset() { *m = PostUploadPackRequest{} }
func (m *PostUploadPackRequest) String() string { return proto.CompactTextString(m) }
func (*PostUploadPackRequest) ProtoMessage() {}
func (*PostUploadPackRequest) Descriptor() ([]byte, []int) { return fileDescriptor12, []int{2} }
func (*PostUploadPackRequest) Descriptor() ([]byte, []int) { return fileDescriptor13, []int{2} }
func (m *PostUploadPackRequest) GetRepository() *Repository {
if m != nil {
......@@ -101,7 +101,7 @@ type PostUploadPackResponse struct {
func (m *PostUploadPackResponse) Reset() { *m = PostUploadPackResponse{} }
func (m *PostUploadPackResponse) String() string { return proto.CompactTextString(m) }
func (*PostUploadPackResponse) ProtoMessage() {}
func (*PostUploadPackResponse) Descriptor() ([]byte, []int) { return fileDescriptor12, []int{3} }
func (*PostUploadPackResponse) Descriptor() ([]byte, []int) { return fileDescriptor13, []int{3} }
func (m *PostUploadPackResponse) GetData() []byte {
if m != nil {
......@@ -125,7 +125,7 @@ type PostReceivePackRequest struct {
func (m *PostReceivePackRequest) Reset() { *m = PostReceivePackRequest{} }
func (m *PostReceivePackRequest) String() string { return proto.CompactTextString(m) }
func (*PostReceivePackRequest) ProtoMessage() {}
func (*PostReceivePackRequest) Descriptor() ([]byte, []int) { return fileDescriptor12, []int{4} }
func (*PostReceivePackRequest) Descriptor() ([]byte, []int) { return fileDescriptor13, []int{4} }
func (m *PostReceivePackRequest) GetRepository() *Repository {
if m != nil {
......@@ -170,7 +170,7 @@ type PostReceivePackResponse struct {
func (m *PostReceivePackResponse) Reset() { *m = PostReceivePackResponse{} }
func (m *PostReceivePackResponse) String() string { return proto.CompactTextString(m) }
func (*PostReceivePackResponse) ProtoMessage() {}
func (*PostReceivePackResponse) Descriptor() ([]byte, []int) { return fileDescriptor12, []int{5} }
func (*PostReceivePackResponse) Descriptor() ([]byte, []int) { return fileDescriptor13, []int{5} }
func (m *PostReceivePackResponse) GetData() []byte {
if m != nil {
......@@ -485,9 +485,9 @@ var _SmartHTTPService_serviceDesc = grpc.ServiceDesc{
Metadata: "smarthttp.proto",
}
func init() { proto.RegisterFile("smarthttp.proto", fileDescriptor12) }
func init() { proto.RegisterFile("smarthttp.proto", fileDescriptor13) }
var fileDescriptor12 = []byte{
var fileDescriptor13 = []byte{
// 386 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x93, 0xdd, 0xee, 0xd2, 0x40,
0x10, 0xc5, 0x5d, 0xbe, 0x12, 0x06, 0x14, 0x32, 0x44, 0x69, 0x9a, 0x28, 0xa4, 0x26, 0xa6, 0x17,
......
package client
import (
"io"
"gitlab.com/gitlab-org/gitaly/streamio"
pb "gitlab.com/gitlab-org/gitaly-proto/go"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
// UploadArchive proxies an SSH git-upload-archive (git archive --remote) session to Gitaly
func UploadArchive(ctx context.Context, conn *grpc.ClientConn, stdin io.Reader, stdout, stderr io.Writer, req *pb.SSHUploadArchiveRequest) (int32, error) {
ctx2, cancel := context.WithCancel(ctx)
defer cancel()
ssh := pb.NewSSHServiceClient(conn)
stream, err := ssh.SSHUploadArchive(ctx2)
if err != nil {
return 0, err
}
if err = stream.Send(req); err != nil {
return 0, err
}
inWriter := streamio.NewWriter(func(p []byte) error {
return stream.Send(&pb.SSHUploadArchiveRequest{Stdin: p})
})
return streamHandler(func() (stdoutStderrResponse, error) {
return stream.Recv()
}, func(errC chan error) {
_, errRecv := io.Copy(inWriter, stdin)
stream.CloseSend()
errC <- errRecv
}, stdout, stderr)
}
......@@ -41,13 +41,13 @@
"versionExact": "v1.0.5"
},
{
"checksumSHA1": "8Gc1ZcO7WxXstNzyePjwG90SBSU=",
"checksumSHA1": "EuiW0GPDEqCG0UhnE7zYCrc6/G0=",
"path": "gitlab.com/gitlab-org/gitaly-proto/go",
"revision": "f62abc80cb25363bf51a4f89f02654ca2f722dc8",
"revisionTime": "2018-01-17T16:23:27Z",
"revision": "4d256c2c6403d420c598c1649b1d26fa4384bb1d",
"revisionTime": "2018-03-08T23:20:01Z",
"tree": true,
"version": "v0.75.0",
"versionExact": "v0.75.0"
"version": "v0.89.0",
"versionExact": "v0.89.0"
},
{
"checksumSHA1": "dUHJbKas746n5fLzlwxHb6FOCxs=",
......@@ -58,12 +58,12 @@
"versionExact": "v0.71.0"
},
{
"checksumSHA1": "s53Qjro9ZHX0DV2tCYQXLO2FHqI=",
"checksumSHA1": "CsPKG7r/N8ARlHtnHKimJiOnYiY=",
"path": "gitlab.com/gitlab-org/gitaly/client",
"revision": "95a198aef54c42fd8e84c62acc63f0cd620864b3",
"revisionTime": "2018-01-18T11:33:00Z",
"version": "v0.71.0",
"versionExact": "v0.71.0"
"revision": "5e2c70a9a670f5d675cf45f880bbbb08a5169ab8",
"revisionTime": "2018-03-13T20:33:04Z",
"version": "v0.90.0",
"versionExact": "v0.90.0"
},
{
"checksumSHA1": "mifcYH0qXpoPkX5KzXoM3mterWQ=",
......
......@@ -12,6 +12,7 @@ class GitlabShell # rubocop:disable Metrics/ClassLength
GIT_COMMANDS = %w(git-upload-pack git-receive-pack git-upload-archive git-lfs-authenticate).freeze
GITALY_MIGRATED_COMMANDS = {
'git-upload-pack' => File.join(ROOT_PATH, 'bin', 'gitaly-upload-pack'),
'git-upload-archive' => File.join(ROOT_PATH, 'bin', 'gitaly-upload-archive'),
'git-receive-pack' => File.join(ROOT_PATH, 'bin', 'gitaly-receive-pack')
}.freeze
API_COMMANDS = %w(2fa_recovery_codes).freeze
......
......@@ -252,6 +252,61 @@ describe GitlabShell do
end
end
shared_examples_for 'upload-archive' do |command|
let(:ssh_cmd) { "#{command} gitlab-ci.git" }
let(:exec_cmd_params) { ['git-upload-archive', repo_path] }
let(:exec_cmd_log_params) { exec_cmd_params }
after { subject.exec(ssh_cmd) }
it "should process the command" do
subject.should_receive(:process_cmd).with(%W(git-upload-archive gitlab-ci.git))
end
it "should execute the command" do
subject.should_receive(:exec_cmd).with(*exec_cmd_params)
end
it "should log the command execution" do
message = "executing git command"
user_string = "user with key #{key_id}"
$logger.should_receive(:info).with(message, command: exec_cmd_log_params.join(' '), user: user_string)
end
it "should use usernames if configured to do so" do
GitlabConfig.any_instance.stub(audit_usernames: true)
$logger.should_receive(:info).with("executing git command", hash_including(user: 'John Doe'))
end
end
context 'git-upload-archive' do
it_behaves_like 'upload-archive', 'git-upload-archive'
end
context 'git upload-archive' do
it_behaves_like 'upload-archive', 'git upload-archive'
end
context 'gitaly-upload-archive' do
before do
api.stub(check_access: gitaly_check_access)
end
it_behaves_like 'upload-archive', 'git-upload-archive' do
let(:gitaly_executable) { "gitaly-upload-archive" }
let(:exec_cmd_params) do
[
File.join(ROOT_PATH, "bin", gitaly_executable),
'unix:gitaly.socket',
gitaly_message
]
end
let(:exec_cmd_log_params) do
[gitaly_executable, 'unix:gitaly.socket', gitaly_message]
end
end
end
context 'arbitrary command' do
let(:ssh_cmd) { 'arbitrary command' }
after { subject.exec(ssh_cmd) }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment