diff -Nru golang-gitaly-proto-1.27.2+dfsg/cleanup.proto golang-gitaly-proto-1.37.0+dfsg/cleanup.proto --- golang-gitaly-proto-1.27.2+dfsg/cleanup.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/cleanup.proto 2019-07-11 14:35:16.000000000 +0000 @@ -9,15 +9,24 @@ service CleanupService { // Deprecated in favour of ApplyBfgObjectMapStream rpc ApplyBfgObjectMap(stream ApplyBfgObjectMapRequest) returns (ApplyBfgObjectMapResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc ApplyBfgObjectMapStream(stream ApplyBfgObjectMapStreamRequest) returns (stream ApplyBfgObjectMapStreamResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc CloseSession(CloseSessionRequest) returns (CloseSessionResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + scope_level: SERVER, + }; } } diff -Nru golang-gitaly-proto-1.27.2+dfsg/commit.proto golang-gitaly-proto-1.37.0+dfsg/commit.proto --- golang-gitaly-proto-1.27.2+dfsg/commit.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/commit.proto 2019-07-11 14:35:16.000000000 +0000 @@ -60,6 +60,9 @@ rpc ListCommitsByOid(ListCommitsByOidRequest) returns (stream ListCommitsByOidResponse) { option (op_type).op = ACCESSOR; } + rpc ListCommitsByRefName(ListCommitsByRefNameRequest) returns (stream ListCommitsByRefNameResponse) { + option (op_type).op = ACCESSOR; + } rpc FilterShasWithSignatures(stream FilterShasWithSignaturesRequest) returns (stream FilterShasWithSignaturesResponse) { option (op_type).op = ACCESSOR; } @@ -231,6 +234,15 @@ repeated GitCommit commits = 1; } +message ListCommitsByRefNameRequest { + Repository repository = 1; + repeated bytes ref_names = 2; +} + +message ListCommitsByRefNameResponse { + repeated GitCommit commits = 1; +} + message FindAllCommitsRequest { Repository repository = 1; // When nil, return all commits reachable by any branch in the repo @@ -320,7 +332,7 @@ reserved 1; GitCommit commit = 2; - string path = 3 [deprecated = true]; + reserved 3; bytes path_bytes = 4; } repeated CommitForTree commits = 1; diff -Nru golang-gitaly-proto-1.27.2+dfsg/conflicts.proto golang-gitaly-proto-1.37.0+dfsg/conflicts.proto --- golang-gitaly-proto-1.27.2+dfsg/conflicts.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/conflicts.proto 2019-07-11 14:35:16.000000000 +0000 @@ -11,7 +11,10 @@ option (op_type).op = ACCESSOR; } rpc ResolveConflicts(stream ResolveConflictsRequest) returns (ResolveConflictsResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1.1" + }; } } diff -Nru golang-gitaly-proto-1.27.2+dfsg/debian/changelog golang-gitaly-proto-1.37.0+dfsg/debian/changelog --- golang-gitaly-proto-1.27.2+dfsg/debian/changelog 2019-08-03 10:50:31.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/debian/changelog 2019-10-03 17:23:02.000000000 +0000 @@ -1,3 +1,21 @@ +golang-gitaly-proto (1.37.0+dfsg-1) unstable; urgency=medium + + [ Pirate Praveen ] + * Build golang part again (not complete) + * Generate pb.rb files in configure + + [Sruthi Chandran ] + * New upstream version 1.37.0+dfsg + + -- Sruthi Chandran Thu, 03 Oct 2019 22:53:02 +0530 + +golang-gitaly-proto (1.32.0+dfsg-1) unstable; urgency=medium + + * Team upload + * New upstream version 1.32.0+dfsg + + -- Sruthi Chandran Sat, 07 Sep 2019 00:03:15 +0530 + golang-gitaly-proto (1.27.2+dfsg-1) unstable; urgency=medium * New upstream version 1.27.2+dfsg diff -Nru golang-gitaly-proto-1.27.2+dfsg/debian/control golang-gitaly-proto-1.37.0+dfsg/debian/control --- golang-gitaly-proto-1.27.2+dfsg/debian/control 2019-08-03 10:50:23.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/debian/control 2019-09-27 19:01:18.000000000 +0000 @@ -2,7 +2,8 @@ Section: devel Priority: optional Maintainer: Debian Go Packaging Team -Uploaders: Pirate Praveen +Uploaders: Pirate Praveen , + Sruthi Chandran Build-Depends: debhelper (>= 11~), dh-golang, golang-goprotobuf-dev, diff -Nru golang-gitaly-proto-1.27.2+dfsg/debian/rules golang-gitaly-proto-1.37.0+dfsg/debian/rules --- golang-gitaly-proto-1.27.2+dfsg/debian/rules 2019-08-03 09:47:15.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/debian/rules 2019-09-27 18:32:58.000000000 +0000 @@ -6,14 +6,12 @@ export GEM2DEB_TEST_RUNNER = --check-dependencies %: - # Skip building golang temporarily https://gitlab.com/gitlab-org/gitaly/issues/1427 (using embedded copy in gitaly) dh $@ --buildsystem=golang --with=golang --package=golang-gitaly-proto-dev dh $@ --buildsystem=ruby --with=ruby --package=ruby-gitaly override_dh_auto_configure: - mkdir -p go/gitalypb _support/generate-from-proto - #dh_auto_configure -O--buildsystem=golang -O--package=golang-gitaly-proto-dev + dh_auto_configure -O--buildsystem=golang -O--package=golang-gitaly-proto-dev dh_auto_configure -O--buildsystem=ruby -O--package=ruby-gitaly override_dh_auto_build: @@ -23,14 +21,14 @@ dh_auto_test -O--buildsystem=ruby -O--package=ruby-gitaly override_dh_auto_install: - #dh_auto_install -O--buildsystem=golang -O--package=golang-gitaly-proto-dev --destdir=debian/golang-gitaly-proto-dev + dh_auto_install -O--buildsystem=golang -O--package=golang-gitaly-proto-dev --destdir=debian/golang-gitaly-proto-dev dh_auto_install -O--buildsystem=ruby -O--package=ruby-gitaly --destdir=debian/ruby-gitaly override_dh_golang: override_dh_auto_clean: rm -rf go/*.pb.go + rm -rf go/gitalypb/*.pb.go rm -rf ruby/lib/gitaly/*_pb.rb - rm -rf go/gitalypb dh_auto_clean -O--buildsystem=golang -O--package=golang-gitaly-proto-dev dh_auto_clean -O--buildsystem=ruby diff -Nru golang-gitaly-proto-1.27.2+dfsg/go/gitalypb/go.mod golang-gitaly-proto-1.37.0+dfsg/go/gitalypb/go.mod --- golang-gitaly-proto-1.27.2+dfsg/go/gitalypb/go.mod 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/go/gitalypb/go.mod 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -module gitlab.com/gitlab-org/gitaly-proto/go/gitalypb diff -Nru golang-gitaly-proto-1.27.2+dfsg/go/gitalypb/protolist.go golang-gitaly-proto-1.37.0+dfsg/go/gitalypb/protolist.go --- golang-gitaly-proto-1.27.2+dfsg/go/gitalypb/protolist.go 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/go/gitalypb/protolist.go 2019-07-11 14:35:16.000000000 +0000 @@ -10,7 +10,6 @@ "conflicts.proto", "diff.proto", "namespace.proto", - "notifications.proto", "objectpool.proto", "operations.proto", "ref.proto", diff -Nru golang-gitaly-proto-1.27.2+dfsg/go/internal/cmd/protoc-gen-gitaly/main.go golang-gitaly-proto-1.37.0+dfsg/go/internal/cmd/protoc-gen-gitaly/main.go --- golang-gitaly-proto-1.27.2+dfsg/go/internal/cmd/protoc-gen-gitaly/main.go 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/go/internal/cmd/protoc-gen-gitaly/main.go 2019-07-11 14:35:16.000000000 +0000 @@ -165,12 +165,7 @@ for _, fi := range files { if !fi.IsDir() && strings.HasSuffix(fi.Name(), ".proto") { - fd := proto.FileDescriptor(fi.Name()) - fdp, err := extractFile(fd) - if err != nil { - return fmt.Errorf("failed to extract %s: %v", fi.Name(), err) - } - protoNames = append(protoNames, fmt.Sprintf(`"%s"`, fdp.GetName())) + protoNames = append(protoNames, fmt.Sprintf(`"%s"`, fi.Name())) } } diff -Nru golang-gitaly-proto-1.27.2+dfsg/go/internal/extension.go golang-gitaly-proto-1.37.0+dfsg/go/internal/extension.go --- golang-gitaly-proto-1.27.2+dfsg/go/internal/extension.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/go/internal/extension.go 2019-07-11 14:35:16.000000000 +0000 @@ -0,0 +1,30 @@ +package internal + +import ( + "errors" + "fmt" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/protoc-gen-go/descriptor" + "gitlab.com/gitlab-org/gitaly-proto/go/gitalypb" +) + +func GetOpExtension(m *descriptor.MethodDescriptorProto) (*gitalypb.OperationMsg, error) { + options := m.GetOptions() + + if !proto.HasExtension(options, gitalypb.E_OpType) { + return nil, errors.New("missing op_type option") + } + + ext, err := proto.GetExtension(options, gitalypb.E_OpType) + if err != nil { + return nil, err + } + + opMsg, ok := ext.(*gitalypb.OperationMsg) + if !ok { + return nil, fmt.Errorf("unable to obtain OperationMsg from %#v", ext) + } + + return opMsg, nil +} diff -Nru golang-gitaly-proto-1.27.2+dfsg/go/internal/filedescriptor.go golang-gitaly-proto-1.37.0+dfsg/go/internal/filedescriptor.go --- golang-gitaly-proto-1.27.2+dfsg/go/internal/filedescriptor.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/go/internal/filedescriptor.go 2019-07-11 14:35:16.000000000 +0000 @@ -0,0 +1,34 @@ +package internal + +import ( + "bytes" + "compress/gzip" + "fmt" + "io/ioutil" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/protoc-gen-go/descriptor" +) + +// ExtractFile extracts a FileDescriptorProto from a gzip'd buffer. +// Note: function is copied from the github.com/golang/protobuf dependency: +// https://github.com/golang/protobuf/blob/9eb2c01ac278a5d89ce4b2be68fe4500955d8179/descriptor/descriptor.go#L50 +func ExtractFile(gz []byte) (*descriptor.FileDescriptorProto, error) { + r, err := gzip.NewReader(bytes.NewReader(gz)) + if err != nil { + return nil, fmt.Errorf("failed to open gzip reader: %v", err) + } + defer r.Close() + + b, err := ioutil.ReadAll(r) + if err != nil { + return nil, fmt.Errorf("failed to uncompress descriptor: %v", err) + } + + fd := new(descriptor.FileDescriptorProto) + if err := proto.Unmarshal(b, fd); err != nil { + return nil, fmt.Errorf("malformed FileDescriptorProto: %v", err) + } + + return fd, nil +} diff -Nru golang-gitaly-proto-1.27.2+dfsg/go/internal/go.mod golang-gitaly-proto-1.37.0+dfsg/go/internal/go.mod --- golang-gitaly-proto-1.27.2+dfsg/go/internal/go.mod 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/go/internal/go.mod 2019-07-11 14:35:16.000000000 +0000 @@ -5,7 +5,7 @@ github.com/pseudomuto/protoc-gen-doc v1.1.0 github.com/pseudomuto/protokit v0.1.0 // indirect github.com/stretchr/testify v0.0.0-20190109162356-363ebb24d041 - gitlab.com/gitlab-org/gitaly-proto/go/gitalypb v0.0.0-20190312170322-310c5c9a1246 + gitlab.com/gitlab-org/gitaly-proto v1.33.0 golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95 // indirect golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 // indirect google.golang.org/grpc v1.19.0 // indirect diff -Nru golang-gitaly-proto-1.27.2+dfsg/go/internal/go.sum golang-gitaly-proto-1.37.0+dfsg/go/internal/go.sum --- golang-gitaly-proto-1.27.2+dfsg/go/internal/go.sum 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/go/internal/go.sum 2019-07-11 14:35:16.000000000 +0000 @@ -17,18 +17,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v0.0.0-20190109162356-363ebb24d041 h1:Jy3vb7QLEaCKB0IU6h2SKxCffKtZVnj3mks4+v04Iag= github.com/stretchr/testify v0.0.0-20190109162356-363ebb24d041/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -gitlab.com/gitlab-org/gitaly-proto/go/gitalypb v0.0.0-20190311164504-26039b1a7be9 h1:ZoxNFx5ePCrog0AzfZwkjyMFH4bDO2LWOE/Xc4mHQcA= -gitlab.com/gitlab-org/gitaly-proto/go/gitalypb v0.0.0-20190311164504-26039b1a7be9/go.mod h1:dGmH1a/qej91t5EmKA9ghVc61Lsjr16ZAyXQiiiN7xg= -gitlab.com/gitlab-org/gitaly-proto/go/gitalypb v0.0.0-20190312170322-11bb23265e26 h1:5U9ocC11G+t+AAwfxqD2cCcUSZeUSfWLemUsAtTYTFI= -gitlab.com/gitlab-org/gitaly-proto/go/gitalypb v0.0.0-20190312170322-11bb23265e26/go.mod h1:dGmH1a/qej91t5EmKA9ghVc61Lsjr16ZAyXQiiiN7xg= -gitlab.com/gitlab-org/gitaly-proto/go/gitalypb v0.0.0-20190312170322-2788afc322a2 h1:f6Q3GKGxiaW5VYP8tStjQNBYbzK6XPSs8wsvvcx+rFA= -gitlab.com/gitlab-org/gitaly-proto/go/gitalypb v0.0.0-20190312170322-2788afc322a2/go.mod h1:dGmH1a/qej91t5EmKA9ghVc61Lsjr16ZAyXQiiiN7xg= -gitlab.com/gitlab-org/gitaly-proto/go/gitalypb v0.0.0-20190312170322-310c5c9a1246 h1:pLzpzwg8+/ECCeScxyE0KVwG9QYpayz8hk4pxdmcDko= -gitlab.com/gitlab-org/gitaly-proto/go/gitalypb v0.0.0-20190312170322-310c5c9a1246/go.mod h1:dGmH1a/qej91t5EmKA9ghVc61Lsjr16ZAyXQiiiN7xg= -gitlab.com/gitlab-org/gitaly-proto/go/gitalypb v0.0.0-20190312170322-43a283ce7e06 h1:V4c1iO+M9/SMGV+UXxBrA6i+8y9TVgyOUHKG6zSWrO8= -gitlab.com/gitlab-org/gitaly-proto/go/gitalypb v0.0.0-20190312170322-43a283ce7e06/go.mod h1:dGmH1a/qej91t5EmKA9ghVc61Lsjr16ZAyXQiiiN7xg= -gitlab.com/gitlab-org/gitaly-proto/go/gitalypb v0.0.0-20190312170322-45bb9aabe6d9 h1:uxF2AHQzO6xsYeTC7dVp2N35040h1jQLzLNMQlZxJc4= -gitlab.com/gitlab-org/gitaly-proto/go/gitalypb v0.0.0-20190312170322-45bb9aabe6d9/go.mod h1:dGmH1a/qej91t5EmKA9ghVc61Lsjr16ZAyXQiiiN7xg= +gitlab.com/gitlab-org/gitaly-proto v1.33.0 h1:gSwV1hGpwrEauYcl81j214DRfUHAznBeeOMdwbvadnc= +gitlab.com/gitlab-org/gitaly-proto v1.33.0/go.mod h1:zNjk/86bjwLVJ4NcvInBcXcLdptdRFQ28sYrdFbrFgY= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95 h1:fY7Dsw114eJN4boqzVSbpVHO6rTdhq6/GnXeu+PKnzU= diff -Nru golang-gitaly-proto-1.27.2+dfsg/go/internal/linter/lint.go golang-gitaly-proto-1.37.0+dfsg/go/internal/linter/lint.go --- golang-gitaly-proto-1.27.2+dfsg/go/internal/linter/lint.go 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/go/internal/linter/lint.go 2019-07-11 14:35:16.000000000 +0000 @@ -1,11 +1,12 @@ package linter import ( + "errors" "fmt" - "github.com/golang/protobuf/proto" "github.com/golang/protobuf/protoc-gen-go/descriptor" "gitlab.com/gitlab-org/gitaly-proto/go/gitalypb" + "gitlab.com/gitlab-org/gitaly-proto/go/internal" ) // ensureMethodOpType will ensure that method includes the op_type option. @@ -14,49 +15,32 @@ // rpc ExampleMethod(ExampleMethodRequest) returns (ExampleMethodResponse) { // option (op_type).op = ACCESSOR; // } -func ensureMethodOpType(file string, m *descriptor.MethodDescriptorProto) error { - options := m.GetOptions() - - if !proto.HasExtension(options, gitalypb.E_OpType) { - return fmt.Errorf( - "%s: Method %s missing op_type option", - file, - m.GetName(), - ) - } - - ext, err := proto.GetExtension(options, gitalypb.E_OpType) +func ensureMethodOpType(fileDesc *descriptor.FileDescriptorProto, m *descriptor.MethodDescriptorProto) error { + opMsg, err := internal.GetOpExtension(m) if err != nil { return err } - opMsg, ok := ext.(*gitalypb.OperationMsg) - if !ok { - return fmt.Errorf("unable to obtain OperationMsg from %#v", ext) + ml := methodLinter{ + fileDesc: fileDesc, + methodDesc: m, + opMsg: opMsg, } switch opCode := opMsg.GetOp(); opCode { case gitalypb.OperationMsg_ACCESSOR: - return nil + return ml.validateAccessor() case gitalypb.OperationMsg_MUTATOR: - return nil + // if mutator, we need to make sure we specify scope or target repo + return ml.validateMutator() case gitalypb.OperationMsg_UNKNOWN: - return fmt.Errorf( - "%s: Method %s has op set to UNKNOWN", - file, - m.GetName(), - ) + return errors.New("op set to UNKNOWN") default: - return fmt.Errorf( - "%s: Method %s has invalid operation class with int32 value of %d", - file, - m.GetName(), - opCode, - ) + return fmt.Errorf("invalid operation class with int32 value of %d", opCode) } } @@ -68,8 +52,13 @@ for _, serviceDescriptorProto := range file.GetService() { for _, methodDescriptorProto := range serviceDescriptorProto.GetMethod() { - err := ensureMethodOpType(file.GetName(), methodDescriptorProto) + err := ensureMethodOpType(file, methodDescriptorProto) if err != nil { + // decorate error with current file and method + err = fmt.Errorf( + "%s: Method %q: %s", + file.GetName(), methodDescriptorProto.GetName(), err, + ) errs = append(errs, err) } } diff -Nru golang-gitaly-proto-1.27.2+dfsg/go/internal/linter/lint_test.go golang-gitaly-proto-1.37.0+dfsg/go/internal/linter/lint_test.go --- golang-gitaly-proto-1.27.2+dfsg/go/internal/linter/lint_test.go 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/go/internal/linter/lint_test.go 2019-07-11 14:35:16.000000000 +0000 @@ -1,17 +1,13 @@ package linter_test import ( - "bytes" - "compress/gzip" "errors" - "fmt" - "io/ioutil" "testing" "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/protoc-gen-go/descriptor" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly-proto/go/internal" "gitlab.com/gitlab-org/gitaly-proto/go/internal/linter" _ "gitlab.com/gitlab-org/gitaly-proto/go/internal/linter/testdata" ) @@ -28,43 +24,26 @@ { protoPath: "go/internal/linter/testdata/invalid.proto", errs: []error{ - errors.New("go/internal/linter/testdata/invalid.proto: Method InvalidMethod has op set to UNKNOWN"), - }, - }, - { - protoPath: "go/internal/linter/testdata/incomplete.proto", - errs: []error{ - errors.New("go/internal/linter/testdata/incomplete.proto: Method IncompleteMethod missing op_type option"), + errors.New(`go/internal/linter/testdata/invalid.proto: Method "InvalidMethod0": missing op_type option`), + errors.New(`go/internal/linter/testdata/invalid.proto: Method "InvalidMethod1": op set to UNKNOWN`), + errors.New(`go/internal/linter/testdata/invalid.proto: Method "InvalidMethod2": accessors cannot specify target repos`), + errors.New(`go/internal/linter/testdata/invalid.proto: Method "InvalidMethod3": server level scoped RPC should not specify target repo`), + errors.New(`go/internal/linter/testdata/invalid.proto: Method "InvalidMethod4": missing target repository field`), + errors.New(`go/internal/linter/testdata/invalid.proto: Method "InvalidMethod5": unable to parse target field OID 🐛: strconv.Atoi: parsing "🐛": invalid syntax`), + errors.New(`go/internal/linter/testdata/invalid.proto: Method "InvalidMethod6": target repo OID [1] does not exist in request message`), + errors.New(`go/internal/linter/testdata/invalid.proto: Method "InvalidMethod7": unexpected type TYPE_INT32 (expected .gitaly.Repository) for target repo field addressed by [1]`), + errors.New(`go/internal/linter/testdata/invalid.proto: Method "InvalidMethod8": expected 1-th field of OID [1 1] to be TYPE_MESSAGE, but got TYPE_INT32`), + errors.New(`go/internal/linter/testdata/invalid.proto: Method "InvalidMethod9": target repo OID [1 2] does not exist in request message`), + errors.New(`go/internal/linter/testdata/invalid.proto: Method "InvalidMethod10": unexpected type TYPE_INT32 (expected .gitaly.Repository) for target repo field addressed by [1 1]`), }, }, } { - fd, err := extractFile(proto.FileDescriptor(tt.protoPath)) - require.NoError(t, err) - - errs := linter.LintFile(fd) - require.Equal(t, tt.errs, errs) + t.Run(tt.protoPath, func(t *testing.T) { + fd, err := internal.ExtractFile(proto.FileDescriptor(tt.protoPath)) + require.NoError(t, err) + + errs := linter.LintFile(fd) + require.Equal(t, tt.errs, errs) + }) } } - -// extractFile extracts a FileDescriptorProto from a gzip'd buffer. -// Note: function is copied from the github.com/golang/protobuf dependency: -// https://github.com/golang/protobuf/blob/9eb2c01ac278a5d89ce4b2be68fe4500955d8179/descriptor/descriptor.go#L50 -func extractFile(gz []byte) (*descriptor.FileDescriptorProto, error) { - r, err := gzip.NewReader(bytes.NewReader(gz)) - if err != nil { - return nil, fmt.Errorf("failed to open gzip reader: %v", err) - } - defer r.Close() - - b, err := ioutil.ReadAll(r) - if err != nil { - return nil, fmt.Errorf("failed to uncompress descriptor: %v", err) - } - - fd := new(descriptor.FileDescriptorProto) - if err := proto.Unmarshal(b, fd); err != nil { - return nil, fmt.Errorf("malformed FileDescriptorProto: %v", err) - } - - return fd, nil -} diff -Nru golang-gitaly-proto-1.27.2+dfsg/go/internal/linter/method.go golang-gitaly-proto-1.37.0+dfsg/go/internal/linter/method.go --- golang-gitaly-proto-1.27.2+dfsg/go/internal/linter/method.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/go/internal/linter/method.go 2019-07-11 14:35:16.000000000 +0000 @@ -0,0 +1,204 @@ +package linter + +import ( + "errors" + "fmt" + "strconv" + "strings" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/protoc-gen-go/descriptor" + "gitlab.com/gitlab-org/gitaly-proto/go/gitalypb" + "gitlab.com/gitlab-org/gitaly-proto/go/internal" +) + +type methodLinter struct { + fileDesc *descriptor.FileDescriptorProto + methodDesc *descriptor.MethodDescriptorProto + opMsg *gitalypb.OperationMsg +} + +// validateAccessor will ensure the accessor method does not specify a target +// repo +func (ml methodLinter) validateAccessor() error { + if ml.opMsg.GetTargetRepositoryField() != "" { + return errors.New("accessors cannot specify target repos") + } + return nil +} + +// validateMutator will ensure the following rules: +// - Mutator RPC's with repository level scope must specify a target repo +// - Mutator RPC's without target repo must not be scoped at repo level +func (ml methodLinter) validateMutator() error { + switch scope := ml.opMsg.GetScopeLevel(); scope { + + case gitalypb.OperationMsg_REPOSITORY: + return ml.ensureValidRepoScope() + + case gitalypb.OperationMsg_SERVER: + return ml.ensureValidServerScope() + + default: + return fmt.Errorf("unknown operation scope level %d", scope) + + } +} + +func (ml methodLinter) ensureValidServerScope() error { + if ml.opMsg.GetTargetRepositoryField() != "" { + return errors.New("server level scoped RPC should not specify target repo") + } + return nil +} + +func (ml methodLinter) ensureValidRepoScope() error { + return ml.ensureValidTargetRepo() +} + +const repoTypeName = ".gitaly.Repository" + +func (ml methodLinter) ensureValidTargetRepo() error { + if ml.opMsg.GetTargetRepositoryField() == "" { + return errors.New("missing target repository field") + } + + oids, err := parseOID(ml.opMsg.GetTargetRepositoryField()) + if err != nil { + return err + } + + sharedMsgs, err := getSharedTypes() + if err != nil { + return err + } + + topLevelMsgs := map[string]*descriptor.DescriptorProto{} + for _, msg := range append(ml.fileDesc.GetMessageType(), sharedMsgs...) { + topLevelMsgs[msg.GetName()] = msg + } + + reqMsgName, err := lastName(ml.methodDesc.GetInputType()) + if err != nil { + return err + } + + msgT := topLevelMsgs[reqMsgName] + targetType := "" + visited := 0 + + // TODO: Improve code quality by removing OID_FIELDS and MSG_FIELDS labels +OID_FIELDS: + for i, fieldNo := range oids { + fields := msgT.GetField() + MSG_FIELDS: + for _, f := range fields { + if f.GetNumber() == int32(fieldNo) { + visited++ + + targetType = f.GetTypeName() + if targetType == "" { + // primitives like int32 don't have TypeName + targetType = f.GetType().String() + } + + // if last OID, we're done + if i == len(oids)-1 { + break OID_FIELDS + } + + // if not last OID, descend into next nested message + const msgPrimitive = "TYPE_MESSAGE" + if primitive := f.GetType().String(); primitive != msgPrimitive { + return fmt.Errorf( + "expected %d-th field of OID %+v to be %s, but got %s", + i+1, oids, msgPrimitive, primitive, + ) + } + + msgName, err := lastName(f.GetTypeName()) + if err != nil { + return err + } + + // first check if field refers to a nested type + for _, nestedType := range msgT.GetNestedType() { + if msgName == nestedType.GetName() { + msgT = nestedType + break MSG_FIELDS + } + } + + // then, check if field refers to a top level type + var ok bool + msgT, ok = topLevelMsgs[msgName] + if !ok { + return fmt.Errorf( + "could not find message type %q for %d-th element %d of target OID %+v", + msgName, i+1, fieldNo, oids, + ) + } + break + } + } + } + + if visited != len(oids) { + return fmt.Errorf("target repo OID %+v does not exist in request message", oids) + } + + if targetType != repoTypeName { + return fmt.Errorf( + "unexpected type %s (expected %s) for target repo field addressed by %+v", + targetType, repoTypeName, oids, + ) + } + + return nil +} + +func lastName(inputType string) (string, error) { + tokens := strings.Split(inputType, ".") + + msgName := tokens[len(tokens)-1] + if msgName == "" { + return "", fmt.Errorf("unable to parse method input type: %s", inputType) + } + + return msgName, nil +} + +// parses a string like "1.1" and returns a slice of ints +func parseOID(rawFieldUID string) ([]int, error) { + fieldNoStrs := strings.Split(rawFieldUID, ".") + + if len(fieldNoStrs) < 1 { + return nil, + fmt.Errorf("OID string contains no field numbers: %s", fieldNoStrs) + } + + fieldNos := make([]int, len(fieldNoStrs)) + + for i, fieldNoStr := range fieldNoStrs { + fieldNo, err := strconv.Atoi(fieldNoStr) + if err != nil { + return nil, + fmt.Errorf("unable to parse target field OID %s: %s", rawFieldUID, err) + } + if fieldNo < 1 { + return nil, errors.New("zero is an invalid field number") + } + fieldNos[i] = fieldNo + } + + return fieldNos, nil +} + +func getSharedTypes() ([]*descriptor.DescriptorProto, error) { + sharedFD, err := internal.ExtractFile(proto.FileDescriptor("shared.proto")) + if err != nil { + return nil, err + } + + return sharedFD.GetMessageType(), nil +} diff -Nru golang-gitaly-proto-1.27.2+dfsg/go/internal/linter/testdata/incomplete.proto golang-gitaly-proto-1.37.0+dfsg/go/internal/linter/testdata/incomplete.proto --- golang-gitaly-proto-1.27.2+dfsg/go/internal/linter/testdata/incomplete.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/go/internal/linter/testdata/incomplete.proto 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -syntax = "proto3"; - -package test; - -message IncompleteMethodRequest {} - -message IncompleteMethodResponse{} - -service IncompleteService { - rpc IncompleteMethod(IncompleteMethodRequest) returns (IncompleteMethodResponse) { - } -} \ No newline at end of file diff -Nru golang-gitaly-proto-1.27.2+dfsg/go/internal/linter/testdata/invalid.proto golang-gitaly-proto-1.37.0+dfsg/go/internal/linter/testdata/invalid.proto --- golang-gitaly-proto-1.27.2+dfsg/go/internal/linter/testdata/invalid.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/go/internal/linter/testdata/invalid.proto 2019-07-11 14:35:16.000000000 +0000 @@ -6,10 +6,92 @@ message InvalidMethodRequest {} +message InvalidTargetType { + int32 wrong_type = 1; // RPC specifies field 1 is target repo +} + message InvalidMethodResponse{} +message InvalidNestedRequest{ + InvalidTargetType inner_message = 1; +} + service InvalidService { - rpc InvalidMethod(InvalidMethodRequest) returns (InvalidMethodResponse) { + // should fail if op_type extension is missing + rpc InvalidMethod0(InvalidMethodRequest) returns (InvalidMethodResponse) {} + + // should fail if op type is unknown + rpc InvalidMethod1(InvalidMethodRequest) returns (InvalidMethodResponse) { option (gitaly.op_type).op = UNKNOWN; } + + // should fail if target repo is provided for accessor + rpc InvalidMethod2(InvalidMethodRequest) returns (InvalidMethodResponse) { + option (gitaly.op_type) = { + op: ACCESSOR + target_repository_field: "1" + }; + } + + // should fail if target repo is provided for server-scoped mutator + rpc InvalidMethod3(InvalidMethodRequest) returns (InvalidMethodResponse) { + option (gitaly.op_type) = { + op: MUTATOR + scope_level: SERVER + target_repository_field: "1" + }; + } + + // should fail if missing either target repo or non-repo-scope for mutator + rpc InvalidMethod4(InvalidMethodRequest) returns (InvalidMethodResponse) { + option (gitaly.op_type).op = MUTATOR; + } + + // should fail if target repo is incorrectly formatted for mutator + rpc InvalidMethod5(InvalidMethodRequest) returns (InvalidMethodResponse) { + option (gitaly.op_type) = { + op: MUTATOR + target_repository_field: "🐛" + }; + } + + // should fail if target field specified does not exist in request message + rpc InvalidMethod6(InvalidMethodRequest) returns (InvalidMethodResponse) { + option (gitaly.op_type) = { + op: MUTATOR + target_repository_field: "1" + }; + } + + // should fail if target field type is not of type Repository + rpc InvalidMethod7(InvalidTargetType) returns (InvalidMethodResponse) { + option (gitaly.op_type) = { + op: MUTATOR + target_repository_field: "1" + }; + } + + // should fail if request message is not deep enough for specified OID + rpc InvalidMethod8(InvalidTargetType) returns (InvalidMethodResponse) { + option (gitaly.op_type) = { + op: MUTATOR + target_repository_field: "1.1" + }; + } + + // should fail if nested target field type is missing + rpc InvalidMethod9(InvalidNestedRequest) returns (InvalidMethodResponse) { + option (gitaly.op_type) = { + op: MUTATOR + target_repository_field: "1.2" + }; + } + + // should fail if nested target field type is not of type Repository + rpc InvalidMethod10(InvalidNestedRequest) returns (InvalidMethodResponse) { + option (gitaly.op_type) = { + op: MUTATOR + target_repository_field: "1.1" + }; + } } \ No newline at end of file diff -Nru golang-gitaly-proto-1.27.2+dfsg/go/internal/linter/testdata/valid.proto golang-gitaly-proto-1.37.0+dfsg/go/internal/linter/testdata/valid.proto --- golang-gitaly-proto-1.27.2+dfsg/go/internal/linter/testdata/valid.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/go/internal/linter/testdata/valid.proto 2019-07-11 14:35:16.000000000 +0000 @@ -4,14 +4,73 @@ import "shared.proto"; -// TestRequest has the required option, so we should not expect it to cause -// a failure -message TestRequest {} +message ValidRequest { + gitaly.Repository destination = 1; +} + +message ValidResponse{} + +message ValidNestedRequest{ + ValidRequest inner_message = 1; +} -message TestResponse{} +message ValidNestedSharedRequest { + gitaly.ObjectPool nested_target_repo = 1; +} + +message ValidInnerNestedRequest { + message Header { + gitaly.Repository destination = 1; + } + + Header header = 1; +} -service TestService { - rpc TestMethod(TestRequest) returns (TestResponse) { +service ValidService { + rpc TestMethod(ValidRequest) returns (ValidResponse) { option (gitaly.op_type).op = ACCESSOR; } + + rpc TestMethod2(ValidRequest) returns (ValidResponse) { + option (gitaly.op_type) = { + op: MUTATOR + target_repository_field: "1" + }; + } + + rpc TestMethod3(ValidRequest) returns (ValidResponse) { + option (gitaly.op_type) = { + op: MUTATOR + scope_level: REPOSITORY // repo can be explicitly included + target_repository_field: "1" + }; + } + + rpc TestMethod4(ValidRequest) returns (ValidResponse) { + option (gitaly.op_type) = { + op: MUTATOR + scope_level: SERVER + }; + } + + rpc TestMethod5(ValidNestedRequest) returns (ValidResponse) { + option (gitaly.op_type) = { + op: MUTATOR + target_repository_field: "1.1" + }; + } + + rpc TestMethod6(ValidNestedSharedRequest) returns (ValidResponse) { + option (gitaly.op_type) = { + op: MUTATOR + target_repository_field: "1.1" + }; + } + + rpc TestMethod7(ValidInnerNestedRequest) returns (ValidResponse) { + option (gitaly.op_type) = { + op: MUTATOR + target_repository_field: "1.1" + }; + } } diff -Nru golang-gitaly-proto-1.27.2+dfsg/go/VERSION golang-gitaly-proto-1.37.0+dfsg/go/VERSION --- golang-gitaly-proto-1.27.2+dfsg/go/VERSION 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/go/VERSION 2019-07-11 14:35:16.000000000 +0000 @@ -1 +1 @@ -1.27.2 +1.37.0 diff -Nru golang-gitaly-proto-1.27.2+dfsg/go.mod golang-gitaly-proto-1.37.0+dfsg/go.mod --- golang-gitaly-proto-1.27.2+dfsg/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/go.mod 2019-07-11 14:35:16.000000000 +0000 @@ -0,0 +1 @@ +module gitlab.com/gitlab-org/gitaly-proto diff -Nru golang-gitaly-proto-1.27.2+dfsg/Makefile golang-gitaly-proto-1.37.0+dfsg/Makefile --- golang-gitaly-proto-1.27.2+dfsg/Makefile 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/Makefile 2019-07-11 14:35:16.000000000 +0000 @@ -59,14 +59,14 @@ touch $@ $(PROTOC_GEN_GO): $(TARGET_SETUP) - cd go/internal; go build -o $@ github.com/golang/protobuf/protoc-gen-go + cd go/internal && go build -o $@ github.com/golang/protobuf/protoc-gen-go $(PROTOC_GEN_DOC): $(TARGET_SETUP) - cd go/internal; go build -o $@ github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc + cd go/internal && go build -o $@ github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc $(PROTOC_GEN_GITALY): $(TARGET_SETUP) # Check if test protobuf stubs are stale - cd go/internal; go build -o $@ gitlab.com/gitlab-org/gitaly-proto/go/internal/cmd/protoc-gen-gitaly + cd go/internal && go build -o $@ gitlab.com/gitlab-org/gitaly-proto/go/internal/cmd/protoc-gen-gitaly .PHONY: pb-go-stubs pb-go-stubs: go/gitalypb/*.pb.go @@ -79,7 +79,7 @@ .PHONY: test test: test-go-pkg-opt - cd go/internal; go test ./... + cd go/internal && go test ./... # test-go-pkg-opt checks if the go_package option is specified in all *.proto # files diff -Nru golang-gitaly-proto-1.27.2+dfsg/namespace.proto golang-gitaly-proto-1.37.0+dfsg/namespace.proto --- golang-gitaly-proto-1.27.2+dfsg/namespace.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/namespace.proto 2019-07-11 14:35:16.000000000 +0000 @@ -8,13 +8,22 @@ service NamespaceService { rpc AddNamespace(AddNamespaceRequest) returns (AddNamespaceResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + scope_level: SERVER, + }; } rpc RemoveNamespace(RemoveNamespaceRequest) returns (RemoveNamespaceResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + scope_level: SERVER, + }; } rpc RenameNamespace(RenameNamespaceRequest) returns (RenameNamespaceResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + scope_level: SERVER, + }; } rpc NamespaceExists(NamespaceExistsRequest) returns (NamespaceExistsResponse) { option (op_type).op = ACCESSOR; diff -Nru golang-gitaly-proto-1.27.2+dfsg/notifications.proto golang-gitaly-proto-1.37.0+dfsg/notifications.proto --- golang-gitaly-proto-1.27.2+dfsg/notifications.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/notifications.proto 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -syntax = "proto3"; - -package gitaly; - -option go_package = "gitlab.com/gitlab-org/gitaly-proto/go/gitalypb"; - -import "shared.proto"; - -service NotificationService { - rpc PostReceive(PostReceiveRequest) returns (PostReceiveResponse) { - option (op_type).op = ACCESSOR; - } -} - -message PostReceiveRequest { - Repository repository = 1; -} - -message PostReceiveResponse {} diff -Nru golang-gitaly-proto-1.27.2+dfsg/objectpool.proto golang-gitaly-proto-1.37.0+dfsg/objectpool.proto --- golang-gitaly-proto-1.27.2+dfsg/objectpool.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/objectpool.proto 2019-07-11 14:35:16.000000000 +0000 @@ -8,28 +8,49 @@ service ObjectPoolService { rpc CreateObjectPool(CreateObjectPoolRequest) returns (CreateObjectPoolResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1.1" + }; } rpc DeleteObjectPool(DeleteObjectPoolRequest) returns (DeleteObjectPoolResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1.1" + }; } // Repositories are assumed to be stored on the same disk rpc LinkRepositoryToObjectPool(LinkRepositoryToObjectPoolRequest) returns (LinkRepositoryToObjectPoolResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1.1" + }; } rpc UnlinkRepositoryFromObjectPool(UnlinkRepositoryFromObjectPoolRequest) returns (UnlinkRepositoryFromObjectPoolResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc ReduplicateRepository(ReduplicateRepositoryRequest) returns (ReduplicateRepositoryResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc DisconnectGitAlternates(DisconnectGitAlternatesRequest) returns (DisconnectGitAlternatesResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc FetchIntoObjectPool(FetchIntoObjectPoolRequest) returns (FetchIntoObjectPoolResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } } diff -Nru golang-gitaly-proto-1.27.2+dfsg/operations.proto golang-gitaly-proto-1.37.0+dfsg/operations.proto --- golang-gitaly-proto-1.27.2+dfsg/operations.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/operations.proto 2019-07-11 14:35:16.000000000 +0000 @@ -8,53 +8,101 @@ service OperationService { rpc UserCreateBranch(UserCreateBranchRequest) returns (UserCreateBranchResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc UserUpdateBranch(UserUpdateBranchRequest) returns (UserUpdateBranchResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc UserDeleteBranch(UserDeleteBranchRequest) returns (UserDeleteBranchResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc UserCreateTag(UserCreateTagRequest) returns (UserCreateTagResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc UserDeleteTag(UserDeleteTagRequest) returns (UserDeleteTagResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc UserMergeToRef(UserMergeToRefRequest) returns (UserMergeToRefResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc UserMergeBranch(stream UserMergeBranchRequest) returns (stream UserMergeBranchResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc UserFFBranch(UserFFBranchRequest) returns (UserFFBranchResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc UserCherryPick(UserCherryPickRequest) returns (UserCherryPickResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc UserCommitFiles(stream UserCommitFilesRequest) returns (UserCommitFilesResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1.1" + }; } rpc UserRebase(UserRebaseRequest) returns (UserRebaseResponse) { option deprecated = true; - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc UserRebaseConfirmable(stream UserRebaseConfirmableRequest) returns (stream UserRebaseConfirmableResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1.1" + }; } rpc UserRevert(UserRevertRequest) returns (UserRevertResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc UserSquash(UserSquashRequest) returns (UserSquashResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc UserApplyPatch(stream UserApplyPatchRequest) returns (UserApplyPatchResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1.1" + }; } rpc UserUpdateSubmodule(UserUpdateSubmoduleRequest) returns (UserUpdateSubmoduleResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } } @@ -144,19 +192,18 @@ } message UserMergeToRefRequest { + // UserMergeRef creates a merge commit and updates target_ref to point to that + // new commit. The first parent of the merge commit (the main line) is taken + // from first_parent_ref. The second parent is specified by its commit ID in source_sha. + // If target_ref already exists it will be overwritten. Repository repository = 1; User user = 2; string source_sha = 3; + // branch is deprecated in favor of `first_parent_ref`. bytes branch = 4; - - // The merge of source_sha and branch has target_ref as target. - // - // The target_ref is _always_ overwritten when merging source_sha - // and branch. That is, if a second request comes in, target_ref - // will lose its previous state and be updated to the latest merge - // between source_sha and branch. bytes target_ref = 5; bytes message = 6; + bytes first_parent_ref = 7; } message UserMergeToRefResponse { @@ -256,6 +303,7 @@ bytes start_branch_name = 7; Repository start_repository = 8; bool force = 9; + string start_sha = 10; } message UserCommitFilesRequest { diff -Nru golang-gitaly-proto-1.27.2+dfsg/README.md golang-gitaly-proto-1.37.0+dfsg/README.md --- golang-gitaly-proto-1.27.2+dfsg/README.md 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/README.md 2019-07-11 14:35:16.000000000 +0000 @@ -231,6 +231,27 @@ `--gitaly_out: server.proto: Method ServerInfo missing op_type option` +Additionally, all mutator RPC's require additional annotations to clearly +indicate what is being modified: + +- When an RPC modifies a server-wide resource, the scope should specify `SERVER`. +- When an RPC modifies a specific repository, the scope should specify `REPOSITORY`. + - Additionally, every RPC with `REPOSITORY` scope, should also specify the target repository. + +The target repository represents the location or address of the repository +being modified by the operation. This is needed by Praefect (Gitaly HA) in +order to properly schedule replications to keep repository replicas up to date. + +The target repository annotation specifies where the target repository can be +found in the message. The annotation looks similar to an IP address, but +variable in length (e.g. "1", "1.1", "1.1.1"). Each dot delimited field +represents the field number of how to traverse the protobuf request message to +find the target repository. The target repository **must** be of protobuf +message type `gitaly.Repository`. + +See our examples of [valid](go/internal/linter/testdata/valid.proto) and +[invalid](go/internal/linter/testdata/invalid.proto) proto annotations. + ### Go Package If adding new protobuf files, make sure to correctly set the `go_package` option diff -Nru golang-gitaly-proto-1.27.2+dfsg/ref.proto golang-gitaly-proto-1.37.0+dfsg/ref.proto --- golang-gitaly-proto-1.27.2+dfsg/ref.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/ref.proto 2019-07-11 14:35:16.000000000 +0000 @@ -40,16 +40,25 @@ option (op_type).op = ACCESSOR; } rpc CreateBranch(CreateBranchRequest) returns (CreateBranchResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc DeleteBranch(DeleteBranchRequest) returns (DeleteBranchResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc FindBranch(FindBranchRequest) returns (FindBranchResponse) { option (op_type).op = ACCESSOR; } rpc DeleteRefs(DeleteRefsRequest) returns (DeleteRefsResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc ListBranchNamesContainingCommit(ListBranchNamesContainingCommitRequest) returns (stream ListBranchNamesContainingCommitResponse) { @@ -72,7 +81,10 @@ option (op_type).op = ACCESSOR; } rpc PackRefs(PackRefsRequest) returns (PackRefsResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } } diff -Nru golang-gitaly-proto-1.27.2+dfsg/remote.proto golang-gitaly-proto-1.37.0+dfsg/remote.proto --- golang-gitaly-proto-1.27.2+dfsg/remote.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/remote.proto 2019-07-11 14:35:16.000000000 +0000 @@ -8,17 +8,29 @@ service RemoteService { rpc AddRemote(AddRemoteRequest) returns (AddRemoteResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc FetchInternalRemote(FetchInternalRemoteRequest) returns (FetchInternalRemoteResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc RemoveRemote(RemoveRemoteRequest) returns (RemoveRemoteResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc UpdateRemoteMirror(stream UpdateRemoteMirrorRequest) returns (UpdateRemoteMirrorResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc FindRemoteRepository(FindRemoteRepositoryRequest) returns (FindRemoteRepositoryResponse) { option (op_type).op = ACCESSOR; diff -Nru golang-gitaly-proto-1.27.2+dfsg/repository-service.proto golang-gitaly-proto-1.37.0+dfsg/repository-service.proto --- golang-gitaly-proto-1.27.2+dfsg/repository-service.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/repository-service.proto 2019-07-11 14:35:16.000000000 +0000 @@ -11,46 +11,82 @@ option (op_type).op = ACCESSOR; } rpc RepackIncremental(RepackIncrementalRequest) returns (RepackIncrementalResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc RepackFull(RepackFullRequest) returns (RepackFullResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc GarbageCollect(GarbageCollectRequest) returns (GarbageCollectResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc RepositorySize(RepositorySizeRequest) returns (RepositorySizeResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc ApplyGitattributes(ApplyGitattributesRequest) returns (ApplyGitattributesResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc FetchRemote(FetchRemoteRequest) returns (FetchRemoteResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc CreateRepository(CreateRepositoryRequest) returns (CreateRepositoryResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc GetArchive(GetArchiveRequest) returns (stream GetArchiveResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc HasLocalBranches(HasLocalBranchesRequest) returns (HasLocalBranchesResponse) { option (op_type).op = ACCESSOR; } rpc FetchSourceBranch(FetchSourceBranchRequest) returns (FetchSourceBranchResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc Fsck(FsckRequest) returns (FsckResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc WriteRef(WriteRefRequest) returns (WriteRefResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc FindMergeBase(FindMergeBaseRequest) returns (FindMergeBaseResponse) { option (op_type).op = ACCESSOR; } rpc CreateFork(CreateForkRequest) returns (CreateForkResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc IsRebaseInProgress(IsRebaseInProgressRequest) returns (IsRebaseInProgressResponse) { option (op_type).op = ACCESSOR; @@ -60,22 +96,40 @@ } rpc CreateRepositoryFromURL(CreateRepositoryFromURLRequest) returns (CreateRepositoryFromURLResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc CreateBundle(CreateBundleRequest) returns (stream CreateBundleResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + scope_level: SERVER, + }; } rpc CreateRepositoryFromBundle(stream CreateRepositoryFromBundleRequest) returns (CreateRepositoryFromBundleResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc WriteConfig(WriteConfigRequest) returns (WriteConfigResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc SetConfig(SetConfigRequest) returns (SetConfigResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc DeleteConfig(DeleteConfigRequest) returns (DeleteConfigResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc FindLicense(FindLicenseRequest) returns (FindLicenseResponse) { option (op_type).op = ACCESSOR; @@ -87,13 +141,19 @@ option (op_type).op = ACCESSOR; } rpc Cleanup(CleanupRequest) returns (CleanupResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc GetSnapshot(GetSnapshotRequest) returns (stream GetSnapshotResponse) { option (op_type).op = ACCESSOR; } rpc CreateRepositoryFromSnapshot(CreateRepositoryFromSnapshotRequest) returns (CreateRepositoryFromSnapshotResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc GetRawChanges(GetRawChangesRequest) returns (stream GetRawChangesResponse) { option (op_type).op = ACCESSOR; @@ -105,20 +165,41 @@ option (op_type).op = ACCESSOR; } rpc RestoreCustomHooks(stream RestoreCustomHooksRequest) returns (RestoreCustomHooksResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc BackupCustomHooks(BackupCustomHooksRequest) returns (stream BackupCustomHooksResponse) { option (op_type).op = ACCESSOR; } rpc PreFetch(PreFetchRequest) returns (PreFetchResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc FetchHTTPRemote(FetchHTTPRemoteRequest) returns (FetchHTTPRemoteResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc GetObjectDirectorySize(GetObjectDirectorySizeRequest) returns (GetObjectDirectorySizeResponse) { option (op_type).op = ACCESSOR; } + rpc CloneFromPool(CloneFromPoolRequest) returns (CloneFromPoolResponse) { + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; + } + rpc CloneFromPoolInternal(CloneFromPoolInternalRequest) returns (CloneFromPoolInternalResponse) { + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; + } } message RepositoryExistsRequest { @@ -493,3 +574,21 @@ // Object directory size in kilobytes int64 size = 1; } + +message CloneFromPoolRequest { + Repository repository = 1; + ObjectPool pool = 2; + Remote remote = 3; +} + +message CloneFromPoolResponse { +} + +message CloneFromPoolInternalRequest { + Repository repository = 1; + ObjectPool pool = 2; + Repository source_repository = 3; +} + +message CloneFromPoolInternalResponse { +} \ No newline at end of file diff -Nru golang-gitaly-proto-1.27.2+dfsg/ruby/lib/gitaly/version.rb golang-gitaly-proto-1.37.0+dfsg/ruby/lib/gitaly/version.rb --- golang-gitaly-proto-1.27.2+dfsg/ruby/lib/gitaly/version.rb 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/ruby/lib/gitaly/version.rb 2019-07-11 14:35:16.000000000 +0000 @@ -1,4 +1,4 @@ # This file was auto-generated by ./_support/release module Gitaly - VERSION = "1.27.2" + VERSION = "1.37.0" end diff -Nru golang-gitaly-proto-1.27.2+dfsg/server.proto golang-gitaly-proto-1.37.0+dfsg/server.proto --- golang-gitaly-proto-1.27.2+dfsg/server.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/server.proto 2019-07-11 14:35:16.000000000 +0000 @@ -19,6 +19,8 @@ string storage_name = 1; bool readable = 2; bool writeable = 3; + string fs_type = 4; + string filesystem_id = 5; } string server_version = 1; diff -Nru golang-gitaly-proto-1.27.2+dfsg/shared.proto golang-gitaly-proto-1.37.0+dfsg/shared.proto --- golang-gitaly-proto-1.27.2+dfsg/shared.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/shared.proto 2019-07-11 14:35:16.000000000 +0000 @@ -15,6 +15,31 @@ } Operation op = 1; + + enum Scope { + REPOSITORY = 0; + SERVER = 1; + } + + // Scope level indicates how a mutating RPC affects Gitaly: + // - REPOSITORY: mutation is scoped to only a single repo + // - SERVER: mutation affects the entire server and potentially all repos + Scope scope_level = 2; + + // If this operation modifies a repository, this field will + // specify the location of the Repository field within the + // request message. The field is specified in an OID style + // formatted string. + // + // For example, if the target repository is at the top level + // of a message at field 1, then the string will be "1" + // + // If the target repository is nested deeper in the message, + // then it will be necessary to specify a nested OID string. + // + // For example, the following OID refers to a target repo field + // nested in a one-of field, both at field one: "1.1" + string target_repository_field = 3; } enum ObjectType { diff -Nru golang-gitaly-proto-1.27.2+dfsg/smarthttp.proto golang-gitaly-proto-1.37.0+dfsg/smarthttp.proto --- golang-gitaly-proto-1.27.2+dfsg/smarthttp.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/smarthttp.proto 2019-07-11 14:35:16.000000000 +0000 @@ -8,13 +8,20 @@ service SmartHTTPService { // The response body for GET /info/refs?service=git-upload-pack + // Will be invoked when the user executes a `git fetch`, meaning the server + // will upload the packs to that user. The user doesn't upload new objects. rpc InfoRefsUploadPack(InfoRefsRequest) returns (stream InfoRefsResponse) { option (op_type).op = ACCESSOR; } // The response body for GET /info/refs?service=git-receive-pack + // Will be invoked when the user executes a `git push`, meaning the server + // will receive new objects in the pack from the user. rpc InfoRefsReceivePack(InfoRefsRequest) returns (stream InfoRefsResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } // Request and response body for POST /upload-pack @@ -24,7 +31,10 @@ // Request and response body for POST /receive-pack rpc PostReceivePack(stream PostReceivePackRequest) returns (stream PostReceivePackResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } } diff -Nru golang-gitaly-proto-1.27.2+dfsg/ssh.proto golang-gitaly-proto-1.37.0+dfsg/ssh.proto --- golang-gitaly-proto-1.27.2+dfsg/ssh.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/ssh.proto 2019-07-11 14:35:16.000000000 +0000 @@ -14,12 +14,18 @@ // To forward 'git receive-pack' to Gitaly for SSH sessions rpc SSHReceivePack(stream SSHReceivePackRequest) returns (stream SSHReceivePackResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } // To forward 'git upload-archive' to Gitaly for SSH sessions rpc SSHUploadArchive(stream SSHUploadArchiveRequest) returns (stream SSHUploadArchiveResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } } diff -Nru golang-gitaly-proto-1.27.2+dfsg/storage.proto golang-gitaly-proto-1.37.0+dfsg/storage.proto --- golang-gitaly-proto-1.27.2+dfsg/storage.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/storage.proto 2019-07-11 14:35:16.000000000 +0000 @@ -8,10 +8,16 @@ service StorageService { rpc ListDirectories(ListDirectoriesRequest) returns (stream ListDirectoriesResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + scope_level: SERVER, + }; } rpc DeleteAllRepositories(DeleteAllRepositoriesRequest) returns (DeleteAllRepositoriesResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + scope_level: SERVER, + }; } } diff -Nru golang-gitaly-proto-1.27.2+dfsg/VERSION golang-gitaly-proto-1.37.0+dfsg/VERSION --- golang-gitaly-proto-1.27.2+dfsg/VERSION 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/VERSION 2019-07-11 14:35:16.000000000 +0000 @@ -1 +1 @@ -1.27.2 +1.37.0 diff -Nru golang-gitaly-proto-1.27.2+dfsg/wiki.proto golang-gitaly-proto-1.37.0+dfsg/wiki.proto --- golang-gitaly-proto-1.27.2+dfsg/wiki.proto 2019-06-19 12:20:10.000000000 +0000 +++ golang-gitaly-proto-1.37.0+dfsg/wiki.proto 2019-07-11 14:35:16.000000000 +0000 @@ -11,13 +11,22 @@ option (op_type).op = ACCESSOR; } rpc WikiWritePage(stream WikiWritePageRequest) returns (WikiWritePageResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc WikiUpdatePage(stream WikiUpdatePageRequest) returns (WikiUpdatePageResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } rpc WikiDeletePage(WikiDeletePageRequest) returns (WikiDeletePageResponse) { - option (op_type).op = MUTATOR; + option (op_type) = { + op: MUTATOR + target_repository_field: "1" + }; } // WikiFindPage returns a stream because the page's raw_data field may be arbitrarily large. rpc WikiFindPage(WikiFindPageRequest) returns (stream WikiFindPageResponse) {