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:
authorPatrick Steinhardt <psteinhardt@gitlab.com>2022-03-31 08:03:59 +0300
committerPatrick Steinhardt <psteinhardt@gitlab.com>2022-03-31 08:03:59 +0300
commita32498721df03d6a16731f7aa4ef5143f3fb60d7 (patch)
treedc234e526d18ea27665356f15dfdee8742766861
parent438801e8fdf288fe1629365c455941467776bab2 (diff)
parenta650f42c86d5a1f9e78afffe200b39bb95a89859 (diff)
Merge branch 'pks-proto-introduce-maintenance-operations' into 'master'
proto: Introduce new "maintenance" RPC type Closes #4079 See merge request gitlab-org/gitaly!4399
-rw-r--r--internal/git/gittest/delta_islands.go2
-rw-r--r--internal/gitaly/service/ref/pack_refs_test.go22
-rw-r--r--internal/gitaly/service/repository/cleanup_test.go33
-rw-r--r--internal/gitaly/service/repository/commit_graph_test.go26
-rw-r--r--internal/gitaly/service/repository/gc_test.go77
-rw-r--r--internal/gitaly/service/repository/midx_test.go31
-rw-r--r--internal/gitaly/service/repository/optimize_test.go23
-rw-r--r--internal/gitaly/service/repository/prune_unreachable_objects_test.go9
-rw-r--r--internal/gitaly/service/repository/repack_test.go65
-rw-r--r--internal/metadata/featureflag/ff_maintenance_operation_routing.go4
-rw-r--r--internal/middleware/cache/cache.go20
-rw-r--r--internal/middleware/cache/cache_test.go26
-rw-r--r--internal/middleware/cache/prometheus.go2
-rw-r--r--internal/middleware/cache/testdata/stream.pb.go64
-rw-r--r--internal/middleware/cache/testdata/stream.proto12
-rw-r--r--internal/middleware/cache/testdata/stream_grpc.pb.go99
-rw-r--r--internal/praefect/coordinator.go90
-rw-r--r--internal/praefect/coordinator_test.go205
-rw-r--r--internal/praefect/middleware/methodtype.go2
-rw-r--r--internal/praefect/mock/mock.pb.go27
-rw-r--r--internal/praefect/mock/mock.proto8
-rw-r--r--internal/praefect/mock/mock_grpc.pb.go38
-rw-r--r--internal/praefect/protoregistry/protoregistry.go6
-rw-r--r--internal/praefect/protoregistry/protoregistry_test.go14
-rw-r--r--internal/praefect/replicator_test.go38
-rw-r--r--internal/praefect/router.go15
-rw-r--r--internal/praefect/router_node_manager.go31
-rw-r--r--internal/praefect/router_per_repository.go53
-rw-r--r--internal/praefect/router_per_repository_test.go213
-rw-r--r--proto/go/gitalypb/lint.pb.go100
-rw-r--r--proto/go/gitalypb/ref.pb.go2
-rw-r--r--proto/go/gitalypb/repository-service.pb.go16
-rw-r--r--proto/go/internal/linter/lint.go3
-rw-r--r--proto/go/internal/linter/lint_test.go8
-rw-r--r--proto/go/internal/linter/method.go11
-rw-r--r--proto/go/internal/linter/testdata/invalid.pb.go119
-rw-r--r--proto/go/internal/linter/testdata/invalid.proto46
-rw-r--r--proto/go/internal/linter/testdata/invalid_grpc.pb.go288
-rw-r--r--proto/go/internal/linter/testdata/valid.pb.go76
-rw-r--r--proto/go/internal/linter/testdata/valid.proto32
-rw-r--r--proto/go/internal/linter/testdata/valid_grpc.pb.go180
-rw-r--r--proto/lint.proto1
-rw-r--r--proto/ref.proto2
-rw-r--r--proto/repository-service.proto16
-rw-r--r--ruby/proto/gitaly/lint_pb.rb1
45 files changed, 1927 insertions, 229 deletions
diff --git a/internal/git/gittest/delta_islands.go b/internal/git/gittest/delta_islands.go
index 286e40389..23f2e8884 100644
--- a/internal/git/gittest/delta_islands.go
+++ b/internal/git/gittest/delta_islands.go
@@ -15,6 +15,8 @@ import (
// TestDeltaIslands is based on the tests in
// https://github.com/git/git/blob/master/t/t5320-delta-islands.sh .
func TestDeltaIslands(t *testing.T, cfg config.Cfg, repoPath string, repack func() error) {
+ t.Helper()
+
// Create blobs that we expect Git to use delta compression on.
blob1, err := io.ReadAll(io.LimitReader(rand.Reader, 100000))
require.NoError(t, err)
diff --git a/internal/gitaly/service/ref/pack_refs_test.go b/internal/gitaly/service/ref/pack_refs_test.go
index f16aa8175..e6da2b733 100644
--- a/internal/gitaly/service/ref/pack_refs_test.go
+++ b/internal/gitaly/service/ref/pack_refs_test.go
@@ -2,6 +2,7 @@ package ref
import (
"bufio"
+ "context"
"fmt"
"os"
"path/filepath"
@@ -13,6 +14,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v14/internal/git"
"gitlab.com/gitlab-org/gitaly/v14/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v14/internal/git/localrepo"
+ "gitlab.com/gitlab-org/gitaly/v14/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
"google.golang.org/grpc/codes"
@@ -20,7 +22,12 @@ import (
)
func TestPackRefsSuccessfulRequest(t *testing.T) {
- ctx := testhelper.Context(t)
+ t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testPackRefsSuccessfulRequest)
+}
+
+func testPackRefsSuccessfulRequest(t *testing.T, ctx context.Context) {
+ t.Parallel()
cfg, repoProto, repoPath, client := setupRefService(ctx, t)
@@ -67,9 +74,19 @@ func linesInPackfile(t *testing.T, repoPath string) int {
func TestPackRefs_invalidRequest(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testPackRefsInvalidRequest)
+}
+
+func testPackRefsInvalidRequest(t *testing.T, ctx context.Context) {
+ t.Parallel()
cfg, client := setupRefServiceWithoutRepo(t)
+ praefectErr := `mutator call: route repository mutator: get repository id: repository "default"/"bar" not found`
+ if featureflag.MaintenanceOperationRouting.IsEnabled(ctx) {
+ praefectErr = `routing repository maintenance: getting repository metadata: repository not found`
+ }
+
tests := []struct {
repo *gitalypb.Repository
err error
@@ -92,7 +109,7 @@ func TestPackRefs_invalidRequest(t *testing.T) {
codes.NotFound,
gitalyOrPraefect(
fmt.Sprintf(`GetRepoPath: not a git repository: "%s/bar"`, cfg.Storages[0].Path),
- `mutator call: route repository mutator: get repository id: repository "default"/"bar" not found`,
+ praefectErr,
),
),
},
@@ -100,7 +117,6 @@ func TestPackRefs_invalidRequest(t *testing.T) {
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
- ctx := testhelper.Context(t)
//nolint:staticcheck
_, err := client.PackRefs(ctx, &gitalypb.PackRefsRequest{Repository: tc.repo})
testhelper.RequireGrpcError(t, err, tc.err)
diff --git a/internal/gitaly/service/repository/cleanup_test.go b/internal/gitaly/service/repository/cleanup_test.go
index 1802fee12..50fc670ce 100644
--- a/internal/gitaly/service/repository/cleanup_test.go
+++ b/internal/gitaly/service/repository/cleanup_test.go
@@ -1,6 +1,7 @@
package repository
import (
+ "context"
"fmt"
"os"
"path/filepath"
@@ -10,6 +11,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v14/internal/git/gittest"
+ "gitlab.com/gitlab-org/gitaly/v14/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
"google.golang.org/grpc/codes"
@@ -24,6 +26,11 @@ const (
// https://gitlab.com/gitlab-org/gitaly/issues/1750
func TestCleanupDeletesStaleWorktrees(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testCleanupDeletesStaleWorktrees)
+}
+
+func testCleanupDeletesStaleWorktrees(t *testing.T, ctx context.Context) {
+ t.Parallel()
cfg, client := setupRepositoryServiceWithoutRepo(t)
testCases := []struct {
@@ -50,7 +57,6 @@ func TestCleanupDeletesStaleWorktrees(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
- ctx := testhelper.Context(t)
repo, repoPath := gittest.CreateRepository(ctx, t, cfg, gittest.CreateRepositoryConfig{
Seed: gittest.SeedGitLabTest,
})
@@ -86,8 +92,12 @@ func TestCleanupDeletesStaleWorktrees(t *testing.T) {
func TestCleanupDeletesOrphanedWorktrees(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testCleanupDeletesOrphanedWorktrees)
+}
+
+func testCleanupDeletesOrphanedWorktrees(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
_, repo, repoPath, client := setupRepositoryService(ctx, t)
worktreeCheckoutPath := filepath.Join(repoPath, worktreePrefix, "test-worktree")
@@ -110,12 +120,16 @@ func TestCleanupDeletesOrphanedWorktrees(t *testing.T) {
// https://gitlab.com/gitlab-org/gitaly/issues/1750
func TestCleanupDisconnectedWorktrees(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testCleanupDisconnectedWorktrees)
+}
+
+func testCleanupDisconnectedWorktrees(t *testing.T, ctx context.Context) {
+ t.Parallel()
const (
worktreeName = "test-worktree"
worktreeAdminDir = "worktrees"
)
- ctx := testhelper.Context(t)
cfg, repo, repoPath, client := setupRepositoryService(ctx, t)
worktreePath := filepath.Join(repoPath, worktreePrefix, worktreeName)
@@ -151,10 +165,19 @@ func TestCleanupDisconnectedWorktrees(t *testing.T) {
func TestCleanup_invalidRequest(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testCleanupInvalidRequest)
+}
+
+func testCleanupInvalidRequest(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
cfg, client := setupRepositoryServiceWithoutRepo(t)
+ praefectErr := `mutator call: route repository mutator: get repository id: repository "default"/"so/me/some.git" not found`
+ if featureflag.MaintenanceOperationRouting.IsEnabled(ctx) {
+ praefectErr = `routing repository maintenance: getting repository metadata: repository not found`
+ }
+
for _, tc := range []struct {
desc string
in *gitalypb.Repository
@@ -176,7 +199,7 @@ func TestCleanup_invalidRequest(t *testing.T) {
codes.NotFound,
gitalyOrPraefect(
fmt.Sprintf(`GetRepoPath: not a git repository: %q`, filepath.Join(cfg.Storages[0].Path, "so/me/some.git")),
- `mutator call: route repository mutator: get repository id: repository "default"/"so/me/some.git" not found`,
+ praefectErr,
),
),
},
diff --git a/internal/gitaly/service/repository/commit_graph_test.go b/internal/gitaly/service/repository/commit_graph_test.go
index c55c64665..b50f520dd 100644
--- a/internal/gitaly/service/repository/commit_graph_test.go
+++ b/internal/gitaly/service/repository/commit_graph_test.go
@@ -2,6 +2,7 @@ package repository
import (
"bytes"
+ "context"
"fmt"
"os"
"path/filepath"
@@ -11,6 +12,7 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v14/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v14/internal/git/stats"
+ "gitlab.com/gitlab-org/gitaly/v14/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper/testserver"
"gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
@@ -20,8 +22,12 @@ import (
func TestWriteCommitGraph_withExistingCommitGraphCreatedWithDefaults(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testWriteCommitGraphWithExistingCommitGraphCreatedWithDefaults)
+}
+
+func testWriteCommitGraphWithExistingCommitGraphCreatedWithDefaults(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
cfg, repo, repoPath, client := setupRepositoryService(ctx, t)
commitGraphPath := filepath.Join(repoPath, stats.CommitGraphRelPath)
@@ -58,8 +64,12 @@ func TestWriteCommitGraph_withExistingCommitGraphCreatedWithDefaults(t *testing.
func TestWriteCommitGraph_withExistingCommitGraphCreatedWithSplit(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testWriteCommitGraphWithExistingCommitGraphCreatedWithSplit)
+}
+
+func testWriteCommitGraphWithExistingCommitGraphCreatedWithSplit(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
cfg, repo, repoPath, client := setupRepositoryService(ctx, t)
commitGraphPath := filepath.Join(repoPath, stats.CommitGraphRelPath)
@@ -96,8 +106,12 @@ func TestWriteCommitGraph_withExistingCommitGraphCreatedWithSplit(t *testing.T)
func TestWriteCommitGraph(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testWriteCommitGraph)
+}
+
+func testWriteCommitGraph(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
_, repo, repoPath, client := setupRepositoryService(ctx, t)
chainPath := filepath.Join(repoPath, stats.CommitGraphChainRelPath)
@@ -160,8 +174,12 @@ func TestWriteCommitGraph_validationChecks(t *testing.T) {
func TestUpdateCommitGraph(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testUpdateCommitGraph)
+}
+
+func testUpdateCommitGraph(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
cfg, repo, repoPath, client := setupRepositoryService(ctx, t)
chainPath := filepath.Join(repoPath, stats.CommitGraphChainRelPath)
diff --git a/internal/gitaly/service/repository/gc_test.go b/internal/gitaly/service/repository/gc_test.go
index 2849a12fb..3308110bd 100644
--- a/internal/gitaly/service/repository/gc_test.go
+++ b/internal/gitaly/service/repository/gc_test.go
@@ -1,6 +1,7 @@
package repository
import (
+ "context"
"fmt"
"os"
"path/filepath"
@@ -15,6 +16,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v14/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v14/internal/git/stats"
"gitlab.com/gitlab-org/gitaly/v14/internal/helper/text"
+ "gitlab.com/gitlab-org/gitaly/v14/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper/testserver"
"gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
@@ -30,8 +32,12 @@ var (
func TestGarbageCollectCommitGraph(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testGarbageCollectCommitGraph)
+}
+
+func testGarbageCollectCommitGraph(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
_, repo, repoPath, client := setupRepositoryService(ctx, t)
//nolint:staticcheck
@@ -45,8 +51,12 @@ func TestGarbageCollectCommitGraph(t *testing.T) {
func TestGarbageCollectSuccess(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testGarbageCollectSuccess)
+}
+
+func testGarbageCollectSuccess(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
_, repo, repoPath, client := setupRepositoryService(ctx, t)
tests := []struct {
@@ -98,7 +108,11 @@ func TestGarbageCollectSuccess(t *testing.T) {
func TestGarbageCollectWithPrune(t *testing.T) {
t.Parallel()
- ctx := testhelper.Context(t)
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testGarbageCollectWithPrune)
+}
+
+func testGarbageCollectWithPrune(t *testing.T, ctx context.Context) {
+ t.Parallel()
cfg, repo, repoPath, client := setupRepositoryService(ctx, t)
@@ -110,7 +124,7 @@ func TestGarbageCollectWithPrune(t *testing.T) {
// create a reference to the blob, so it should not be removed by gc
gittest.WriteCommit(t, cfg, repoPath,
gittest.WithTreeEntries(gittest.TreeEntry{
- OID: git.ObjectID(blobHashes[2]), Path: t.Name(), Mode: "100644",
+ OID: git.ObjectID(blobHashes[2]), Path: "blob-name", Mode: "100644",
}),
)
@@ -141,7 +155,11 @@ func TestGarbageCollectWithPrune(t *testing.T) {
func TestGarbageCollectLogStatistics(t *testing.T) {
t.Parallel()
- ctx := testhelper.Context(t)
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testGarbageCollectLogStatistics)
+}
+
+func testGarbageCollectLogStatistics(t *testing.T, ctx context.Context) {
+ t.Parallel()
logger, hook := test.NewNullLogger()
_, repo, _, client := setupRepositoryService(ctx, t, testserver.WithLogger(logger))
@@ -155,8 +173,12 @@ func TestGarbageCollectLogStatistics(t *testing.T) {
func TestGarbageCollectDeletesRefsLocks(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testGarbageCollectDeletesRefsLocks)
+}
+
+func testGarbageCollectDeletesRefsLocks(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
_, repo, repoPath, client := setupRepositoryService(ctx, t)
req := &gitalypb.GarbageCollectRequest{Repository: repo}
@@ -197,6 +219,11 @@ func TestGarbageCollectDeletesRefsLocks(t *testing.T) {
func TestGarbageCollectDeletesPackedRefsLock(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testGarbageCollectDeletesPackedRefsLock)
+}
+
+func testGarbageCollectDeletesPackedRefsLock(t *testing.T, ctx context.Context) {
+ t.Parallel()
cfg, client := setupRepositoryServiceWithoutRepo(t)
testCases := []struct {
@@ -223,7 +250,6 @@ func TestGarbageCollectDeletesPackedRefsLock(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
- ctx := testhelper.Context(t)
repo, repoPath := gittest.CreateRepository(ctx, t, cfg, gittest.CreateRepositoryConfig{
Seed: gittest.SeedGitLabTest,
})
@@ -264,8 +290,12 @@ func TestGarbageCollectDeletesPackedRefsLock(t *testing.T) {
func TestGarbageCollectDeletesFileLocks(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testGarbageCollectDeletesFileLocks)
+}
+
+func testGarbageCollectDeletesFileLocks(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
_, repo, repoPath, client := setupRepositoryService(ctx, t)
req := &gitalypb.GarbageCollectRequest{Repository: repo}
@@ -301,6 +331,11 @@ func TestGarbageCollectDeletesFileLocks(t *testing.T) {
func TestGarbageCollectDeletesPackedRefsNew(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testGarbageCollectDeletesPackedRefsNew)
+}
+
+func testGarbageCollectDeletesPackedRefsNew(t *testing.T, ctx context.Context) {
+ t.Parallel()
cfg, client := setupRepositoryServiceWithoutRepo(t)
testCases := []struct {
@@ -326,7 +361,6 @@ func TestGarbageCollectDeletesPackedRefsNew(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
- ctx := testhelper.Context(t)
repo, repoPath := gittest.CreateRepository(ctx, t, cfg)
req := &gitalypb.GarbageCollectRequest{Repository: repo}
@@ -356,11 +390,20 @@ func TestGarbageCollectDeletesPackedRefsNew(t *testing.T) {
func TestGarbageCollectFailure(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testGarbageCollectFailure)
+}
+
+func testGarbageCollectFailure(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
_, repo, repoPath, client := setupRepositoryService(ctx, t)
storagePath := strings.TrimSuffix(repoPath, "/"+repo.RelativePath)
+ praefectErr := `mutator call: route repository mutator: get repository id: repository "default"/"bar" not found`
+ if featureflag.MaintenanceOperationRouting.IsEnabled(ctx) {
+ praefectErr = `routing repository maintenance: getting repository metadata: repository not found`
+ }
+
tests := []struct {
repo *gitalypb.Repository
err error
@@ -379,7 +422,7 @@ func TestGarbageCollectFailure(t *testing.T) {
codes.NotFound,
gitalyOrPraefect(
fmt.Sprintf(`GetRepoPath: not a git repository: "%s/bar"`, storagePath),
- `mutator call: route repository mutator: get repository id: repository "default"/"bar" not found`,
+ praefectErr,
),
),
},
@@ -396,8 +439,12 @@ func TestGarbageCollectFailure(t *testing.T) {
func TestCleanupInvalidKeepAroundRefs(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testCleanupInvalidKeepAroundRefs)
+}
+
+func testCleanupInvalidKeepAroundRefs(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
cfg, repo, repoPath, client := setupRepositoryService(ctx, t)
// Make the directory, so we can create random reflike things in it
@@ -491,8 +538,12 @@ func mustCreateFileWithTimes(t testing.TB, path string, mTime time.Time) {
func TestGarbageCollectDeltaIslands(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testGarbageCollectDeltaIslands)
+}
+
+func testGarbageCollectDeltaIslands(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
cfg, repo, repoPath, client := setupRepositoryService(ctx, t)
gittest.TestDeltaIslands(t, cfg, repoPath, func() error {
diff --git a/internal/gitaly/service/repository/midx_test.go b/internal/gitaly/service/repository/midx_test.go
index 984f4ee44..d0bea2ca0 100644
--- a/internal/gitaly/service/repository/midx_test.go
+++ b/internal/gitaly/service/repository/midx_test.go
@@ -17,6 +17,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/transaction"
"gitlab.com/gitlab-org/gitaly/v14/internal/helper/text"
"gitlab.com/gitlab-org/gitaly/v14/internal/metadata"
+ "gitlab.com/gitlab-org/gitaly/v14/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper/testserver"
"gitlab.com/gitlab-org/gitaly/v14/internal/transaction/txinfo"
@@ -28,8 +29,12 @@ import (
func TestMidxWrite(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testMidxWrite)
+}
+
+func testMidxWrite(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
cfg, repo, repoPath, client := setupRepositoryService(ctx, t)
//nolint:staticcheck
@@ -47,8 +52,12 @@ func TestMidxWrite(t *testing.T) {
func TestMidxRewrite(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testMidxRewrite)
+}
+
+func testMidxRewrite(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
_, repo, repoPath, client := setupRepositoryService(ctx, t)
midxPath := filepath.Join(repoPath, MidxRelPath)
@@ -75,8 +84,12 @@ func TestMidxRewrite(t *testing.T) {
func TestMidxRepack(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testMidxRepack)
+}
+
+func testMidxRepack(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
cfg, repo, repoPath, client := setupRepositoryService(ctx, t)
// add some pack files with different sizes
@@ -115,7 +128,11 @@ func TestMidxRepack(t *testing.T) {
func TestMidxRepack_transactional(t *testing.T) {
t.Parallel()
- ctx := testhelper.Context(t)
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testMidxRepackTransactional)
+}
+
+func testMidxRepackTransactional(t *testing.T, ctx context.Context) {
+ t.Parallel()
txManager := transaction.NewTrackingManager()
@@ -145,12 +162,16 @@ func TestMidxRepack_transactional(t *testing.T) {
func TestMidxRepackExpire(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testMidxRepackExpire)
+}
+
+func testMidxRepackExpire(t *testing.T, ctx context.Context) {
+ t.Parallel()
cfg, client := setupRepositoryServiceWithoutRepo(t)
for _, packsAdded := range []int{3, 5, 11, 20} {
t.Run(fmt.Sprintf("Test repack expire with %d added packs", packsAdded),
func(t *testing.T) {
- ctx := testhelper.Context(t)
repo, repoPath := gittest.CreateRepository(ctx, t, cfg, gittest.CreateRepositoryConfig{
Seed: gittest.SeedGitLabTest,
})
diff --git a/internal/gitaly/service/repository/optimize_test.go b/internal/gitaly/service/repository/optimize_test.go
index a843b5668..4c63c3972 100644
--- a/internal/gitaly/service/repository/optimize_test.go
+++ b/internal/gitaly/service/repository/optimize_test.go
@@ -2,6 +2,7 @@ package repository
import (
"bytes"
+ "context"
"fmt"
"os"
"path/filepath"
@@ -13,6 +14,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v14/internal/git"
"gitlab.com/gitlab-org/gitaly/v14/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v14/internal/git/stats"
+ "gitlab.com/gitlab-org/gitaly/v14/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
"google.golang.org/grpc/codes"
@@ -43,8 +45,12 @@ func getNewestPackfileModtime(t *testing.T, repoPath string) time.Time {
func TestOptimizeRepository(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testOptimizeRepository)
+}
+
+func testOptimizeRepository(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
cfg, repoProto, repoPath, client := setupRepositoryService(ctx, t)
gittest.Exec(t, cfg, "-C", repoPath, "repack", "-A", "-b")
@@ -157,10 +163,19 @@ func TestOptimizeRepository(t *testing.T) {
func TestOptimizeRepositoryValidation(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testOptimizeRepositoryValidation)
+}
+
+func testOptimizeRepositoryValidation(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
cfg, repo, _, client := setupRepositoryService(ctx, t)
+ praefectErr := `mutator call: route repository mutator: get repository id: repository "default"/"path/not/exist" not found`
+ if featureflag.MaintenanceOperationRouting.IsEnabled(ctx) {
+ praefectErr = `routing repository maintenance: getting repository metadata: repository not found`
+ }
+
testCases := []struct {
desc string
repo *gitalypb.Repository
@@ -183,7 +198,7 @@ func TestOptimizeRepositoryValidation(t *testing.T) {
codes.NotFound,
gitalyOrPraefect(
fmt.Sprintf(`GetRepoPath: not a git repository: "%s/path/not/exist"`, cfg.Storages[0].Path),
- `mutator call: route repository mutator: get repository id: repository "default"/"path/not/exist" not found`,
+ praefectErr,
),
),
},
@@ -193,7 +208,7 @@ func TestOptimizeRepositoryValidation(t *testing.T) {
t.Run(tc.desc, func(t *testing.T) {
_, err := client.OptimizeRepository(ctx, &gitalypb.OptimizeRepositoryRequest{Repository: tc.repo})
require.Error(t, err)
- testhelper.RequireGrpcError(t, err, tc.exp)
+ testhelper.RequireGrpcError(t, tc.exp, err)
})
}
diff --git a/internal/gitaly/service/repository/prune_unreachable_objects_test.go b/internal/gitaly/service/repository/prune_unreachable_objects_test.go
index 3d1d6c1f8..b02aa224e 100644
--- a/internal/gitaly/service/repository/prune_unreachable_objects_test.go
+++ b/internal/gitaly/service/repository/prune_unreachable_objects_test.go
@@ -1,6 +1,7 @@
package repository
import (
+ "context"
"os"
"path/filepath"
"testing"
@@ -10,12 +11,18 @@ import (
"gitlab.com/gitlab-org/gitaly/v14/internal/git"
"gitlab.com/gitlab-org/gitaly/v14/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v14/internal/helper"
+ "gitlab.com/gitlab-org/gitaly/v14/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
)
func TestPruneUnreachableObjects(t *testing.T) {
- ctx := testhelper.Context(t)
+ t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testPruneUnreachableObjects)
+}
+
+func testPruneUnreachableObjects(t *testing.T, ctx context.Context) {
+ t.Parallel()
cfg, client := setupRepositoryServiceWithoutRepo(t)
diff --git a/internal/gitaly/service/repository/repack_test.go b/internal/gitaly/service/repository/repack_test.go
index d7efb78dc..244e23077 100644
--- a/internal/gitaly/service/repository/repack_test.go
+++ b/internal/gitaly/service/repository/repack_test.go
@@ -1,6 +1,7 @@
package repository
import (
+ "context"
"fmt"
"path/filepath"
"testing"
@@ -12,6 +13,7 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v14/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v14/internal/git/stats"
+ "gitlab.com/gitlab-org/gitaly/v14/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper/testserver"
"gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
@@ -21,8 +23,12 @@ import (
func TestRepackIncrementalSuccess(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testRepackIncrementalSuccess)
+}
+
+func testRepackIncrementalSuccess(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
_, repo, repoPath, client := setupRepositoryService(ctx, t)
packPath := filepath.Join(repoPath, "objects", "pack")
@@ -48,7 +54,11 @@ func TestRepackIncrementalSuccess(t *testing.T) {
func TestRepackIncrementalCollectLogStatistics(t *testing.T) {
t.Parallel()
- ctx := testhelper.Context(t)
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testRepackIncrementalCollectLogStatistics)
+}
+
+func testRepackIncrementalCollectLogStatistics(t *testing.T, ctx context.Context) {
+ t.Parallel()
logger, hook := test.NewNullLogger()
_, repo, _, client := setupRepositoryService(ctx, t, testserver.WithLogger(logger))
@@ -62,8 +72,12 @@ func TestRepackIncrementalCollectLogStatistics(t *testing.T) {
func TestRepackLocal(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testRepackLocal)
+}
+
+func testRepackLocal(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
cfg, repo, repoPath, client := setupRepositoryService(ctx, t)
altObjectsDir := "./alt-objects"
@@ -99,8 +113,18 @@ func TestRepackLocal(t *testing.T) {
func TestRepackIncrementalFailure(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testRepackIncrementalFailure)
+}
+
+func testRepackIncrementalFailure(t *testing.T, ctx context.Context) {
+ t.Parallel()
cfg, client := setupRepositoryServiceWithoutRepo(t)
+ praefectErr := `mutator call: route repository mutator: get repository id: repository "default"/"bar" not found`
+ if featureflag.MaintenanceOperationRouting.IsEnabled(ctx) {
+ praefectErr = `routing repository maintenance: getting repository metadata: repository not found`
+ }
+
tests := []struct {
repo *gitalypb.Repository
err error
@@ -128,7 +152,7 @@ func TestRepackIncrementalFailure(t *testing.T) {
codes.NotFound,
gitalyOrPraefect(
fmt.Sprintf(`GetRepoPath: not a git repository: "%s/bar"`, cfg.Storages[0].Path),
- `mutator call: route repository mutator: get repository id: repository "default"/"bar" not found`,
+ praefectErr,
),
),
},
@@ -136,7 +160,6 @@ func TestRepackIncrementalFailure(t *testing.T) {
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
- ctx := testhelper.Context(t)
//nolint:staticcheck
_, err := client.RepackIncremental(ctx, &gitalypb.RepackIncrementalRequest{Repository: tc.repo})
testhelper.RequireGrpcError(t, err, tc.err)
@@ -146,6 +169,11 @@ func TestRepackIncrementalFailure(t *testing.T) {
func TestRepackFullSuccess(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testRepackFullSuccess)
+}
+
+func testRepackFullSuccess(t *testing.T, ctx context.Context) {
+ t.Parallel()
cfg, client := setupRepositoryServiceWithoutRepo(t)
tests := []struct {
@@ -158,8 +186,6 @@ func TestRepackFullSuccess(t *testing.T) {
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
- ctx := testhelper.Context(t)
-
var repoPath string
test.req.Repository, repoPath = gittest.CreateRepository(ctx, t, cfg, gittest.CreateRepositoryConfig{
Seed: gittest.SeedGitLabTest,
@@ -202,7 +228,11 @@ func TestRepackFullSuccess(t *testing.T) {
func TestRepackFullCollectLogStatistics(t *testing.T) {
t.Parallel()
- ctx := testhelper.Context(t)
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testRepackFullCollectLogStatistics)
+}
+
+func testRepackFullCollectLogStatistics(t *testing.T, ctx context.Context) {
+ t.Parallel()
logger, hook := test.NewNullLogger()
_, repo, _, client := setupRepositoryService(ctx, t, testserver.WithLogger(logger))
@@ -243,8 +273,18 @@ func doBitmapsContainHashCache(t *testing.T, bitmapPaths []string) {
func TestRepackFullFailure(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testRepackFullFailure)
+}
+
+func testRepackFullFailure(t *testing.T, ctx context.Context) {
+ t.Parallel()
cfg, client := setupRepositoryServiceWithoutRepo(t)
+ praefectErr := `mutator call: route repository mutator: get repository id: repository "default"/"bar" not found`
+ if featureflag.MaintenanceOperationRouting.IsEnabled(ctx) {
+ praefectErr = `routing repository maintenance: getting repository metadata: repository not found`
+ }
+
tests := []struct {
desc string
repo *gitalypb.Repository
@@ -272,7 +312,7 @@ func TestRepackFullFailure(t *testing.T) {
codes.NotFound,
gitalyOrPraefect(
fmt.Sprintf(`GetRepoPath: not a git repository: "%s/bar"`, cfg.Storages[0].Path),
- `mutator call: route repository mutator: get repository id: repository "default"/"bar" not found`,
+ praefectErr,
),
),
},
@@ -280,7 +320,6 @@ func TestRepackFullFailure(t *testing.T) {
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
- ctx := testhelper.Context(t)
//nolint:staticcheck
_, err := client.RepackFull(ctx, &gitalypb.RepackFullRequest{Repository: tc.repo})
testhelper.RequireGrpcError(t, err, tc.err)
@@ -290,8 +329,12 @@ func TestRepackFullFailure(t *testing.T) {
func TestRepackFullDeltaIslands(t *testing.T) {
t.Parallel()
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testRepackFullDeltaIslands)
+}
+
+func testRepackFullDeltaIslands(t *testing.T, ctx context.Context) {
+ t.Parallel()
- ctx := testhelper.Context(t)
cfg, repo, repoPath, client := setupRepositoryService(ctx, t)
gittest.TestDeltaIslands(t, cfg, repoPath, func() error {
diff --git a/internal/metadata/featureflag/ff_maintenance_operation_routing.go b/internal/metadata/featureflag/ff_maintenance_operation_routing.go
new file mode 100644
index 000000000..9f108af9c
--- /dev/null
+++ b/internal/metadata/featureflag/ff_maintenance_operation_routing.go
@@ -0,0 +1,4 @@
+package featureflag
+
+// MaintenanceOperationRouting enables routing logic that is specific to maintenance operations.
+var MaintenanceOperationRouting = NewFeatureFlag("maintenance_operation_routing", false)
diff --git a/internal/middleware/cache/cache.go b/internal/middleware/cache/cache.go
index 6634fcbfa..aed1c74e1 100644
--- a/internal/middleware/cache/cache.go
+++ b/internal/middleware/cache/cache.go
@@ -24,6 +24,22 @@ func shouldIgnore(reg *protoregistry.Registry, fullMethod string) bool {
return strings.HasPrefix(fullMethod, "/grpc.health") || reg.IsInterceptedMethod(fullMethod)
}
+func shouldInvalidate(mi protoregistry.MethodInfo) bool {
+ if mi.Scope != protoregistry.ScopeRepository {
+ return false
+ }
+
+ if mi.Operation == protoregistry.OpAccessor {
+ return false
+ }
+
+ if mi.Operation == protoregistry.OpMaintenance {
+ return false
+ }
+
+ return true
+}
+
// StreamInvalidator will invalidate any mutating RPC that targets a
// repository in a gRPC stream based RPC
func StreamInvalidator(ci diskcache.Invalidator, reg *protoregistry.Registry) grpc.StreamServerInterceptor {
@@ -41,7 +57,7 @@ func StreamInvalidator(ci diskcache.Invalidator, reg *protoregistry.Registry) gr
return handler(srv, ss)
}
- if mInfo.Scope != protoregistry.ScopeRepository || mInfo.Operation == protoregistry.OpAccessor {
+ if !shouldInvalidate(mInfo) {
return handler(srv, ss)
}
@@ -68,7 +84,7 @@ func UnaryInvalidator(ci diskcache.Invalidator, reg *protoregistry.Registry) grp
return handler(ctx, req)
}
- if mInfo.Scope != protoregistry.ScopeRepository || mInfo.Operation == protoregistry.OpAccessor {
+ if !shouldInvalidate(mInfo) {
return handler(ctx, req)
}
diff --git a/internal/middleware/cache/cache_test.go b/internal/middleware/cache/cache_test.go
index 9a271efb1..b23a5b2be 100644
--- a/internal/middleware/cache/cache_test.go
+++ b/internal/middleware/cache/cache_test.go
@@ -70,7 +70,7 @@ func TestInvalidators(t *testing.T) {
StorageName: "3",
}
- expectedSvcRequests := []*gitalypb.Repository{repo1, repo2, repo3, repo1, repo2}
+ expectedSvcRequests := []*gitalypb.Repository{repo1, repo1, repo2, repo3, repo1, repo2, repo2}
expectedInvalidations := []*gitalypb.Repository{repo2, repo3, repo1}
// Should NOT trigger cache invalidation
@@ -81,6 +81,14 @@ func TestInvalidators(t *testing.T) {
_, err = c.Recv() // make client call synchronous by waiting for close
assert.Equal(t, err, io.EOF)
+ // Should NOT trigger cache invalidation
+ c, err = cli.ClientStreamRepoMaintainer(ctx, &testdata.Request{
+ Destination: repo1,
+ })
+ assert.NoError(t, err)
+ _, err = c.Recv() // make client call synchronous by waiting for close
+ assert.Equal(t, err, io.EOF)
+
// Should trigger cache invalidation
c, err = cli.ClientStreamRepoMutator(ctx, &testdata.Request{
Destination: repo2,
@@ -109,6 +117,12 @@ func TestInvalidators(t *testing.T) {
})
require.NoError(t, err)
+ // Should NOT trigger cache invalidation
+ _, err = cli.ClientUnaryRepoMaintainer(ctx, &testdata.Request{
+ Destination: repo2,
+ })
+ require.NoError(t, err)
+
// Health checks should NOT trigger cache invalidation
hcr := &grpc_health_v1.HealthCheckRequest{Service: "TestService"}
_, err = grpc_health_v1.NewHealthClient(cc).Check(ctx, hcr)
@@ -203,6 +217,11 @@ func (ts *testSvc) ClientStreamRepoAccessor(req *testdata.Request, _ testdata.Te
return nil
}
+func (ts *testSvc) ClientStreamRepoMaintainer(req *testdata.Request, _ testdata.TestService_ClientStreamRepoMaintainerServer) error {
+ ts.repoRequests = append(ts.repoRequests, req.GetDestination())
+ return nil
+}
+
func (ts *testSvc) ClientUnaryRepoMutator(_ context.Context, req *testdata.Request) (*testdata.Response, error) {
ts.repoRequests = append(ts.repoRequests, req.GetDestination())
return &testdata.Response{}, nil
@@ -212,3 +231,8 @@ func (ts *testSvc) ClientUnaryRepoAccessor(_ context.Context, req *testdata.Requ
ts.repoRequests = append(ts.repoRequests, req.GetDestination())
return &testdata.Response{}, nil
}
+
+func (ts *testSvc) ClientUnaryRepoMaintainer(_ context.Context, req *testdata.Request) (*testdata.Response, error) {
+ ts.repoRequests = append(ts.repoRequests, req.GetDestination())
+ return &testdata.Response{}, nil
+}
diff --git a/internal/middleware/cache/prometheus.go b/internal/middleware/cache/prometheus.go
index 195bab26b..073402d5e 100644
--- a/internal/middleware/cache/prometheus.go
+++ b/internal/middleware/cache/prometheus.go
@@ -40,6 +40,8 @@ var (
rpcOpTypes.WithLabelValues("accessor").Inc()
case protoregistry.OpMutator:
rpcOpTypes.WithLabelValues("mutator").Inc()
+ case protoregistry.OpMaintenance:
+ rpcOpTypes.WithLabelValues("maintenance").Inc()
default:
rpcOpTypes.WithLabelValues("unknown").Inc()
}
diff --git a/internal/middleware/cache/testdata/stream.pb.go b/internal/middleware/cache/testdata/stream.pb.go
index dc2cfdc5d..ffaebf70a 100644
--- a/internal/middleware/cache/testdata/stream.pb.go
+++ b/internal/middleware/cache/testdata/stream.pb.go
@@ -124,7 +124,7 @@ var file_middleware_cache_testdata_stream_proto_rawDesc = []byte{
0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x11, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74,
0x61, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x74, 0x65, 0x73, 0x74,
0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x04, 0xf0,
- 0x97, 0x28, 0x01, 0x32, 0xb9, 0x02, 0x0a, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76,
+ 0x97, 0x28, 0x01, 0x32, 0xd4, 0x03, 0x0a, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x12, 0x4a, 0x0a, 0x17, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72,
0x65, 0x61, 0x6d, 0x52, 0x65, 0x70, 0x6f, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x11,
0x2e, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
@@ -134,21 +134,31 @@ var file_middleware_cache_testdata_stream_proto_rawDesc = []byte{
0x65, 0x70, 0x6f, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12, 0x11, 0x2e, 0x74, 0x65,
0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12,
0x2e, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x02, 0x30, 0x01, 0x12, 0x47, 0x0a, 0x16,
- 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6f, 0x4d,
- 0x75, 0x74, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x11, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74,
- 0x61, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x74, 0x65, 0x73, 0x74,
- 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa,
- 0x97, 0x28, 0x02, 0x08, 0x01, 0x12, 0x48, 0x0a, 0x17, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x55,
- 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6f, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72,
- 0x12, 0x11, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x02, 0x42,
- 0x45, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69,
- 0x74, 0x6c, 0x61, 0x62, 0x2d, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2f,
- 0x76, 0x31, 0x34, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6d, 0x69, 0x64,
- 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x2f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2f, 0x74, 0x65,
- 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x02, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x1a,
+ 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x70, 0x6f,
+ 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x11, 0x2e, 0x74, 0x65, 0x73,
+ 0x74, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e,
+ 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x03, 0x30, 0x01, 0x12, 0x47, 0x0a, 0x16, 0x43,
+ 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6f, 0x4d, 0x75,
+ 0x74, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x11, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61,
+ 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x64,
+ 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97,
+ 0x28, 0x02, 0x08, 0x01, 0x12, 0x48, 0x0a, 0x17, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x6e,
+ 0x61, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6f, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12,
+ 0x11, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x02, 0x12, 0x4a,
+ 0x0a, 0x19, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x70,
+ 0x6f, 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x11, 0x2e, 0x74, 0x65,
+ 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12,
+ 0x2e, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x03, 0x42, 0x45, 0x5a, 0x43, 0x67, 0x69,
+ 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2d,
+ 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x34, 0x2f, 0x69,
+ 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61,
+ 0x72, 0x65, 0x2f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -174,15 +184,19 @@ var file_middleware_cache_testdata_stream_proto_depIdxs = []int32{
0, // 1: testdata.InterceptedService.IgnoredMethod:input_type -> testdata.Request
0, // 2: testdata.TestService.ClientStreamRepoMutator:input_type -> testdata.Request
0, // 3: testdata.TestService.ClientStreamRepoAccessor:input_type -> testdata.Request
- 0, // 4: testdata.TestService.ClientUnaryRepoMutator:input_type -> testdata.Request
- 0, // 5: testdata.TestService.ClientUnaryRepoAccessor:input_type -> testdata.Request
- 1, // 6: testdata.InterceptedService.IgnoredMethod:output_type -> testdata.Response
- 1, // 7: testdata.TestService.ClientStreamRepoMutator:output_type -> testdata.Response
- 1, // 8: testdata.TestService.ClientStreamRepoAccessor:output_type -> testdata.Response
- 1, // 9: testdata.TestService.ClientUnaryRepoMutator:output_type -> testdata.Response
- 1, // 10: testdata.TestService.ClientUnaryRepoAccessor:output_type -> testdata.Response
- 6, // [6:11] is the sub-list for method output_type
- 1, // [1:6] is the sub-list for method input_type
+ 0, // 4: testdata.TestService.ClientStreamRepoMaintainer:input_type -> testdata.Request
+ 0, // 5: testdata.TestService.ClientUnaryRepoMutator:input_type -> testdata.Request
+ 0, // 6: testdata.TestService.ClientUnaryRepoAccessor:input_type -> testdata.Request
+ 0, // 7: testdata.TestService.ClientUnaryRepoMaintainer:input_type -> testdata.Request
+ 1, // 8: testdata.InterceptedService.IgnoredMethod:output_type -> testdata.Response
+ 1, // 9: testdata.TestService.ClientStreamRepoMutator:output_type -> testdata.Response
+ 1, // 10: testdata.TestService.ClientStreamRepoAccessor:output_type -> testdata.Response
+ 1, // 11: testdata.TestService.ClientStreamRepoMaintainer:output_type -> testdata.Response
+ 1, // 12: testdata.TestService.ClientUnaryRepoMutator:output_type -> testdata.Response
+ 1, // 13: testdata.TestService.ClientUnaryRepoAccessor:output_type -> testdata.Response
+ 1, // 14: testdata.TestService.ClientUnaryRepoMaintainer:output_type -> testdata.Response
+ 8, // [8:15] is the sub-list for method output_type
+ 1, // [1:8] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
diff --git a/internal/middleware/cache/testdata/stream.proto b/internal/middleware/cache/testdata/stream.proto
index aed6ab7dd..c977b0d69 100644
--- a/internal/middleware/cache/testdata/stream.proto
+++ b/internal/middleware/cache/testdata/stream.proto
@@ -32,6 +32,12 @@ service TestService {
};
}
+ rpc ClientStreamRepoMaintainer(Request) returns (stream Response) {
+ option (gitaly.op_type) = {
+ op: MAINTENANCE
+ };
+ }
+
rpc ClientUnaryRepoMutator(Request) returns (Response) {
option (gitaly.op_type) = {
op: MUTATOR
@@ -43,4 +49,10 @@ service TestService {
op: ACCESSOR
};
}
+
+ rpc ClientUnaryRepoMaintainer(Request) returns (Response) {
+ option (gitaly.op_type) = {
+ op: MAINTENANCE
+ };
+ }
}
diff --git a/internal/middleware/cache/testdata/stream_grpc.pb.go b/internal/middleware/cache/testdata/stream_grpc.pb.go
index ec9aaa71e..066eddc51 100644
--- a/internal/middleware/cache/testdata/stream_grpc.pb.go
+++ b/internal/middleware/cache/testdata/stream_grpc.pb.go
@@ -106,8 +106,10 @@ var InterceptedService_ServiceDesc = grpc.ServiceDesc{
type TestServiceClient interface {
ClientStreamRepoMutator(ctx context.Context, in *Request, opts ...grpc.CallOption) (TestService_ClientStreamRepoMutatorClient, error)
ClientStreamRepoAccessor(ctx context.Context, in *Request, opts ...grpc.CallOption) (TestService_ClientStreamRepoAccessorClient, error)
+ ClientStreamRepoMaintainer(ctx context.Context, in *Request, opts ...grpc.CallOption) (TestService_ClientStreamRepoMaintainerClient, error)
ClientUnaryRepoMutator(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
ClientUnaryRepoAccessor(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
+ ClientUnaryRepoMaintainer(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
}
type testServiceClient struct {
@@ -182,6 +184,38 @@ func (x *testServiceClientStreamRepoAccessorClient) Recv() (*Response, error) {
return m, nil
}
+func (c *testServiceClient) ClientStreamRepoMaintainer(ctx context.Context, in *Request, opts ...grpc.CallOption) (TestService_ClientStreamRepoMaintainerClient, error) {
+ stream, err := c.cc.NewStream(ctx, &TestService_ServiceDesc.Streams[2], "/testdata.TestService/ClientStreamRepoMaintainer", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &testServiceClientStreamRepoMaintainerClient{stream}
+ if err := x.ClientStream.SendMsg(in); err != nil {
+ return nil, err
+ }
+ if err := x.ClientStream.CloseSend(); err != nil {
+ return nil, err
+ }
+ return x, nil
+}
+
+type TestService_ClientStreamRepoMaintainerClient interface {
+ Recv() (*Response, error)
+ grpc.ClientStream
+}
+
+type testServiceClientStreamRepoMaintainerClient struct {
+ grpc.ClientStream
+}
+
+func (x *testServiceClientStreamRepoMaintainerClient) Recv() (*Response, error) {
+ m := new(Response)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
func (c *testServiceClient) ClientUnaryRepoMutator(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
out := new(Response)
err := c.cc.Invoke(ctx, "/testdata.TestService/ClientUnaryRepoMutator", in, out, opts...)
@@ -200,14 +234,25 @@ func (c *testServiceClient) ClientUnaryRepoAccessor(ctx context.Context, in *Req
return out, nil
}
+func (c *testServiceClient) ClientUnaryRepoMaintainer(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
+ out := new(Response)
+ err := c.cc.Invoke(ctx, "/testdata.TestService/ClientUnaryRepoMaintainer", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
// TestServiceServer is the server API for TestService service.
// All implementations must embed UnimplementedTestServiceServer
// for forward compatibility
type TestServiceServer interface {
ClientStreamRepoMutator(*Request, TestService_ClientStreamRepoMutatorServer) error
ClientStreamRepoAccessor(*Request, TestService_ClientStreamRepoAccessorServer) error
+ ClientStreamRepoMaintainer(*Request, TestService_ClientStreamRepoMaintainerServer) error
ClientUnaryRepoMutator(context.Context, *Request) (*Response, error)
ClientUnaryRepoAccessor(context.Context, *Request) (*Response, error)
+ ClientUnaryRepoMaintainer(context.Context, *Request) (*Response, error)
mustEmbedUnimplementedTestServiceServer()
}
@@ -221,12 +266,18 @@ func (UnimplementedTestServiceServer) ClientStreamRepoMutator(*Request, TestServ
func (UnimplementedTestServiceServer) ClientStreamRepoAccessor(*Request, TestService_ClientStreamRepoAccessorServer) error {
return status.Errorf(codes.Unimplemented, "method ClientStreamRepoAccessor not implemented")
}
+func (UnimplementedTestServiceServer) ClientStreamRepoMaintainer(*Request, TestService_ClientStreamRepoMaintainerServer) error {
+ return status.Errorf(codes.Unimplemented, "method ClientStreamRepoMaintainer not implemented")
+}
func (UnimplementedTestServiceServer) ClientUnaryRepoMutator(context.Context, *Request) (*Response, error) {
return nil, status.Errorf(codes.Unimplemented, "method ClientUnaryRepoMutator not implemented")
}
func (UnimplementedTestServiceServer) ClientUnaryRepoAccessor(context.Context, *Request) (*Response, error) {
return nil, status.Errorf(codes.Unimplemented, "method ClientUnaryRepoAccessor not implemented")
}
+func (UnimplementedTestServiceServer) ClientUnaryRepoMaintainer(context.Context, *Request) (*Response, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method ClientUnaryRepoMaintainer not implemented")
+}
func (UnimplementedTestServiceServer) mustEmbedUnimplementedTestServiceServer() {}
// UnsafeTestServiceServer may be embedded to opt out of forward compatibility for this service.
@@ -282,6 +333,27 @@ func (x *testServiceClientStreamRepoAccessorServer) Send(m *Response) error {
return x.ServerStream.SendMsg(m)
}
+func _TestService_ClientStreamRepoMaintainer_Handler(srv interface{}, stream grpc.ServerStream) error {
+ m := new(Request)
+ if err := stream.RecvMsg(m); err != nil {
+ return err
+ }
+ return srv.(TestServiceServer).ClientStreamRepoMaintainer(m, &testServiceClientStreamRepoMaintainerServer{stream})
+}
+
+type TestService_ClientStreamRepoMaintainerServer interface {
+ Send(*Response) error
+ grpc.ServerStream
+}
+
+type testServiceClientStreamRepoMaintainerServer struct {
+ grpc.ServerStream
+}
+
+func (x *testServiceClientStreamRepoMaintainerServer) Send(m *Response) error {
+ return x.ServerStream.SendMsg(m)
+}
+
func _TestService_ClientUnaryRepoMutator_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Request)
if err := dec(in); err != nil {
@@ -318,6 +390,24 @@ func _TestService_ClientUnaryRepoAccessor_Handler(srv interface{}, ctx context.C
return interceptor(ctx, in, info, handler)
}
+func _TestService_ClientUnaryRepoMaintainer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(Request)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(TestServiceServer).ClientUnaryRepoMaintainer(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/testdata.TestService/ClientUnaryRepoMaintainer",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(TestServiceServer).ClientUnaryRepoMaintainer(ctx, req.(*Request))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
// TestService_ServiceDesc is the grpc.ServiceDesc for TestService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -333,6 +423,10 @@ var TestService_ServiceDesc = grpc.ServiceDesc{
MethodName: "ClientUnaryRepoAccessor",
Handler: _TestService_ClientUnaryRepoAccessor_Handler,
},
+ {
+ MethodName: "ClientUnaryRepoMaintainer",
+ Handler: _TestService_ClientUnaryRepoMaintainer_Handler,
+ },
},
Streams: []grpc.StreamDesc{
{
@@ -345,6 +439,11 @@ var TestService_ServiceDesc = grpc.ServiceDesc{
Handler: _TestService_ClientStreamRepoAccessor_Handler,
ServerStreams: true,
},
+ {
+ StreamName: "ClientStreamRepoMaintainer",
+ Handler: _TestService_ClientStreamRepoMaintainer_Handler,
+ ServerStreams: true,
+ },
},
Metadata: "middleware/cache/testdata/stream.proto",
}
diff --git a/internal/praefect/coordinator.go b/internal/praefect/coordinator.go
index 41621914d..7e3c4b60c 100644
--- a/internal/praefect/coordinator.go
+++ b/internal/praefect/coordinator.go
@@ -92,20 +92,9 @@ var transactionRPCs = map[string]transactionsCondition{
"/gitaly.ObjectPoolService/ReduplicateRepository": transactionsDisabled,
"/gitaly.RepositoryService/RenameRepository": transactionsDisabled,
- // The following list of RPCs are considered idempotent RPCs: while they write into the
- // target repository, this shouldn't ever have any user-visible impact given that they're
- // purely optimizations of the on-disk state. These RPCs are thus treated specially and
- // shouldn't ever cause a repository generation bump.
- "/gitaly.RefService/PackRefs": transactionsDisabled,
- "/gitaly.RepositoryService/Cleanup": transactionsDisabled,
- "/gitaly.RepositoryService/GarbageCollect": transactionsDisabled,
- "/gitaly.RepositoryService/MidxRepack": transactionsDisabled,
- "/gitaly.RepositoryService/OptimizeRepository": transactionsDisabled,
- "/gitaly.RepositoryService/PruneUnreachableObjects": transactionsDisabled,
- "/gitaly.RepositoryService/RepackFull": transactionsDisabled,
- "/gitaly.RepositoryService/RepackIncremental": transactionsDisabled,
- "/gitaly.RepositoryService/RestoreCustomHooks": transactionsDisabled,
- "/gitaly.RepositoryService/WriteCommitGraph": transactionsDisabled,
+ // This RPC call should be made transactional. Furthermore, we should consider whether we
+ // have to replicate custom hooks.
+ "/gitaly.RepositoryService/RestoreCustomHooks": transactionsDisabled,
}
// forcePrimaryRoutingRPCs tracks RPCs which need to always get routed to the primary. This should
@@ -331,6 +320,12 @@ func (c *Coordinator) directRepositoryScopedMessage(ctx context.Context, call gr
ps, err = c.accessorStreamParameters(ctx, call)
case protoregistry.OpMutator:
ps, err = c.mutatorStreamParameters(ctx, call)
+ case protoregistry.OpMaintenance:
+ if featureflag.MaintenanceOperationRouting.IsEnabled(ctx) {
+ ps, err = c.maintenanceStreamParameters(ctx, call)
+ } else {
+ ps, err = c.mutatorStreamParameters(ctx, call)
+ }
default:
err = fmt.Errorf("unknown operation type: %v", call.methodInfo.Operation)
}
@@ -340,6 +335,10 @@ func (c *Coordinator) directRepositoryScopedMessage(ctx context.Context, call gr
return nil, helper.ErrNotFound(err)
}
+ if errors.Is(err, commonerr.ErrRepositoryNotFound) {
+ return nil, helper.ErrNotFound(err)
+ }
+
return nil, err
}
@@ -580,6 +579,69 @@ func (c *Coordinator) mutatorStreamParameters(ctx context.Context, call grpcCall
return proxy.NewStreamParameters(primaryDest, secondaryDests, reqFinalizer, nil), nil
}
+// maintenanceStreamParameters returns stream parameters for a maintenance-style RPC. The RPC call
+// is proxied to all nodes. Because it shouldn't matter whether a node is the primary or not in this
+// context, we just pick the first node returned by the router to be the primary. Returns an error
+// in case any of the nodes has failed to perform the maintenance RPC.
+func (c *Coordinator) maintenanceStreamParameters(ctx context.Context, call grpcCall) (*proxy.StreamParameters, error) {
+ route, err := c.router.RouteRepositoryMaintenance(ctx, call.targetRepo.StorageName, call.targetRepo.RelativePath)
+ if err != nil {
+ return nil, fmt.Errorf("routing repository maintenance: %w", err)
+ }
+
+ peerCtx := streamParametersContext(ctx)
+
+ nodeDests := make([]proxy.Destination, 0, len(route.Nodes))
+ nodeErrors := &nodeErrors{
+ errByNode: make(map[string]error),
+ }
+
+ for _, node := range route.Nodes {
+ node := node
+
+ nodeMsg, err := rewrittenRepositoryMessage(call.methodInfo, call.msg, node.Storage, route.ReplicaPath, "")
+ if err != nil {
+ return nil, err
+ }
+
+ nodeDests = append(nodeDests, proxy.Destination{
+ Ctx: peerCtx,
+ Conn: node.Connection,
+ Msg: nodeMsg,
+ ErrHandler: func(err error) error {
+ nodeErrors.Lock()
+ defer nodeErrors.Unlock()
+ nodeErrors.errByNode[node.Storage] = err
+
+ ctxlogrus.Extract(ctx).WithField("gitaly_storage", node.Storage).WithError(err).Error("proxying maintenance RPC to node failed")
+
+ // We ignore any errors returned by nodes such that they all have a
+ // chance to finish their maintenance RPC in a best-effort strategy.
+ // In case any node fails though, the RPC call will return with an
+ // error after all nodes have finished.
+ return nil
+ },
+ })
+ }
+
+ return proxy.NewStreamParameters(nodeDests[0], nodeDests[1:], func() error {
+ nodeErrors.Lock()
+ defer nodeErrors.Unlock()
+
+ // In case any of the nodes has recorded an error we will return it. It shouldn't
+ // matter which error we return exactly, so we just return errors in the order we've
+ // got from the router. This also has the nice property that any error returned by
+ // the primary node would be prioritized over all the others.
+ for _, node := range route.Nodes {
+ if nodeErr, ok := nodeErrors.errByNode[node.Storage]; ok && nodeErr != nil {
+ return nodeErr
+ }
+ }
+
+ return nil
+ }, nil), nil
+}
+
// streamParametersContexts converts the contexts with incoming metadata into a context that is
// usable by peer Gitaly nodes.
func streamParametersContext(ctx context.Context) context.Context {
diff --git a/internal/praefect/coordinator_test.go b/internal/praefect/coordinator_test.go
index 3fc515da0..fd28f29d6 100644
--- a/internal/praefect/coordinator_test.go
+++ b/internal/praefect/coordinator_test.go
@@ -115,13 +115,18 @@ func TestStreamDirectorReadOnlyEnforcement(t *testing.T) {
protoregistry.GitalyProtoPreregistered,
)
- frame, err := proto.Marshal(&gitalypb.CleanupRequest{Repository: &gitalypb.Repository{
- StorageName: virtualStorage,
- RelativePath: relativePath,
- }})
+ frame, err := proto.Marshal(&gitalypb.DeleteRefsRequest{
+ Repository: &gitalypb.Repository{
+ StorageName: virtualStorage,
+ RelativePath: relativePath,
+ },
+ Refs: [][]byte{
+ []byte("refs/heads/does-not-exist"),
+ },
+ })
require.NoError(t, err)
- _, err = coordinator.StreamDirector(ctx, "/gitaly.RepositoryService/Cleanup", &mockPeeker{frame: frame})
+ _, err = coordinator.StreamDirector(ctx, "/gitaly.RefService/DeleteRefs", &mockPeeker{frame: frame})
if tc.readOnly {
require.Equal(t, ErrRepositoryReadOnly, err)
testhelper.RequireGrpcCode(t, err, codes.FailedPrecondition)
@@ -386,6 +391,196 @@ func TestStreamDirectorMutator_StopTransaction(t *testing.T) {
require.NoError(t, err)
}
+func TestStreamDirector_maintenance(t *testing.T) {
+ t.Parallel()
+
+ node1 := &config.Node{
+ Address: "unix://" + testhelper.GetTemporaryGitalySocketFileName(t),
+ Storage: "praefect-internal-1",
+ }
+
+ node2 := &config.Node{
+ Address: "unix://" + testhelper.GetTemporaryGitalySocketFileName(t),
+ Storage: "praefect-internal-2",
+ }
+
+ cfg := config.Config{
+ VirtualStorages: []*config.VirtualStorage{
+ {
+ Name: "praefect",
+ Nodes: []*config.Node{node1, node2},
+ },
+ },
+ }
+
+ db := testdb.New(t)
+
+ repo := gitalypb.Repository{
+ StorageName: "praefect",
+ RelativePath: "/path/to/hashed/storage",
+ }
+
+ ctx := testhelper.Context(t)
+
+ nodeSet, err := DialNodes(ctx, cfg.VirtualStorages, protoregistry.GitalyProtoPreregistered, nil, nil, nil)
+ require.NoError(t, err)
+ defer nodeSet.Close()
+
+ tx := db.Begin(t)
+ defer tx.Rollback(t)
+
+ rs := datastore.NewPostgresRepositoryStore(tx, cfg.StorageNames())
+ require.NoError(t, rs.CreateRepository(ctx, 1, repo.StorageName, repo.RelativePath,
+ repo.RelativePath, node1.Storage, []string{node2.Storage}, nil, true, true))
+
+ testdb.SetHealthyNodes(t, ctx, tx, map[string]map[string][]string{"praefect": cfg.StorageNames()})
+
+ registry, err := protoregistry.NewFromPaths("praefect/mock/mock.proto")
+ require.NoError(t, err)
+
+ queueInterceptor := datastore.NewReplicationEventQueueInterceptor(datastore.NewPostgresReplicationEventQueue(tx))
+
+ coordinator := NewCoordinator(
+ queueInterceptor,
+ rs,
+ NewPerRepositoryRouter(
+ nodeSet.Connections(),
+ nodes.NewPerRepositoryElector(tx),
+ StaticHealthChecker(cfg.StorageNames()),
+ NewLockedRandom(rand.New(rand.NewSource(0))),
+ rs,
+ datastore.NewAssignmentStore(tx, cfg.StorageNames()),
+ rs,
+ nil,
+ ),
+ nil,
+ cfg,
+ registry,
+ )
+
+ message, err := proto.Marshal(&mock.RepoRequest{
+ Repo: &repo,
+ })
+ require.NoError(t, err)
+
+ methodInfo, err := registry.LookupMethod("/mock.SimpleService/RepoMaintenanceUnary")
+ require.NoError(t, err)
+
+ for _, tc := range []struct {
+ desc string
+ primaryErr error
+ secondaryErr error
+ expectedErr error
+ }{
+ {
+ desc: "successful",
+ },
+ {
+ desc: "primary returns an error",
+ primaryErr: helper.ErrNotFoundf("primary error"),
+ expectedErr: helper.ErrNotFoundf("primary error"),
+ },
+ {
+ desc: "secondary returns an error",
+ secondaryErr: helper.ErrNotFoundf("secondary error"),
+ expectedErr: helper.ErrNotFoundf("secondary error"),
+ },
+ {
+ desc: "primary error preferred",
+ primaryErr: helper.ErrNotFoundf("primary error"),
+ secondaryErr: helper.ErrNotFoundf("secondary error"),
+ expectedErr: helper.ErrNotFoundf("primary error"),
+ },
+ } {
+ t.Run(tc.desc, func(t *testing.T) {
+ // Behaviour between the new and old routing are sufficiently different that
+ // it doesn't make sense to try and cram both tests in here.
+ ctx := featureflag.ContextWithFeatureFlag(ctx, featureflag.MaintenanceOperationRouting, true)
+
+ queueInterceptor.OnEnqueue(func(context.Context, datastore.ReplicationEvent, datastore.ReplicationEventQueue) (datastore.ReplicationEvent, error) {
+ require.FailNow(t, "no replication jobs should have been created")
+ return datastore.ReplicationEvent{}, fmt.Errorf("unexpected call")
+ })
+
+ streamParams, err := coordinator.StreamDirector(ctx, methodInfo.FullMethodName(), &mockPeeker{message})
+ require.NoError(t, err)
+
+ var targetNodes []string
+ destinationByAddress := make(map[string]proxy.Destination)
+ for _, node := range append(streamParams.Secondaries(), streamParams.Primary()) {
+ targetNodes = append(targetNodes, node.Conn.Target())
+ destinationByAddress[node.Conn.Target()] = node
+ }
+
+ // Assert that both nodes are part of the stream parameters. Because the
+ // order is not deterministic (we randomly shuffle primary and secondary
+ // nodes) we only assert that elements match, not that any of both nodes has
+ // a specific role.
+ require.ElementsMatch(t, []string{
+ node1.Address,
+ node2.Address,
+ }, targetNodes)
+
+ // Assert that the target repositories were rewritten as expected for all of
+ // the nodes.
+ for _, nodeCfg := range []*config.Node{node1, node2} {
+ destination, ok := destinationByAddress[nodeCfg.Address]
+ require.True(t, ok)
+
+ request, err := methodInfo.UnmarshalRequestProto(destination.Msg)
+ require.NoError(t, err)
+
+ rewrittenTargetRepo, err := methodInfo.TargetRepo(request)
+ require.NoError(t, err)
+ require.Equal(t, nodeCfg.Storage, rewrittenTargetRepo.GetStorageName(), "stream director should have rewritten the storage name")
+ }
+
+ // We now inject errors into the streams by manually executing the error
+ // handlers. This simulates that the RPCs have been proxied and may or may
+ // not have returned an error.
+ //
+ // Note that these functions should not return an error: this is a strict
+ // requirement because otherwise failures returned by the primary would
+ // abort the operation on secondaries.
+ require.Nil(t, streamParams.Primary().ErrHandler(tc.primaryErr))
+ require.Nil(t, streamParams.Secondaries()[0].ErrHandler(tc.secondaryErr))
+
+ // The request finalizer should then see the errors as injected above.
+ require.Equal(t, tc.expectedErr, streamParams.RequestFinalizer())
+ })
+ }
+
+ t.Run("disabled maintenance routing", func(t *testing.T) {
+ ctx := featureflag.ContextWithFeatureFlag(ctx, featureflag.MaintenanceOperationRouting, false)
+
+ replicationEventCounter := 0
+ queueInterceptor.OnEnqueue(func(context.Context, datastore.ReplicationEvent, datastore.ReplicationEventQueue) (datastore.ReplicationEvent, error) {
+ replicationEventCounter++
+ return datastore.ReplicationEvent{}, nil
+ })
+
+ streamParams, err := coordinator.StreamDirector(ctx, methodInfo.FullMethodName(), &mockPeeker{message})
+ require.NoError(t, err)
+
+ // We're cheating a bit: the method we use here is not something that the
+ // coordinator would know, and thus it wouldn't ever set up transactions for that
+ // call either. This is accidentally the same behaviour like for any of the other
+ // preexisting maintenance-style RPCs though, so it's good enough. Furthermore, we
+ // really only want to ensure that the feature flag does its thing. The actual logic
+ // of mutator stream parameters is tested elsewhere already.
+ require.Equal(t, node1.Address, streamParams.Primary().Conn.Target())
+ require.Empty(t, streamParams.Secondaries())
+
+ // There shouldn't be any replication event yet.
+ require.Zero(t, replicationEventCounter)
+
+ require.NoError(t, streamParams.RequestFinalizer())
+
+ // But there should be one after having called the request finalizer.
+ require.Equal(t, 1, replicationEventCounter)
+ })
+}
+
type mockRouter struct {
Router
routeRepositoryAccessorFunc func(ctx context.Context, virtualStorage, relativePath string, forcePrimary bool) (RepositoryAccessorRoute, error)
diff --git a/internal/praefect/middleware/methodtype.go b/internal/praefect/middleware/methodtype.go
index 2478b0470..a3a0667b3 100644
--- a/internal/praefect/middleware/methodtype.go
+++ b/internal/praefect/middleware/methodtype.go
@@ -47,6 +47,8 @@ func observeMethodType(registry *protoregistry.Registry, fullMethod string) {
opType = "accessor"
case protoregistry.OpMutator:
opType = "mutator"
+ case protoregistry.OpMaintenance:
+ opType = "maintenance"
default:
return
}
diff --git a/internal/praefect/mock/mock.pb.go b/internal/praefect/mock/mock.pb.go
index 76ba4ff21..ffdd2df38 100644
--- a/internal/praefect/mock/mock.pb.go
+++ b/internal/praefect/mock/mock.pb.go
@@ -86,7 +86,7 @@ var file_praefect_mock_mock_proto_rawDesc = []byte{
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x52, 0x65,
0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x42, 0x04, 0x98, 0xc6, 0x2c, 0x01, 0x52, 0x04,
- 0x72, 0x65, 0x70, 0x6f, 0x32, 0x9e, 0x01, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x53,
+ 0x72, 0x65, 0x70, 0x6f, 0x32, 0xe9, 0x01, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x53,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x46, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x41, 0x63,
0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x12, 0x11, 0x2e, 0x6d, 0x6f,
0x63, 0x6b, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16,
@@ -96,11 +96,16 @@ var file_praefect_mock_mock_proto_rawDesc = []byte{
0x72, 0x79, 0x12, 0x11, 0x2e, 0x6d, 0x6f, 0x63, 0x6b, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x06, 0xfa,
- 0x97, 0x28, 0x02, 0x08, 0x01, 0x42, 0x39, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e,
- 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2d, 0x6f, 0x72, 0x67, 0x2f, 0x67,
- 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x34, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x61, 0x65, 0x66, 0x65, 0x63, 0x74, 0x2f, 0x6d, 0x6f, 0x63, 0x6b,
- 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x97, 0x28, 0x02, 0x08, 0x01, 0x12, 0x49, 0x0a, 0x14, 0x52, 0x65, 0x70, 0x6f, 0x4d, 0x61, 0x69,
+ 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x12, 0x11, 0x2e,
+ 0x6d, 0x6f, 0x63, 0x6b, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
+ 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x03,
+ 0x42, 0x39, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67,
+ 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2d, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79,
+ 0x2f, 0x76, 0x31, 0x34, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72,
+ 0x61, 0x65, 0x66, 0x65, 0x63, 0x74, 0x2f, 0x6d, 0x6f, 0x63, 0x6b, 0x62, 0x06, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x33,
}
var (
@@ -125,10 +130,12 @@ var file_praefect_mock_mock_proto_depIdxs = []int32{
1, // 0: mock.RepoRequest.repo:type_name -> gitaly.Repository
0, // 1: mock.SimpleService.RepoAccessorUnary:input_type -> mock.RepoRequest
0, // 2: mock.SimpleService.RepoMutatorUnary:input_type -> mock.RepoRequest
- 2, // 3: mock.SimpleService.RepoAccessorUnary:output_type -> google.protobuf.Empty
- 2, // 4: mock.SimpleService.RepoMutatorUnary:output_type -> google.protobuf.Empty
- 3, // [3:5] is the sub-list for method output_type
- 1, // [1:3] is the sub-list for method input_type
+ 0, // 3: mock.SimpleService.RepoMaintenanceUnary:input_type -> mock.RepoRequest
+ 2, // 4: mock.SimpleService.RepoAccessorUnary:output_type -> google.protobuf.Empty
+ 2, // 5: mock.SimpleService.RepoMutatorUnary:output_type -> google.protobuf.Empty
+ 2, // 6: mock.SimpleService.RepoMaintenanceUnary:output_type -> google.protobuf.Empty
+ 4, // [4:7] is the sub-list for method output_type
+ 1, // [1:4] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
diff --git a/internal/praefect/mock/mock.proto b/internal/praefect/mock/mock.proto
index 694ac2e4f..748befbf6 100644
--- a/internal/praefect/mock/mock.proto
+++ b/internal/praefect/mock/mock.proto
@@ -33,4 +33,12 @@ service SimpleService {
scope_level: REPOSITORY
};
}
+
+ // RepoMaintenanceUnary is a unary RPC that maintains a repo
+ rpc RepoMaintenanceUnary(RepoRequest) returns (google.protobuf.Empty) {
+ option (gitaly.op_type) = {
+ op: MAINTENANCE
+ scope_level: REPOSITORY
+ };
+ }
}
diff --git a/internal/praefect/mock/mock_grpc.pb.go b/internal/praefect/mock/mock_grpc.pb.go
index 60203340b..0f3f1522a 100644
--- a/internal/praefect/mock/mock_grpc.pb.go
+++ b/internal/praefect/mock/mock_grpc.pb.go
@@ -23,6 +23,8 @@ type SimpleServiceClient interface {
RepoAccessorUnary(ctx context.Context, in *RepoRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
// RepoMutatorUnary is a unary RPC that mutates a repo
RepoMutatorUnary(ctx context.Context, in *RepoRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // RepoMaintenanceUnary is a unary RPC that maintains a repo
+ RepoMaintenanceUnary(ctx context.Context, in *RepoRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
}
type simpleServiceClient struct {
@@ -51,6 +53,15 @@ func (c *simpleServiceClient) RepoMutatorUnary(ctx context.Context, in *RepoRequ
return out, nil
}
+func (c *simpleServiceClient) RepoMaintenanceUnary(ctx context.Context, in *RepoRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/mock.SimpleService/RepoMaintenanceUnary", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
// SimpleServiceServer is the server API for SimpleService service.
// All implementations must embed UnimplementedSimpleServiceServer
// for forward compatibility
@@ -59,6 +70,8 @@ type SimpleServiceServer interface {
RepoAccessorUnary(context.Context, *RepoRequest) (*emptypb.Empty, error)
// RepoMutatorUnary is a unary RPC that mutates a repo
RepoMutatorUnary(context.Context, *RepoRequest) (*emptypb.Empty, error)
+ // RepoMaintenanceUnary is a unary RPC that maintains a repo
+ RepoMaintenanceUnary(context.Context, *RepoRequest) (*emptypb.Empty, error)
mustEmbedUnimplementedSimpleServiceServer()
}
@@ -72,6 +85,9 @@ func (UnimplementedSimpleServiceServer) RepoAccessorUnary(context.Context, *Repo
func (UnimplementedSimpleServiceServer) RepoMutatorUnary(context.Context, *RepoRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method RepoMutatorUnary not implemented")
}
+func (UnimplementedSimpleServiceServer) RepoMaintenanceUnary(context.Context, *RepoRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method RepoMaintenanceUnary not implemented")
+}
func (UnimplementedSimpleServiceServer) mustEmbedUnimplementedSimpleServiceServer() {}
// UnsafeSimpleServiceServer may be embedded to opt out of forward compatibility for this service.
@@ -121,6 +137,24 @@ func _SimpleService_RepoMutatorUnary_Handler(srv interface{}, ctx context.Contex
return interceptor(ctx, in, info, handler)
}
+func _SimpleService_RepoMaintenanceUnary_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RepoRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(SimpleServiceServer).RepoMaintenanceUnary(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/mock.SimpleService/RepoMaintenanceUnary",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(SimpleServiceServer).RepoMaintenanceUnary(ctx, req.(*RepoRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
// SimpleService_ServiceDesc is the grpc.ServiceDesc for SimpleService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -136,6 +170,10 @@ var SimpleService_ServiceDesc = grpc.ServiceDesc{
MethodName: "RepoMutatorUnary",
Handler: _SimpleService_RepoMutatorUnary_Handler,
},
+ {
+ MethodName: "RepoMaintenanceUnary",
+ Handler: _SimpleService_RepoMaintenanceUnary_Handler,
+ },
},
Streams: []grpc.StreamDesc{},
Metadata: "praefect/mock/mock.proto",
diff --git a/internal/praefect/protoregistry/protoregistry.go b/internal/praefect/protoregistry/protoregistry.go
index bc82bbf05..d2b900b1e 100644
--- a/internal/praefect/protoregistry/protoregistry.go
+++ b/internal/praefect/protoregistry/protoregistry.go
@@ -35,6 +35,10 @@ const (
OpAccessor
// OpMutator = mutator operation type (modifies a repository)
OpMutator
+ // OpMaintenance is an operation which performs maintenance-tasks on the repository. It
+ // shouldn't ever result in a user-visible change in behaviour, except that it may repair
+ // corrupt data.
+ OpMaintenance
)
// Scope represents the intended scope of an RPC method
@@ -250,6 +254,8 @@ func parseMethodInfo(
opCode = OpAccessor
case gitalypb.OperationMsg_MUTATOR:
opCode = OpMutator
+ case gitalypb.OperationMsg_MAINTENANCE:
+ opCode = OpMaintenance
default:
opCode = OpUnknown
}
diff --git a/internal/praefect/protoregistry/protoregistry_test.go b/internal/praefect/protoregistry/protoregistry_test.go
index 4ce683c07..89976b7c5 100644
--- a/internal/praefect/protoregistry/protoregistry_test.go
+++ b/internal/praefect/protoregistry/protoregistry_test.go
@@ -92,7 +92,7 @@ func TestNewProtoRegistry(t *testing.T) {
"GetTagMessages": protoregistry.OpAccessor,
"ListBranchNamesContainingCommit": protoregistry.OpAccessor,
"ListTagNamesContainingCommit": protoregistry.OpAccessor,
- "PackRefs": protoregistry.OpMutator,
+ "PackRefs": protoregistry.OpMaintenance,
"RefExists": protoregistry.OpAccessor,
},
"RemoteService": {
@@ -104,7 +104,7 @@ func TestNewProtoRegistry(t *testing.T) {
"ApplyGitattributes": protoregistry.OpMutator,
"BackupCustomHooks": protoregistry.OpAccessor,
"CalculateChecksum": protoregistry.OpAccessor,
- "Cleanup": protoregistry.OpMutator,
+ "Cleanup": protoregistry.OpMaintenance,
"CreateBundle": protoregistry.OpAccessor,
"CreateFork": protoregistry.OpMutator,
"CreateRepository": protoregistry.OpMutator,
@@ -117,16 +117,16 @@ func TestNewProtoRegistry(t *testing.T) {
"FindLicense": protoregistry.OpAccessor,
"FindMergeBase": protoregistry.OpAccessor,
"Fsck": protoregistry.OpAccessor,
- "GarbageCollect": protoregistry.OpMutator,
+ "GarbageCollect": protoregistry.OpMaintenance,
"GetArchive": protoregistry.OpAccessor,
"GetInfoAttributes": protoregistry.OpAccessor,
"GetRawChanges": protoregistry.OpAccessor,
"GetSnapshot": protoregistry.OpAccessor,
"HasLocalBranches": protoregistry.OpAccessor,
- "OptimizeRepository": protoregistry.OpMutator,
- "PruneUnreachableObjects": protoregistry.OpMutator,
- "RepackFull": protoregistry.OpMutator,
- "RepackIncremental": protoregistry.OpMutator,
+ "OptimizeRepository": protoregistry.OpMaintenance,
+ "PruneUnreachableObjects": protoregistry.OpMaintenance,
+ "RepackFull": protoregistry.OpMaintenance,
+ "RepackIncremental": protoregistry.OpMaintenance,
"RepositoryExists": protoregistry.OpAccessor,
"RepositorySize": protoregistry.OpAccessor,
"RestoreCustomHooks": protoregistry.OpMutator,
diff --git a/internal/praefect/replicator_test.go b/internal/praefect/replicator_test.go
index 79e4135d7..6862b2f3f 100644
--- a/internal/praefect/replicator_test.go
+++ b/internal/praefect/replicator_test.go
@@ -2,6 +2,7 @@ package praefect
import (
"context"
+ "fmt"
"path/filepath"
"strings"
"sync"
@@ -283,6 +284,10 @@ func TestReplicatorDowngradeAttempt(t *testing.T) {
}
func TestReplicator_PropagateReplicationJob(t *testing.T) {
+ testhelper.NewFeatureSets(featureflag.MaintenanceOperationRouting).Run(t, testReplicatorPropagateReplicationJob)
+}
+
+func testReplicatorPropagateReplicationJob(t *testing.T, ctx context.Context) {
t.Parallel()
primaryStorage, secondaryStorage := "internal-gitaly-0", "internal-gitaly-1"
@@ -318,16 +323,29 @@ func TestReplicator_PropagateReplicationJob(t *testing.T) {
// By using WaitGroup we are sure the test cleanup will be started after all replication
// requests are completed, so no running cache IO operations happen.
queue := datastore.NewReplicationEventQueueInterceptor(datastore.NewPostgresReplicationEventQueue(testdb.New(t)))
+
var wg sync.WaitGroup
- queue.OnEnqueue(func(ctx context.Context, event datastore.ReplicationEvent, queue datastore.ReplicationEventQueue) (datastore.ReplicationEvent, error) {
- wg.Add(1)
- return queue.Enqueue(ctx, event)
- })
- queue.OnAcknowledge(func(ctx context.Context, state datastore.JobState, eventIDs []uint64, queue datastore.ReplicationEventQueue) ([]uint64, error) {
- acknowledged, err := queue.Acknowledge(ctx, state, eventIDs)
- wg.Add(-len(eventIDs))
- return acknowledged, err
- })
+ if featureflag.MaintenanceOperationRouting.IsEnabled(ctx) {
+ // When maintenance operation routing is enabled we don't expect to see any
+ // replication events. The observed behaviour should still be the same though: we
+ // expect to observe the RPC calls on both the primary and secondary node because we
+ // route them to both at the same time.
+ queue.OnEnqueue(func(ctx context.Context, event datastore.ReplicationEvent, queue datastore.ReplicationEventQueue) (datastore.ReplicationEvent, error) {
+ require.FailNow(t, "no replication jobs should have been created")
+ return datastore.ReplicationEvent{}, fmt.Errorf("unexpected enqueue")
+ })
+ } else {
+ queue.OnEnqueue(func(ctx context.Context, event datastore.ReplicationEvent, queue datastore.ReplicationEventQueue) (datastore.ReplicationEvent, error) {
+ wg.Add(1)
+ return queue.Enqueue(ctx, event)
+ })
+ queue.OnAcknowledge(func(ctx context.Context, state datastore.JobState, eventIDs []uint64, queue datastore.ReplicationEventQueue) ([]uint64, error) {
+ acknowledged, err := queue.Acknowledge(ctx, state, eventIDs)
+ wg.Add(-len(eventIDs))
+ return acknowledged, err
+ })
+ }
+
logEntry := testhelper.NewDiscardingLogEntry(t)
nodeMgr, err := nodes.NewManager(logEntry, conf, nil, nil, promtest.NewMockHistogramVec(), protoregistry.GitalyProtoPreregistered, nil, nil, nil)
@@ -362,7 +380,7 @@ func TestReplicator_PropagateReplicationJob(t *testing.T) {
prf := NewGRPCServer(conf, logEntry, protoregistry.GitalyProtoPreregistered, coordinator.StreamDirector, txMgr, rs, nil, nil, nil, nil)
listener, port := listenAvailPort(t)
- ctx, cancel := context.WithCancel(testhelper.Context(t))
+ ctx, cancel := context.WithCancel(ctx)
go prf.Serve(listener)
defer prf.Stop()
diff --git a/internal/praefect/router.go b/internal/praefect/router.go
index 1b6f19387..da9dbd36f 100644
--- a/internal/praefect/router.go
+++ b/internal/praefect/router.go
@@ -49,6 +49,16 @@ type RepositoryMutatorRoute struct {
ReplicationTargets []string
}
+// RepositoryMaintenanceRoute describes how to route a repository scoped maintenance call.
+type RepositoryMaintenanceRoute struct {
+ // RepositoryID is the repository's ID as Praefect identifies it.
+ RepositoryID int64
+ // ReplicaPath is the disk path where the replicas are stored.
+ ReplicaPath string
+ // Nodes contains all the nodes the call should be routed to.
+ Nodes []RouterNode
+}
+
// Router decides which nodes to direct accessor and mutator RPCs to.
type Router interface {
// RouteStorageAccessor returns the node which should serve the storage accessor request.
@@ -66,4 +76,9 @@ type Router interface {
// RouteRepositoryCreation decides returns the primary and secondaries that should handle the repository creation
// request. It is up to the caller to store the assignments and primary information after finishing the RPC.
RouteRepositoryCreation(ctx context.Context, virtualStorage, relativePath, additionalRepoRelativePath string) (RepositoryMutatorRoute, error)
+ // RouteRepositoryMaintenance routes the given maintenance-style RPC to all nodes which
+ // should perform maintenance. This would typically include all online nodes, regardless of
+ // whether the repository hosted by them is up-to-date or not. Maintenance tasks should
+ // never be replicated.
+ RouteRepositoryMaintenance(ctx context.Context, virtualStorage, relativePath string) (RepositoryMaintenanceRoute, error)
}
diff --git a/internal/praefect/router_node_manager.go b/internal/praefect/router_node_manager.go
index 9cceaea0a..f1f3c474a 100644
--- a/internal/praefect/router_node_manager.go
+++ b/internal/praefect/router_node_manager.go
@@ -151,3 +151,34 @@ func (r *nodeManagerRouter) RouteRepositoryCreation(ctx context.Context, virtual
ReplicationTargets: replicationTargets,
}, nil
}
+
+// RouteRepositoryMaintenance includes all healthy nodes regardless of whether they're consistent or
+// not.
+func (r *nodeManagerRouter) RouteRepositoryMaintenance(ctx context.Context, virtualStorage, relativePath string) (RepositoryMaintenanceRoute, error) {
+ shard, err := r.mgr.GetShard(ctx, virtualStorage)
+ if err != nil {
+ return RepositoryMaintenanceRoute{}, fmt.Errorf("get shard: %w", err)
+ }
+
+ nodes := make([]RouterNode, 0, 1+len(shard.Secondaries))
+
+ if shard.Primary.IsHealthy() {
+ nodes = append(nodes, toRouterNode(shard.Primary))
+ }
+
+ for _, secondary := range shard.Secondaries {
+ if secondary.IsHealthy() {
+ nodes = append(nodes, toRouterNode(secondary))
+ continue
+ }
+ }
+
+ if len(nodes) == 0 {
+ return RepositoryMaintenanceRoute{}, ErrNoHealthyNodes
+ }
+
+ return RepositoryMaintenanceRoute{
+ ReplicaPath: relativePath,
+ Nodes: nodes,
+ }, nil
+}
diff --git a/internal/praefect/router_per_repository.go b/internal/praefect/router_per_repository.go
index 2685829f8..6f1b4e7bd 100644
--- a/internal/praefect/router_per_repository.go
+++ b/internal/praefect/router_per_repository.go
@@ -367,3 +367,56 @@ func (r *PerRepositoryRouter) RouteRepositoryCreation(ctx context.Context, virtu
ReplicationTargets: replicationTargets,
}, nil
}
+
+// RouteRepositoryMaintenance will route the maintenance call to all healthy nodes in a best-effort
+// strategy. We do not raise an error in case the primary node is unhealthy, but will in case all
+// nodes are unhealthy.
+func (r *PerRepositoryRouter) RouteRepositoryMaintenance(ctx context.Context, virtualStorage, relativePath string) (RepositoryMaintenanceRoute, error) {
+ healthyNodes, err := r.healthyNodes(virtualStorage)
+ if err != nil {
+ return RepositoryMaintenanceRoute{}, err
+ }
+
+ healthyNodesByStorage := map[string]RouterNode{}
+ for _, healthyNode := range healthyNodes {
+ healthyNodesByStorage[healthyNode.Storage] = healthyNode
+ }
+
+ metadata, err := r.rs.GetRepositoryMetadataByPath(ctx, virtualStorage, relativePath)
+ if err != nil {
+ return RepositoryMaintenanceRoute{}, fmt.Errorf("getting repository metadata: %w", err)
+ }
+
+ nodes := make([]RouterNode, 0, len(metadata.Replicas))
+ for _, replica := range metadata.Replicas {
+ node, ok := healthyNodesByStorage[replica.Storage]
+ if !ok {
+ continue
+ }
+
+ // If the is not assigned to the replica it either hasn't yet been created
+ // or it will eventually get deleted. In neither case does it make sense to
+ // maintain it, so we skip such nodes.
+ if !replica.Assigned {
+ continue
+ }
+
+ // If the repository doesn't exist on the replica there is no need to perform any
+ // maintenance tasks at all.
+ if replica.Generation < 0 {
+ continue
+ }
+
+ nodes = append(nodes, node)
+ }
+
+ if len(nodes) == 0 {
+ return RepositoryMaintenanceRoute{}, ErrNoHealthyNodes
+ }
+
+ return RepositoryMaintenanceRoute{
+ RepositoryID: metadata.RepositoryID,
+ ReplicaPath: metadata.ReplicaPath,
+ Nodes: nodes,
+ }, nil
+}
diff --git a/internal/praefect/router_per_repository_test.go b/internal/praefect/router_per_repository_test.go
index dfc68552d..44d8b10ce 100644
--- a/internal/praefect/router_per_repository_test.go
+++ b/internal/praefect/router_per_repository_test.go
@@ -7,6 +7,7 @@ import (
"testing"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v14/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v14/internal/praefect/commonerr"
"gitlab.com/gitlab-org/gitaly/v14/internal/praefect/datastore"
"gitlab.com/gitlab-org/gitaly/v14/internal/praefect/nodes"
@@ -448,6 +449,218 @@ func TestPerRepositoryRouter_RouteRepositoryMutator(t *testing.T) {
}
}
+func TestPerRepositoryRouter_RouteRepositoryMaintenance(t *testing.T) {
+ t.Parallel()
+
+ db := testdb.New(t)
+
+ var (
+ virtualStorage = "virtual-storage-1"
+ relativePath = gittest.NewRepositoryName(t, true)
+ )
+
+ configuredStorages := []string{"primary", "secondary-1", "secondary-2"}
+
+ for _, tc := range []struct {
+ desc string
+ virtualStorage string
+ healthyStorages []string
+ assignedStorages []string
+ storageGenerations map[string]int
+ expectedStorages []string
+ expectedErr error
+ }{
+ {
+ desc: "unknown virtual storage",
+ virtualStorage: "unknown",
+ expectedErr: nodes.ErrVirtualStorageNotExist,
+ },
+ {
+ desc: "all nodes unhealthy",
+ virtualStorage: virtualStorage,
+ storageGenerations: map[string]int{
+ "primary": 1,
+ "secondary-1": 1,
+ "secondary-2": 1,
+ },
+ expectedErr: ErrNoHealthyNodes,
+ },
+ {
+ desc: "unhealthy primary",
+ virtualStorage: virtualStorage,
+ healthyStorages: []string{"secondary-1", "secondary-2"},
+ storageGenerations: map[string]int{
+ "primary": 1,
+ "secondary-1": 1,
+ "secondary-2": 1,
+ },
+ expectedStorages: []string{"secondary-1", "secondary-2"},
+ },
+ {
+ desc: "unhealthy secondaries",
+ virtualStorage: virtualStorage,
+ healthyStorages: []string{"primary"},
+ storageGenerations: map[string]int{
+ "primary": 1,
+ "secondary-1": 1,
+ "secondary-2": 1,
+ },
+ expectedStorages: []string{"primary"},
+ },
+ {
+ desc: "all nodes healthy",
+ virtualStorage: virtualStorage,
+ healthyStorages: configuredStorages,
+ storageGenerations: map[string]int{
+ "primary": 1,
+ "secondary-1": 1,
+ "secondary-2": 1,
+ },
+ expectedStorages: []string{"primary", "secondary-1", "secondary-2"},
+ },
+ {
+ desc: "unassigned primary is ignored",
+ virtualStorage: virtualStorage,
+ healthyStorages: configuredStorages,
+ assignedStorages: []string{"secondary-1", "secondary-2"},
+ storageGenerations: map[string]int{
+ "primary": 1,
+ "secondary-1": 1,
+ "secondary-2": 1,
+ },
+ expectedStorages: []string{"secondary-1", "secondary-2"},
+ },
+ {
+ desc: "unassigned secondary is ignored",
+ virtualStorage: virtualStorage,
+ healthyStorages: configuredStorages,
+ assignedStorages: []string{"primary", "secondary-1"},
+ storageGenerations: map[string]int{
+ "primary": 1,
+ "secondary-1": 1,
+ "secondary-2": 1,
+ },
+ expectedStorages: []string{"primary", "secondary-1"},
+ },
+ {
+ desc: "no assigned nodes",
+ virtualStorage: virtualStorage,
+ healthyStorages: configuredStorages,
+ storageGenerations: map[string]int{
+ "primary": 1,
+ "secondary-1": 1,
+ "secondary-2": 1,
+ },
+ expectedStorages: []string{"primary", "secondary-1", "secondary-2"},
+ },
+ {
+ desc: "unhealthy and unassigned nodes",
+ virtualStorage: virtualStorage,
+ healthyStorages: []string{"primary", "secondary-1"},
+ assignedStorages: []string{"primary", "secondary-2"},
+ storageGenerations: map[string]int{
+ "primary": 1,
+ "secondary-1": 1,
+ "secondary-2": 1,
+ },
+ expectedStorages: []string{"primary"},
+ },
+ {
+ desc: "missing repo on primary",
+ virtualStorage: virtualStorage,
+ healthyStorages: configuredStorages,
+ assignedStorages: configuredStorages,
+ storageGenerations: map[string]int{
+ "primary": -1,
+ "secondary-1": 9000,
+ "secondary-2": 9000,
+ },
+ expectedStorages: []string{"secondary-1", "secondary-2"},
+ },
+ {
+ desc: "missing repo on secondary",
+ virtualStorage: virtualStorage,
+ healthyStorages: configuredStorages,
+ assignedStorages: configuredStorages,
+ storageGenerations: map[string]int{
+ "primary": 9000,
+ "secondary-1": 9000,
+ "secondary-2": -1,
+ },
+ expectedStorages: []string{"primary", "secondary-1"},
+ },
+ {
+ desc: "mixed generations",
+ virtualStorage: virtualStorage,
+ healthyStorages: configuredStorages,
+ assignedStorages: configuredStorages,
+ storageGenerations: map[string]int{
+ "primary": 0,
+ "secondary-1": 1,
+ "secondary-2": 2,
+ },
+ expectedStorages: []string{"primary", "secondary-1", "secondary-2"},
+ },
+ } {
+ t.Run(tc.desc, func(t *testing.T) {
+ ctx := testhelper.Context(t)
+
+ tx := db.Begin(t)
+ defer tx.Rollback(t)
+
+ conns := Connections{
+ virtualStorage: {
+ "primary": &grpc.ClientConn{},
+ "secondary-1": &grpc.ClientConn{},
+ "secondary-2": &grpc.ClientConn{},
+ },
+ }
+
+ rs := datastore.NewPostgresRepositoryStore(tx, map[string][]string{
+ virtualStorage: configuredStorages,
+ })
+
+ repositoryID, err := rs.ReserveRepositoryID(ctx, virtualStorage, relativePath)
+ require.NoError(t, err)
+ require.NoError(t, rs.CreateRepository(ctx, repositoryID, virtualStorage, relativePath, relativePath, "primary", []string{"secondary-1", "secondary-2"}, nil, true, false))
+
+ for _, storage := range tc.assignedStorages {
+ _, err := tx.ExecContext(ctx, `
+ INSERT INTO repository_assignments
+ VALUES ($1, $2, $3, $4)
+ `, virtualStorage, relativePath, storage, repositoryID)
+ require.NoError(t, err)
+ }
+
+ for storage, generation := range tc.storageGenerations {
+ require.NoError(t, rs.SetGeneration(ctx, repositoryID, storage, relativePath, generation))
+ }
+
+ router := NewPerRepositoryRouter(conns, nil, StaticHealthChecker{
+ virtualStorage: tc.healthyStorages,
+ }, nil, nil, nil, rs, nil)
+
+ route, err := router.RouteRepositoryMaintenance(ctx, tc.virtualStorage, relativePath)
+ require.Equal(t, tc.expectedErr, err)
+ if err == nil {
+ var expectedStorages []RouterNode
+ for _, expectedNode := range tc.expectedStorages {
+ expectedStorages = append(expectedStorages, RouterNode{
+ Storage: expectedNode,
+ Connection: conns[tc.virtualStorage][expectedNode],
+ })
+ }
+
+ require.Equal(t, RepositoryMaintenanceRoute{
+ RepositoryID: repositoryID,
+ ReplicaPath: relativePath,
+ Nodes: expectedStorages,
+ }, route)
+ }
+ })
+ }
+}
+
func TestPerRepositoryRouter_RouteRepositoryCreation(t *testing.T) {
t.Parallel()
diff --git a/proto/go/gitalypb/lint.pb.go b/proto/go/gitalypb/lint.pb.go
index cb57cecac..13c98757d 100644
--- a/proto/go/gitalypb/lint.pb.go
+++ b/proto/go/gitalypb/lint.pb.go
@@ -24,9 +24,10 @@ const (
type OperationMsg_Operation int32
const (
- OperationMsg_UNKNOWN OperationMsg_Operation = 0
- OperationMsg_MUTATOR OperationMsg_Operation = 1
- OperationMsg_ACCESSOR OperationMsg_Operation = 2
+ OperationMsg_UNKNOWN OperationMsg_Operation = 0
+ OperationMsg_MUTATOR OperationMsg_Operation = 1
+ OperationMsg_ACCESSOR OperationMsg_Operation = 2
+ OperationMsg_MAINTENANCE OperationMsg_Operation = 3
)
// Enum value maps for OperationMsg_Operation.
@@ -35,11 +36,13 @@ var (
0: "UNKNOWN",
1: "MUTATOR",
2: "ACCESSOR",
+ 3: "MAINTENANCE",
}
OperationMsg_Operation_value = map[string]int32{
- "UNKNOWN": 0,
- "MUTATOR": 1,
- "ACCESSOR": 2,
+ "UNKNOWN": 0,
+ "MUTATOR": 1,
+ "ACCESSOR": 2,
+ "MAINTENANCE": 3,
}
)
@@ -288,7 +291,7 @@ var file_lint_proto_rawDesc = []byte{
0x0a, 0x0a, 0x6c, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x67, 0x69,
0x74, 0x61, 0x6c, 0x79, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72,
- 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe4, 0x01, 0x0a, 0x0c, 0x4f, 0x70, 0x65, 0x72, 0x61,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf5, 0x01, 0x0a, 0x0c, 0x4f, 0x70, 0x65, 0x72, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x67, 0x12, 0x2e, 0x0a, 0x02, 0x6f, 0x70, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x4f, 0x70, 0x65,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
@@ -296,50 +299,51 @@ var file_lint_proto_rawDesc = []byte{
0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x67,
0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d,
0x73, 0x67, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x0a, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x4c,
- 0x65, 0x76, 0x65, 0x6c, 0x22, 0x33, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
+ 0x65, 0x76, 0x65, 0x6c, 0x22, 0x44, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b,
0x0a, 0x07, 0x4d, 0x55, 0x54, 0x41, 0x54, 0x4f, 0x52, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x41,
- 0x43, 0x43, 0x45, 0x53, 0x53, 0x4f, 0x52, 0x10, 0x02, 0x22, 0x32, 0x0a, 0x05, 0x53, 0x63, 0x6f,
- 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x4f, 0x52, 0x59,
- 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x4f, 0x52, 0x41, 0x47, 0x45, 0x10, 0x02, 0x22,
- 0x04, 0x08, 0x01, 0x10, 0x01, 0x2a, 0x06, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x3a, 0x43, 0x0a,
- 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x12, 0x1f, 0x2e, 0x67,
- 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53,
- 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xfe, 0x82,
- 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74,
- 0x65, 0x64, 0x3a, 0x4f, 0x0a, 0x07, 0x6f, 0x70, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1e, 0x2e,
+ 0x43, 0x43, 0x45, 0x53, 0x53, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x41, 0x49,
+ 0x4e, 0x54, 0x45, 0x4e, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x03, 0x22, 0x32, 0x0a, 0x05, 0x53, 0x63,
+ 0x6f, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x4f, 0x52,
+ 0x59, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x4f, 0x52, 0x41, 0x47, 0x45, 0x10, 0x02,
+ 0x22, 0x04, 0x08, 0x01, 0x10, 0x01, 0x2a, 0x06, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x3a, 0x43,
+ 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x12, 0x1f, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
- 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xff, 0x82,
- 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x4f,
- 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x67, 0x52, 0x06, 0x6f, 0x70, 0x54,
- 0x79, 0x70, 0x65, 0x3a, 0x4f, 0x0a, 0x12, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74,
- 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
- 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68,
- 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x80, 0x83, 0x05, 0x20, 0x01, 0x28,
- 0x08, 0x52, 0x11, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65,
- 0x74, 0x68, 0x6f, 0x64, 0x3a, 0x39, 0x0a, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12,
- 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
- 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xe1,
- 0xc8, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x3a,
- 0x3f, 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1d, 0x2e,
- 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
- 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xe2, 0xc8, 0x05,
- 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79,
- 0x3a, 0x4c, 0x0a, 0x11, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x73,
- 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
- 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74,
- 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xe3, 0xc8, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x74, 0x61,
- 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x3a, 0x54,
- 0x0a, 0x15, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x70,
- 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
- 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f,
- 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xe4, 0xc8, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14,
- 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69,
- 0x74, 0x6f, 0x72, 0x79, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63,
- 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2d, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x69,
- 0x74, 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x34, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67,
- 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x33,
+ 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xfe,
+ 0x82, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70,
+ 0x74, 0x65, 0x64, 0x3a, 0x4f, 0x0a, 0x07, 0x6f, 0x70, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1e,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+ 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xff,
+ 0x82, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e,
+ 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x67, 0x52, 0x06, 0x6f, 0x70,
+ 0x54, 0x79, 0x70, 0x65, 0x3a, 0x4f, 0x0a, 0x12, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70,
+ 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74,
+ 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x80, 0x83, 0x05, 0x20, 0x01,
+ 0x28, 0x08, 0x52, 0x11, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x4d,
+ 0x65, 0x74, 0x68, 0x6f, 0x64, 0x3a, 0x39, 0x0a, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65,
+ 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
+ 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18,
+ 0xe1, 0xc8, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65,
+ 0x3a, 0x3f, 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1d,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+ 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xe2, 0xc8,
+ 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72,
+ 0x79, 0x3a, 0x4c, 0x0a, 0x11, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x70, 0x6f,
+ 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xe3, 0xc8, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x74,
+ 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x3a,
+ 0x54, 0x0a, 0x15, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x65,
+ 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64,
+ 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xe4, 0xc8, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52,
+ 0x14, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x70, 0x6f, 0x73,
+ 0x69, 0x74, 0x6f, 0x72, 0x79, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2d, 0x6f, 0x72, 0x67, 0x2f, 0x67,
+ 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x34, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
+ 0x67, 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x33,
}
var (
diff --git a/proto/go/gitalypb/ref.pb.go b/proto/go/gitalypb/ref.pb.go
index e2a4e4b97..116e1ac18 100644
--- a/proto/go/gitalypb/ref.pb.go
+++ b/proto/go/gitalypb/ref.pb.go
@@ -3255,7 +3255,7 @@ var file_ref_proto_rawDesc = []byte{
0x17, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x66,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c,
0x79, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x66, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x22, 0x09, 0x88, 0x02, 0x01, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x01, 0x12, 0x47, 0x0a,
+ 0x73, 0x65, 0x22, 0x09, 0x88, 0x02, 0x01, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x03, 0x12, 0x47, 0x0a,
0x08, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x66, 0x73, 0x12, 0x17, 0x2e, 0x67, 0x69, 0x74, 0x61,
0x6c, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x66, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x18, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74,
diff --git a/proto/go/gitalypb/repository-service.pb.go b/proto/go/gitalypb/repository-service.pb.go
index 4e346ae7e..54e49033c 100644
--- a/proto/go/gitalypb/repository-service.pb.go
+++ b/proto/go/gitalypb/repository-service.pb.go
@@ -5057,28 +5057,28 @@ var file_repository_service_proto_rawDesc = []byte{
0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x52, 0x65,
0x70, 0x61, 0x63, 0x6b, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x09, 0x88, 0x02, 0x01, 0xfa, 0x97, 0x28, 0x02,
- 0x08, 0x01, 0x12, 0x4e, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x61, 0x63, 0x6b, 0x46, 0x75, 0x6c, 0x6c,
+ 0x08, 0x03, 0x12, 0x4e, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x61, 0x63, 0x6b, 0x46, 0x75, 0x6c, 0x6c,
0x12, 0x19, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x52, 0x65, 0x70, 0x61, 0x63, 0x6b,
0x46, 0x75, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x67, 0x69,
0x74, 0x61, 0x6c, 0x79, 0x2e, 0x52, 0x65, 0x70, 0x61, 0x63, 0x6b, 0x46, 0x75, 0x6c, 0x6c, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x09, 0x88, 0x02, 0x01, 0xfa, 0x97, 0x28, 0x02,
- 0x08, 0x01, 0x12, 0x4e, 0x0a, 0x0a, 0x4d, 0x69, 0x64, 0x78, 0x52, 0x65, 0x70, 0x61, 0x63, 0x6b,
+ 0x08, 0x03, 0x12, 0x4e, 0x0a, 0x0a, 0x4d, 0x69, 0x64, 0x78, 0x52, 0x65, 0x70, 0x61, 0x63, 0x6b,
0x12, 0x19, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x4d, 0x69, 0x64, 0x78, 0x52, 0x65,
0x70, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x67, 0x69,
0x74, 0x61, 0x6c, 0x79, 0x2e, 0x4d, 0x69, 0x64, 0x78, 0x52, 0x65, 0x70, 0x61, 0x63, 0x6b, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x09, 0x88, 0x02, 0x01, 0xfa, 0x97, 0x28, 0x02,
- 0x08, 0x01, 0x12, 0x5a, 0x0a, 0x0e, 0x47, 0x61, 0x72, 0x62, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6c,
+ 0x08, 0x03, 0x12, 0x5a, 0x0a, 0x0e, 0x47, 0x61, 0x72, 0x62, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6c,
0x6c, 0x65, 0x63, 0x74, 0x12, 0x1d, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x47, 0x61,
0x72, 0x62, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x47, 0x61, 0x72,
0x62, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
- 0x6e, 0x73, 0x65, 0x22, 0x09, 0x88, 0x02, 0x01, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x01, 0x12, 0x60,
+ 0x6e, 0x73, 0x65, 0x22, 0x09, 0x88, 0x02, 0x01, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x03, 0x12, 0x60,
0x0a, 0x10, 0x57, 0x72, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x47, 0x72, 0x61,
0x70, 0x68, 0x12, 0x1f, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x57, 0x72, 0x69, 0x74,
0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x57, 0x72, 0x69,
0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x73,
- 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x09, 0x88, 0x02, 0x01, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x01,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x09, 0x88, 0x02, 0x01, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x03,
0x12, 0x57, 0x0a, 0x0e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x69,
0x7a, 0x65, 0x12, 0x1d, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x52, 0x65, 0x70, 0x6f,
0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
@@ -5196,7 +5196,7 @@ var file_repository_service_proto_rawDesc = []byte{
0x70, 0x12, 0x16, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x43, 0x6c, 0x65, 0x61, 0x6e,
0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x69, 0x74, 0x61,
0x6c, 0x79, 0x2e, 0x43, 0x6c, 0x65, 0x61, 0x6e, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x22, 0x09, 0x88, 0x02, 0x01, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x01, 0x12, 0x50, 0x0a,
+ 0x73, 0x65, 0x22, 0x09, 0x88, 0x02, 0x01, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x03, 0x12, 0x50, 0x0a,
0x0b, 0x47, 0x65, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x1a, 0x2e, 0x67,
0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f,
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c,
@@ -5273,14 +5273,14 @@ var file_repository_service_proto_rawDesc = []byte{
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79,
0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74,
0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28,
- 0x02, 0x08, 0x01, 0x12, 0x72, 0x0a, 0x17, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x55, 0x6e, 0x72, 0x65,
+ 0x02, 0x08, 0x03, 0x12, 0x72, 0x0a, 0x17, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x55, 0x6e, 0x72, 0x65,
0x61, 0x63, 0x68, 0x61, 0x62, 0x6c, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x26,
0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x55, 0x6e, 0x72,
0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x6c, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e,
0x50, 0x72, 0x75, 0x6e, 0x65, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x6c, 0x65,
0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
- 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x01, 0x12, 0x4e, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x46, 0x75,
+ 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x03, 0x12, 0x4e, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x46, 0x75,
0x6c, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1a, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e,
0x53, 0x65, 0x74, 0x46, 0x75, 0x6c, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x46,
diff --git a/proto/go/internal/linter/lint.go b/proto/go/internal/linter/lint.go
index 6d8ed34b6..48eb0f252 100644
--- a/proto/go/internal/linter/lint.go
+++ b/proto/go/internal/linter/lint.go
@@ -43,6 +43,9 @@ func ensureMethodOpType(fileDesc *descriptorpb.FileDescriptorProto, m *descripto
// if mutator, we need to make sure we specify scope or target repo
return ml.validateMutator()
+ case gitalypb.OperationMsg_MAINTENANCE:
+ return ml.validateMaintenance()
+
case gitalypb.OperationMsg_UNKNOWN:
return errors.New("op set to UNKNOWN")
diff --git a/proto/go/internal/linter/lint_test.go b/proto/go/internal/linter/lint_test.go
index bbf868d20..5747b3893 100644
--- a/proto/go/internal/linter/lint_test.go
+++ b/proto/go/internal/linter/lint_test.go
@@ -39,6 +39,14 @@ func TestLintFile(t *testing.T) {
formatError("go/internal/linter/testdata/invalid.proto", "InvalidService", "InvalidMethod13", errors.New("unexpected count of storage field 0, expected 1, found storage label at: []")),
formatError("go/internal/linter/testdata/invalid.proto", "InvalidService", "InvalidMethod14", errors.New("unexpected count of storage field 2, expected 1, found storage label at: [RequestWithMultipleNestedStorage.inner_message.storage_name RequestWithMultipleNestedStorage.storage_name]")),
formatError("go/internal/linter/testdata/invalid.proto", "InvalidService", "InvalidMethod15", errors.New("operation type defined on an intercepted method")),
+ formatError("go/internal/linter/testdata/invalid.proto", "InvalidService", "MaintenanceWithMissingRepository", errors.New("unexpected count of target_repository fields 0, expected 1, found target_repository label at: []")),
+ formatError("go/internal/linter/testdata/invalid.proto", "InvalidService", "MaintenanceWithUnflaggedRepository", errors.New("unexpected count of target_repository fields 0, expected 1, found target_repository label at: []")),
+ formatError("go/internal/linter/testdata/invalid.proto", "InvalidService", "MaintenanceWithWrongNestedRepositoryType", errors.New("wrong type of field RequestWithWrongTypeRepository.header.repository, expected .gitaly.Repository, got .test.InvalidMethodResponse")),
+ formatError("go/internal/linter/testdata/invalid.proto", "InvalidService", "MaintenanceWithInvalidTargetType", errors.New("unexpected count of target_repository fields 0, expected 1, found target_repository label at: []")),
+ formatError("go/internal/linter/testdata/invalid.proto", "InvalidService", "MaintenanceWithInvalidNestedRequest", errors.New("unexpected count of target_repository fields 0, expected 1, found target_repository label at: []")),
+ formatError("go/internal/linter/testdata/invalid.proto", "InvalidService", "MaintenanceWithStorageAndRepository", errors.New("unexpected count of storage field 1, expected 0, found storage label at: [RequestWithStorageAndRepo.storage_name]")),
+ formatError("go/internal/linter/testdata/invalid.proto", "InvalidService", "MaintenanceWithNestedStorageAndRepository", errors.New("unexpected count of storage field 1, expected 0, found storage label at: [RequestWithNestedStorageAndRepo.inner_message.storage_name]")),
+ formatError("go/internal/linter/testdata/invalid.proto", "InvalidService", "MaintenanceWithStorageScope", errors.New("unknown operation scope level 2")),
},
},
} {
diff --git a/proto/go/internal/linter/method.go b/proto/go/internal/linter/method.go
index 11ad03c36..b336f7f4f 100644
--- a/proto/go/internal/linter/method.go
+++ b/proto/go/internal/linter/method.go
@@ -49,6 +49,17 @@ func (ml methodLinter) validateMutator() error {
}
}
+// validateMaintenance ensures that the message is repository-scoped and that it's got a target
+// repository.
+func (ml methodLinter) validateMaintenance() error {
+ switch scope := ml.opMsg.GetScopeLevel(); scope {
+ case gitalypb.OperationMsg_REPOSITORY:
+ return ml.ensureValidRepoScope()
+ default:
+ return fmt.Errorf("unknown operation scope level %d", scope)
+ }
+}
+
func (ml methodLinter) ensureValidStorageScope() error {
if err := ml.ensureValidTargetRepository(0); err != nil {
return err
diff --git a/proto/go/internal/linter/testdata/invalid.pb.go b/proto/go/internal/linter/testdata/invalid.pb.go
index cc379716f..1252ad32f 100644
--- a/proto/go/internal/linter/testdata/invalid.pb.go
+++ b/proto/go/internal/linter/testdata/invalid.pb.go
@@ -828,7 +828,7 @@ var file_go_internal_linter_testdata_invalid_proto_rawDesc = []byte{
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x76,
0x61, 0x6c, 0x69, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x02, 0x1a, 0x04, 0xf0, 0x97, 0x28, 0x01,
- 0x32, 0xd9, 0x09, 0x0a, 0x0e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x53, 0x65, 0x72, 0x76,
+ 0x32, 0xc1, 0x10, 0x0a, 0x0e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x4d, 0x65,
0x74, 0x68, 0x6f, 0x64, 0x30, 0x12, 0x1a, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x76,
0x61, 0x6c, 0x69, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
@@ -905,12 +905,67 @@ var file_go_internal_linter_testdata_invalid_proto_rawDesc = []byte{
0x65, 0x73, 0x74, 0x57, 0x69, 0x74, 0x68, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x41, 0x6e,
0x64, 0x52, 0x65, 0x70, 0x6f, 0x1a, 0x1b, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x76,
0x61, 0x6c, 0x69, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x22, 0x08, 0x80, 0x98, 0x28, 0x01, 0xfa, 0x97, 0x28, 0x00, 0x42, 0x44, 0x5a, 0x42,
- 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61,
- 0x62, 0x2d, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x34,
- 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x61, 0x6c, 0x2f, 0x6c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61,
- 0x74, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x73, 0x65, 0x22, 0x08, 0x80, 0x98, 0x28, 0x01, 0xfa, 0x97, 0x28, 0x00, 0x12, 0x63, 0x0a, 0x20,
+ 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x57, 0x69, 0x74, 0x68, 0x4d,
+ 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79,
+ 0x12, 0x1a, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x4d,
+ 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x74,
+ 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f,
+ 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08,
+ 0x03, 0x12, 0x70, 0x0a, 0x22, 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65,
+ 0x57, 0x69, 0x74, 0x68, 0x55, 0x6e, 0x66, 0x6c, 0x61, 0x67, 0x67, 0x65, 0x64, 0x52, 0x65, 0x70,
+ 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x25, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x57, 0x69, 0x74, 0x68, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64,
+ 0x52, 0x65, 0x70, 0x6f, 0x4e, 0x6f, 0x74, 0x46, 0x6c, 0x61, 0x67, 0x67, 0x65, 0x64, 0x1a, 0x1b,
+ 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x4d, 0x65, 0x74,
+ 0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28,
+ 0x02, 0x08, 0x03, 0x12, 0x75, 0x0a, 0x28, 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e,
+ 0x63, 0x65, 0x57, 0x69, 0x74, 0x68, 0x57, 0x72, 0x6f, 0x6e, 0x67, 0x4e, 0x65, 0x73, 0x74, 0x65,
+ 0x64, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12,
+ 0x24, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x57, 0x69,
+ 0x74, 0x68, 0x57, 0x72, 0x6f, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73,
+ 0x69, 0x74, 0x6f, 0x72, 0x79, 0x1a, 0x1b, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x76,
+ 0x61, 0x6c, 0x69, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x03, 0x12, 0x60, 0x0a, 0x20, 0x4d, 0x61,
+ 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x57, 0x69, 0x74, 0x68, 0x49, 0x6e, 0x76,
+ 0x61, 0x6c, 0x69, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17,
+ 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x54, 0x61, 0x72,
+ 0x67, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x1a, 0x1b, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49,
+ 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x03, 0x12, 0x66, 0x0a, 0x23,
+ 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x57, 0x69, 0x74, 0x68, 0x49,
+ 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x1a, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c,
+ 0x69, 0x64, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+ 0x1b, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x4d, 0x65,
+ 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97,
+ 0x28, 0x02, 0x08, 0x03, 0x12, 0x6b, 0x0a, 0x23, 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61,
+ 0x6e, 0x63, 0x65, 0x57, 0x69, 0x74, 0x68, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x41, 0x6e,
+ 0x64, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1f, 0x2e, 0x74, 0x65,
+ 0x73, 0x74, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x57, 0x69, 0x74, 0x68, 0x53, 0x74,
+ 0x6f, 0x72, 0x61, 0x67, 0x65, 0x41, 0x6e, 0x64, 0x52, 0x65, 0x70, 0x6f, 0x1a, 0x1b, 0x2e, 0x74,
+ 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f,
+ 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08,
+ 0x03, 0x12, 0x77, 0x0a, 0x29, 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65,
+ 0x57, 0x69, 0x74, 0x68, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67,
+ 0x65, 0x41, 0x6e, 0x64, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x25,
+ 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x57, 0x69, 0x74,
+ 0x68, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x41, 0x6e,
+ 0x64, 0x52, 0x65, 0x70, 0x6f, 0x1a, 0x1b, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x76,
+ 0x61, 0x6c, 0x69, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x03, 0x12, 0x68, 0x0a, 0x1b, 0x4d, 0x61,
+ 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x57, 0x69, 0x74, 0x68, 0x53, 0x74, 0x6f,
+ 0x72, 0x61, 0x67, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x22, 0x2e, 0x74, 0x65, 0x73, 0x74,
+ 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x57, 0x69, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x1a, 0x1b, 0x2e,
+ 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x4d, 0x65, 0x74, 0x68,
+ 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0xfa, 0x97, 0x28, 0x04,
+ 0x08, 0x03, 0x10, 0x02, 0x42, 0x44, 0x5a, 0x42, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2d, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x69,
+ 0x74, 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x34, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67,
+ 0x6f, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x69, 0x6e, 0x74, 0x65,
+ 0x72, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x33,
}
var (
@@ -971,23 +1026,39 @@ var file_go_internal_linter_testdata_invalid_proto_depIdxs = []int32{
2, // 23: test.InvalidService.InvalidMethod13:input_type -> test.InvalidTargetType
8, // 24: test.InvalidService.InvalidMethod14:input_type -> test.RequestWithMultipleNestedStorage
6, // 25: test.InvalidService.InvalidMethod15:input_type -> test.RequestWithStorageAndRepo
- 3, // 26: test.InterceptedWithOperationType.InvalidMethod:output_type -> test.InvalidMethodResponse
- 3, // 27: test.InvalidService.InvalidMethod0:output_type -> test.InvalidMethodResponse
- 3, // 28: test.InvalidService.InvalidMethod1:output_type -> test.InvalidMethodResponse
- 3, // 29: test.InvalidService.InvalidMethod2:output_type -> test.InvalidMethodResponse
- 3, // 30: test.InvalidService.InvalidMethod4:output_type -> test.InvalidMethodResponse
- 3, // 31: test.InvalidService.InvalidMethod5:output_type -> test.InvalidMethodResponse
- 3, // 32: test.InvalidService.InvalidMethod6:output_type -> test.InvalidMethodResponse
- 3, // 33: test.InvalidService.InvalidMethod7:output_type -> test.InvalidMethodResponse
- 3, // 34: test.InvalidService.InvalidMethod8:output_type -> test.InvalidMethodResponse
- 3, // 35: test.InvalidService.InvalidMethod9:output_type -> test.InvalidMethodResponse
- 3, // 36: test.InvalidService.InvalidMethod10:output_type -> test.InvalidMethodResponse
- 3, // 37: test.InvalidService.InvalidMethod11:output_type -> test.InvalidMethodResponse
- 3, // 38: test.InvalidService.InvalidMethod13:output_type -> test.InvalidMethodResponse
- 3, // 39: test.InvalidService.InvalidMethod14:output_type -> test.InvalidMethodResponse
- 3, // 40: test.InvalidService.InvalidMethod15:output_type -> test.InvalidMethodResponse
- 26, // [26:41] is the sub-list for method output_type
- 11, // [11:26] is the sub-list for method input_type
+ 0, // 26: test.InvalidService.MaintenanceWithMissingRepository:input_type -> test.InvalidMethodRequest
+ 11, // 27: test.InvalidService.MaintenanceWithUnflaggedRepository:input_type -> test.RequestWithNestedRepoNotFlagged
+ 10, // 28: test.InvalidService.MaintenanceWithWrongNestedRepositoryType:input_type -> test.RequestWithWrongTypeRepository
+ 2, // 29: test.InvalidService.MaintenanceWithInvalidTargetType:input_type -> test.InvalidTargetType
+ 4, // 30: test.InvalidService.MaintenanceWithInvalidNestedRequest:input_type -> test.InvalidNestedRequest
+ 6, // 31: test.InvalidService.MaintenanceWithStorageAndRepository:input_type -> test.RequestWithStorageAndRepo
+ 7, // 32: test.InvalidService.MaintenanceWithNestedStorageAndRepository:input_type -> test.RequestWithNestedStorageAndRepo
+ 1, // 33: test.InvalidService.MaintenanceWithStorageScope:input_type -> test.InvalidMethodRequestWithRepo
+ 3, // 34: test.InterceptedWithOperationType.InvalidMethod:output_type -> test.InvalidMethodResponse
+ 3, // 35: test.InvalidService.InvalidMethod0:output_type -> test.InvalidMethodResponse
+ 3, // 36: test.InvalidService.InvalidMethod1:output_type -> test.InvalidMethodResponse
+ 3, // 37: test.InvalidService.InvalidMethod2:output_type -> test.InvalidMethodResponse
+ 3, // 38: test.InvalidService.InvalidMethod4:output_type -> test.InvalidMethodResponse
+ 3, // 39: test.InvalidService.InvalidMethod5:output_type -> test.InvalidMethodResponse
+ 3, // 40: test.InvalidService.InvalidMethod6:output_type -> test.InvalidMethodResponse
+ 3, // 41: test.InvalidService.InvalidMethod7:output_type -> test.InvalidMethodResponse
+ 3, // 42: test.InvalidService.InvalidMethod8:output_type -> test.InvalidMethodResponse
+ 3, // 43: test.InvalidService.InvalidMethod9:output_type -> test.InvalidMethodResponse
+ 3, // 44: test.InvalidService.InvalidMethod10:output_type -> test.InvalidMethodResponse
+ 3, // 45: test.InvalidService.InvalidMethod11:output_type -> test.InvalidMethodResponse
+ 3, // 46: test.InvalidService.InvalidMethod13:output_type -> test.InvalidMethodResponse
+ 3, // 47: test.InvalidService.InvalidMethod14:output_type -> test.InvalidMethodResponse
+ 3, // 48: test.InvalidService.InvalidMethod15:output_type -> test.InvalidMethodResponse
+ 3, // 49: test.InvalidService.MaintenanceWithMissingRepository:output_type -> test.InvalidMethodResponse
+ 3, // 50: test.InvalidService.MaintenanceWithUnflaggedRepository:output_type -> test.InvalidMethodResponse
+ 3, // 51: test.InvalidService.MaintenanceWithWrongNestedRepositoryType:output_type -> test.InvalidMethodResponse
+ 3, // 52: test.InvalidService.MaintenanceWithInvalidTargetType:output_type -> test.InvalidMethodResponse
+ 3, // 53: test.InvalidService.MaintenanceWithInvalidNestedRequest:output_type -> test.InvalidMethodResponse
+ 3, // 54: test.InvalidService.MaintenanceWithStorageAndRepository:output_type -> test.InvalidMethodResponse
+ 3, // 55: test.InvalidService.MaintenanceWithNestedStorageAndRepository:output_type -> test.InvalidMethodResponse
+ 3, // 56: test.InvalidService.MaintenanceWithStorageScope:output_type -> test.InvalidMethodResponse
+ 34, // [34:57] is the sub-list for method output_type
+ 11, // [11:34] is the sub-list for method input_type
11, // [11:11] is the sub-list for extension type_name
11, // [11:11] is the sub-list for extension extendee
0, // [0:11] is the sub-list for field type_name
diff --git a/proto/go/internal/linter/testdata/invalid.proto b/proto/go/internal/linter/testdata/invalid.proto
index a8c3ce54a..badafa4da 100644
--- a/proto/go/internal/linter/testdata/invalid.proto
+++ b/proto/go/internal/linter/testdata/invalid.proto
@@ -162,4 +162,50 @@ service InvalidService {
option (gitaly.intercepted_method) = true;
option (gitaly.op_type) = {};
};
+
+ rpc MaintenanceWithMissingRepository(InvalidMethodRequest) returns (InvalidMethodResponse) {
+ option (gitaly.op_type).op = MAINTENANCE;
+ }
+
+ rpc MaintenanceWithUnflaggedRepository(RequestWithNestedRepoNotFlagged) returns (InvalidMethodResponse) {
+ option (gitaly.op_type).op = MAINTENANCE;
+ }
+
+ rpc MaintenanceWithWrongNestedRepositoryType(RequestWithWrongTypeRepository) returns (InvalidMethodResponse) {
+ option (gitaly.op_type).op = MAINTENANCE;
+ }
+
+ rpc MaintenanceWithInvalidTargetType(InvalidTargetType) returns (InvalidMethodResponse) {
+ option (gitaly.op_type) = {
+ op: MAINTENANCE
+ };
+ }
+
+ rpc MaintenanceWithInvalidNestedRequest(InvalidNestedRequest) returns (InvalidMethodResponse) {
+ option (gitaly.op_type) = {
+ op: MAINTENANCE
+ };
+ }
+
+ rpc MaintenanceWithStorageAndRepository(RequestWithStorageAndRepo) returns (InvalidMethodResponse) {
+ option (gitaly.op_type) = {
+ op: MAINTENANCE
+ scope_level: REPOSITORY
+ };
+ }
+
+ rpc MaintenanceWithNestedStorageAndRepository(RequestWithNestedStorageAndRepo) returns (InvalidMethodResponse) {
+ option (gitaly.op_type) = {
+ op: MAINTENANCE
+ scope_level: REPOSITORY
+ };
+ }
+
+ rpc MaintenanceWithStorageScope(InvalidMethodRequestWithRepo) returns (InvalidMethodResponse) {
+ option (gitaly.op_type) = {
+ op: MAINTENANCE
+ scope_level: STORAGE
+ };
+ }
+
}
diff --git a/proto/go/internal/linter/testdata/invalid_grpc.pb.go b/proto/go/internal/linter/testdata/invalid_grpc.pb.go
index 2f109e568..02211b2f9 100644
--- a/proto/go/internal/linter/testdata/invalid_grpc.pb.go
+++ b/proto/go/internal/linter/testdata/invalid_grpc.pb.go
@@ -135,6 +135,14 @@ type InvalidServiceClient interface {
InvalidMethod14(ctx context.Context, in *RequestWithMultipleNestedStorage, opts ...grpc.CallOption) (*InvalidMethodResponse, error)
// Intercepted methods must not have operation type annotations.
InvalidMethod15(ctx context.Context, in *RequestWithStorageAndRepo, opts ...grpc.CallOption) (*InvalidMethodResponse, error)
+ MaintenanceWithMissingRepository(ctx context.Context, in *InvalidMethodRequest, opts ...grpc.CallOption) (*InvalidMethodResponse, error)
+ MaintenanceWithUnflaggedRepository(ctx context.Context, in *RequestWithNestedRepoNotFlagged, opts ...grpc.CallOption) (*InvalidMethodResponse, error)
+ MaintenanceWithWrongNestedRepositoryType(ctx context.Context, in *RequestWithWrongTypeRepository, opts ...grpc.CallOption) (*InvalidMethodResponse, error)
+ MaintenanceWithInvalidTargetType(ctx context.Context, in *InvalidTargetType, opts ...grpc.CallOption) (*InvalidMethodResponse, error)
+ MaintenanceWithInvalidNestedRequest(ctx context.Context, in *InvalidNestedRequest, opts ...grpc.CallOption) (*InvalidMethodResponse, error)
+ MaintenanceWithStorageAndRepository(ctx context.Context, in *RequestWithStorageAndRepo, opts ...grpc.CallOption) (*InvalidMethodResponse, error)
+ MaintenanceWithNestedStorageAndRepository(ctx context.Context, in *RequestWithNestedStorageAndRepo, opts ...grpc.CallOption) (*InvalidMethodResponse, error)
+ MaintenanceWithStorageScope(ctx context.Context, in *InvalidMethodRequestWithRepo, opts ...grpc.CallOption) (*InvalidMethodResponse, error)
}
type invalidServiceClient struct {
@@ -271,6 +279,78 @@ func (c *invalidServiceClient) InvalidMethod15(ctx context.Context, in *RequestW
return out, nil
}
+func (c *invalidServiceClient) MaintenanceWithMissingRepository(ctx context.Context, in *InvalidMethodRequest, opts ...grpc.CallOption) (*InvalidMethodResponse, error) {
+ out := new(InvalidMethodResponse)
+ err := c.cc.Invoke(ctx, "/test.InvalidService/MaintenanceWithMissingRepository", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *invalidServiceClient) MaintenanceWithUnflaggedRepository(ctx context.Context, in *RequestWithNestedRepoNotFlagged, opts ...grpc.CallOption) (*InvalidMethodResponse, error) {
+ out := new(InvalidMethodResponse)
+ err := c.cc.Invoke(ctx, "/test.InvalidService/MaintenanceWithUnflaggedRepository", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *invalidServiceClient) MaintenanceWithWrongNestedRepositoryType(ctx context.Context, in *RequestWithWrongTypeRepository, opts ...grpc.CallOption) (*InvalidMethodResponse, error) {
+ out := new(InvalidMethodResponse)
+ err := c.cc.Invoke(ctx, "/test.InvalidService/MaintenanceWithWrongNestedRepositoryType", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *invalidServiceClient) MaintenanceWithInvalidTargetType(ctx context.Context, in *InvalidTargetType, opts ...grpc.CallOption) (*InvalidMethodResponse, error) {
+ out := new(InvalidMethodResponse)
+ err := c.cc.Invoke(ctx, "/test.InvalidService/MaintenanceWithInvalidTargetType", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *invalidServiceClient) MaintenanceWithInvalidNestedRequest(ctx context.Context, in *InvalidNestedRequest, opts ...grpc.CallOption) (*InvalidMethodResponse, error) {
+ out := new(InvalidMethodResponse)
+ err := c.cc.Invoke(ctx, "/test.InvalidService/MaintenanceWithInvalidNestedRequest", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *invalidServiceClient) MaintenanceWithStorageAndRepository(ctx context.Context, in *RequestWithStorageAndRepo, opts ...grpc.CallOption) (*InvalidMethodResponse, error) {
+ out := new(InvalidMethodResponse)
+ err := c.cc.Invoke(ctx, "/test.InvalidService/MaintenanceWithStorageAndRepository", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *invalidServiceClient) MaintenanceWithNestedStorageAndRepository(ctx context.Context, in *RequestWithNestedStorageAndRepo, opts ...grpc.CallOption) (*InvalidMethodResponse, error) {
+ out := new(InvalidMethodResponse)
+ err := c.cc.Invoke(ctx, "/test.InvalidService/MaintenanceWithNestedStorageAndRepository", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *invalidServiceClient) MaintenanceWithStorageScope(ctx context.Context, in *InvalidMethodRequestWithRepo, opts ...grpc.CallOption) (*InvalidMethodResponse, error) {
+ out := new(InvalidMethodResponse)
+ err := c.cc.Invoke(ctx, "/test.InvalidService/MaintenanceWithStorageScope", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
// InvalidServiceServer is the server API for InvalidService service.
// All implementations must embed UnimplementedInvalidServiceServer
// for forward compatibility
@@ -303,6 +383,14 @@ type InvalidServiceServer interface {
InvalidMethod14(context.Context, *RequestWithMultipleNestedStorage) (*InvalidMethodResponse, error)
// Intercepted methods must not have operation type annotations.
InvalidMethod15(context.Context, *RequestWithStorageAndRepo) (*InvalidMethodResponse, error)
+ MaintenanceWithMissingRepository(context.Context, *InvalidMethodRequest) (*InvalidMethodResponse, error)
+ MaintenanceWithUnflaggedRepository(context.Context, *RequestWithNestedRepoNotFlagged) (*InvalidMethodResponse, error)
+ MaintenanceWithWrongNestedRepositoryType(context.Context, *RequestWithWrongTypeRepository) (*InvalidMethodResponse, error)
+ MaintenanceWithInvalidTargetType(context.Context, *InvalidTargetType) (*InvalidMethodResponse, error)
+ MaintenanceWithInvalidNestedRequest(context.Context, *InvalidNestedRequest) (*InvalidMethodResponse, error)
+ MaintenanceWithStorageAndRepository(context.Context, *RequestWithStorageAndRepo) (*InvalidMethodResponse, error)
+ MaintenanceWithNestedStorageAndRepository(context.Context, *RequestWithNestedStorageAndRepo) (*InvalidMethodResponse, error)
+ MaintenanceWithStorageScope(context.Context, *InvalidMethodRequestWithRepo) (*InvalidMethodResponse, error)
mustEmbedUnimplementedInvalidServiceServer()
}
@@ -352,6 +440,30 @@ func (UnimplementedInvalidServiceServer) InvalidMethod14(context.Context, *Reque
func (UnimplementedInvalidServiceServer) InvalidMethod15(context.Context, *RequestWithStorageAndRepo) (*InvalidMethodResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method InvalidMethod15 not implemented")
}
+func (UnimplementedInvalidServiceServer) MaintenanceWithMissingRepository(context.Context, *InvalidMethodRequest) (*InvalidMethodResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method MaintenanceWithMissingRepository not implemented")
+}
+func (UnimplementedInvalidServiceServer) MaintenanceWithUnflaggedRepository(context.Context, *RequestWithNestedRepoNotFlagged) (*InvalidMethodResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method MaintenanceWithUnflaggedRepository not implemented")
+}
+func (UnimplementedInvalidServiceServer) MaintenanceWithWrongNestedRepositoryType(context.Context, *RequestWithWrongTypeRepository) (*InvalidMethodResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method MaintenanceWithWrongNestedRepositoryType not implemented")
+}
+func (UnimplementedInvalidServiceServer) MaintenanceWithInvalidTargetType(context.Context, *InvalidTargetType) (*InvalidMethodResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method MaintenanceWithInvalidTargetType not implemented")
+}
+func (UnimplementedInvalidServiceServer) MaintenanceWithInvalidNestedRequest(context.Context, *InvalidNestedRequest) (*InvalidMethodResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method MaintenanceWithInvalidNestedRequest not implemented")
+}
+func (UnimplementedInvalidServiceServer) MaintenanceWithStorageAndRepository(context.Context, *RequestWithStorageAndRepo) (*InvalidMethodResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method MaintenanceWithStorageAndRepository not implemented")
+}
+func (UnimplementedInvalidServiceServer) MaintenanceWithNestedStorageAndRepository(context.Context, *RequestWithNestedStorageAndRepo) (*InvalidMethodResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method MaintenanceWithNestedStorageAndRepository not implemented")
+}
+func (UnimplementedInvalidServiceServer) MaintenanceWithStorageScope(context.Context, *InvalidMethodRequestWithRepo) (*InvalidMethodResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method MaintenanceWithStorageScope not implemented")
+}
func (UnimplementedInvalidServiceServer) mustEmbedUnimplementedInvalidServiceServer() {}
// UnsafeInvalidServiceServer may be embedded to opt out of forward compatibility for this service.
@@ -617,6 +729,150 @@ func _InvalidService_InvalidMethod15_Handler(srv interface{}, ctx context.Contex
return interceptor(ctx, in, info, handler)
}
+func _InvalidService_MaintenanceWithMissingRepository_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(InvalidMethodRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(InvalidServiceServer).MaintenanceWithMissingRepository(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/test.InvalidService/MaintenanceWithMissingRepository",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(InvalidServiceServer).MaintenanceWithMissingRepository(ctx, req.(*InvalidMethodRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _InvalidService_MaintenanceWithUnflaggedRepository_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RequestWithNestedRepoNotFlagged)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(InvalidServiceServer).MaintenanceWithUnflaggedRepository(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/test.InvalidService/MaintenanceWithUnflaggedRepository",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(InvalidServiceServer).MaintenanceWithUnflaggedRepository(ctx, req.(*RequestWithNestedRepoNotFlagged))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _InvalidService_MaintenanceWithWrongNestedRepositoryType_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RequestWithWrongTypeRepository)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(InvalidServiceServer).MaintenanceWithWrongNestedRepositoryType(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/test.InvalidService/MaintenanceWithWrongNestedRepositoryType",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(InvalidServiceServer).MaintenanceWithWrongNestedRepositoryType(ctx, req.(*RequestWithWrongTypeRepository))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _InvalidService_MaintenanceWithInvalidTargetType_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(InvalidTargetType)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(InvalidServiceServer).MaintenanceWithInvalidTargetType(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/test.InvalidService/MaintenanceWithInvalidTargetType",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(InvalidServiceServer).MaintenanceWithInvalidTargetType(ctx, req.(*InvalidTargetType))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _InvalidService_MaintenanceWithInvalidNestedRequest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(InvalidNestedRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(InvalidServiceServer).MaintenanceWithInvalidNestedRequest(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/test.InvalidService/MaintenanceWithInvalidNestedRequest",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(InvalidServiceServer).MaintenanceWithInvalidNestedRequest(ctx, req.(*InvalidNestedRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _InvalidService_MaintenanceWithStorageAndRepository_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RequestWithStorageAndRepo)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(InvalidServiceServer).MaintenanceWithStorageAndRepository(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/test.InvalidService/MaintenanceWithStorageAndRepository",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(InvalidServiceServer).MaintenanceWithStorageAndRepository(ctx, req.(*RequestWithStorageAndRepo))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _InvalidService_MaintenanceWithNestedStorageAndRepository_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RequestWithNestedStorageAndRepo)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(InvalidServiceServer).MaintenanceWithNestedStorageAndRepository(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/test.InvalidService/MaintenanceWithNestedStorageAndRepository",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(InvalidServiceServer).MaintenanceWithNestedStorageAndRepository(ctx, req.(*RequestWithNestedStorageAndRepo))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _InvalidService_MaintenanceWithStorageScope_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(InvalidMethodRequestWithRepo)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(InvalidServiceServer).MaintenanceWithStorageScope(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/test.InvalidService/MaintenanceWithStorageScope",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(InvalidServiceServer).MaintenanceWithStorageScope(ctx, req.(*InvalidMethodRequestWithRepo))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
// InvalidService_ServiceDesc is the grpc.ServiceDesc for InvalidService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -680,6 +936,38 @@ var InvalidService_ServiceDesc = grpc.ServiceDesc{
MethodName: "InvalidMethod15",
Handler: _InvalidService_InvalidMethod15_Handler,
},
+ {
+ MethodName: "MaintenanceWithMissingRepository",
+ Handler: _InvalidService_MaintenanceWithMissingRepository_Handler,
+ },
+ {
+ MethodName: "MaintenanceWithUnflaggedRepository",
+ Handler: _InvalidService_MaintenanceWithUnflaggedRepository_Handler,
+ },
+ {
+ MethodName: "MaintenanceWithWrongNestedRepositoryType",
+ Handler: _InvalidService_MaintenanceWithWrongNestedRepositoryType_Handler,
+ },
+ {
+ MethodName: "MaintenanceWithInvalidTargetType",
+ Handler: _InvalidService_MaintenanceWithInvalidTargetType_Handler,
+ },
+ {
+ MethodName: "MaintenanceWithInvalidNestedRequest",
+ Handler: _InvalidService_MaintenanceWithInvalidNestedRequest_Handler,
+ },
+ {
+ MethodName: "MaintenanceWithStorageAndRepository",
+ Handler: _InvalidService_MaintenanceWithStorageAndRepository_Handler,
+ },
+ {
+ MethodName: "MaintenanceWithNestedStorageAndRepository",
+ Handler: _InvalidService_MaintenanceWithNestedStorageAndRepository_Handler,
+ },
+ {
+ MethodName: "MaintenanceWithStorageScope",
+ Handler: _InvalidService_MaintenanceWithStorageScope_Handler,
+ },
},
Streams: []grpc.StreamDesc{},
Metadata: "go/internal/linter/testdata/invalid.proto",
diff --git a/proto/go/internal/linter/testdata/valid.pb.go b/proto/go/internal/linter/testdata/valid.pb.go
index b136201be..2885e8430 100644
--- a/proto/go/internal/linter/testdata/valid.pb.go
+++ b/proto/go/internal/linter/testdata/valid.pb.go
@@ -581,7 +581,7 @@ var file_go_internal_linter_testdata_valid_proto_rawDesc = []byte{
0x12, 0x12, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x69,
0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x04, 0xf0, 0x97, 0x28, 0x01, 0x32,
- 0x88, 0x05, 0x0a, 0x0c, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
+ 0xc4, 0x08, 0x0a, 0x0c, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x12, 0x3d, 0x0a, 0x0a, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x12,
0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x13, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x52,
@@ -621,12 +621,40 @@ var file_go_internal_linter_testdata_valid_proto_rawDesc = []byte{
0x6f, 0x64, 0x31, 0x30, 0x12, 0x19, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x69,
0x64, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x13, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x04, 0x80, 0x98, 0x28, 0x01, 0x42, 0x44, 0x5a, 0x42, 0x67, 0x69,
- 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2d,
- 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x34, 0x2f, 0x70,
- 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
- 0x2f, 0x6c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61,
- 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x04, 0x80, 0x98, 0x28, 0x01, 0x12, 0x42, 0x0a, 0x0f, 0x54, 0x65,
+ 0x73, 0x74, 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x2e,
+ 0x74, 0x65, 0x73, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x1a, 0x13, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x03, 0x12, 0x53,
+ 0x0a, 0x20, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63,
+ 0x65, 0x57, 0x69, 0x74, 0x68, 0x45, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x53, 0x63, 0x6f,
+ 0x70, 0x65, 0x12, 0x12, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x56, 0x61,
+ 0x6c, 0x69, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28,
+ 0x02, 0x08, 0x03, 0x12, 0x59, 0x0a, 0x20, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x61, 0x69, 0x6e, 0x74,
+ 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x57, 0x69, 0x74, 0x68, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x56,
+ 0x61, 0x6c, 0x69, 0x64, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x1a, 0x13, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28, 0x02, 0x08, 0x03, 0x12, 0x65,
+ 0x0a, 0x26, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63,
+ 0x65, 0x57, 0x69, 0x74, 0x68, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x68, 0x61, 0x72, 0x65,
+ 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e,
+ 0x56, 0x61, 0x6c, 0x69, 0x64, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x68, 0x61, 0x72, 0x65,
+ 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e,
+ 0x56, 0x61, 0x6c, 0x69, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa,
+ 0x97, 0x28, 0x02, 0x08, 0x03, 0x12, 0x5f, 0x0a, 0x21, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x75, 0x74,
+ 0x61, 0x74, 0x6f, 0x72, 0x57, 0x69, 0x74, 0x68, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x4e, 0x65, 0x73,
+ 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x2e, 0x74, 0x65, 0x73,
+ 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x4e, 0x65, 0x73, 0x74,
+ 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x74, 0x65, 0x73, 0x74,
+ 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06,
+ 0xfa, 0x97, 0x28, 0x02, 0x08, 0x03, 0x42, 0x44, 0x5a, 0x42, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2d, 0x6f, 0x72, 0x67, 0x2f,
+ 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x34, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2f, 0x67, 0x6f, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x69, 0x6e,
+ 0x74, 0x65, 0x72, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x62, 0x06, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -675,18 +703,28 @@ var file_go_internal_linter_testdata_valid_proto_depIdxs = []int32{
2, // 14: test.ValidService.TestMethod8:input_type -> test.ValidStorageRequest
5, // 15: test.ValidService.TestMethod9:input_type -> test.ValidStorageNestedRequest
2, // 16: test.ValidService.TestMethod10:input_type -> test.ValidStorageRequest
- 3, // 17: test.InterceptedService.TestMethod:output_type -> test.ValidResponse
- 3, // 18: test.ValidService.TestMethod:output_type -> test.ValidResponse
- 3, // 19: test.ValidService.TestMethod2:output_type -> test.ValidResponse
- 3, // 20: test.ValidService.TestMethod3:output_type -> test.ValidResponse
- 3, // 21: test.ValidService.TestMethod5:output_type -> test.ValidResponse
- 3, // 22: test.ValidService.TestMethod6:output_type -> test.ValidResponse
- 3, // 23: test.ValidService.TestMethod7:output_type -> test.ValidResponse
- 3, // 24: test.ValidService.TestMethod8:output_type -> test.ValidResponse
- 3, // 25: test.ValidService.TestMethod9:output_type -> test.ValidResponse
- 3, // 26: test.ValidService.TestMethod10:output_type -> test.ValidResponse
- 17, // [17:27] is the sub-list for method output_type
- 7, // [7:17] is the sub-list for method input_type
+ 0, // 17: test.ValidService.TestMaintenance:input_type -> test.ValidRequest
+ 0, // 18: test.ValidService.TestMaintenanceWithExplicitScope:input_type -> test.ValidRequest
+ 4, // 19: test.ValidService.TestMaintenanceWithNestedRequest:input_type -> test.ValidNestedRequest
+ 6, // 20: test.ValidService.TestMaintenanceWithNestedSharedRequest:input_type -> test.ValidNestedSharedRequest
+ 7, // 21: test.ValidService.TestMutatorWithInnerNestedRequest:input_type -> test.ValidInnerNestedRequest
+ 3, // 22: test.InterceptedService.TestMethod:output_type -> test.ValidResponse
+ 3, // 23: test.ValidService.TestMethod:output_type -> test.ValidResponse
+ 3, // 24: test.ValidService.TestMethod2:output_type -> test.ValidResponse
+ 3, // 25: test.ValidService.TestMethod3:output_type -> test.ValidResponse
+ 3, // 26: test.ValidService.TestMethod5:output_type -> test.ValidResponse
+ 3, // 27: test.ValidService.TestMethod6:output_type -> test.ValidResponse
+ 3, // 28: test.ValidService.TestMethod7:output_type -> test.ValidResponse
+ 3, // 29: test.ValidService.TestMethod8:output_type -> test.ValidResponse
+ 3, // 30: test.ValidService.TestMethod9:output_type -> test.ValidResponse
+ 3, // 31: test.ValidService.TestMethod10:output_type -> test.ValidResponse
+ 3, // 32: test.ValidService.TestMaintenance:output_type -> test.ValidResponse
+ 3, // 33: test.ValidService.TestMaintenanceWithExplicitScope:output_type -> test.ValidResponse
+ 3, // 34: test.ValidService.TestMaintenanceWithNestedRequest:output_type -> test.ValidResponse
+ 3, // 35: test.ValidService.TestMaintenanceWithNestedSharedRequest:output_type -> test.ValidResponse
+ 3, // 36: test.ValidService.TestMutatorWithInnerNestedRequest:output_type -> test.ValidResponse
+ 22, // [22:37] is the sub-list for method output_type
+ 7, // [7:22] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name
diff --git a/proto/go/internal/linter/testdata/valid.proto b/proto/go/internal/linter/testdata/valid.proto
index 0e3614792..9d1c9532e 100644
--- a/proto/go/internal/linter/testdata/valid.proto
+++ b/proto/go/internal/linter/testdata/valid.proto
@@ -112,4 +112,36 @@ service ValidService {
rpc TestMethod10(ValidStorageRequest) returns (ValidResponse) {
option (gitaly.intercepted_method) = true;
}
+
+ rpc TestMaintenance(ValidRequest) returns (ValidResponse) {
+ option (gitaly.op_type) = {
+ op: MAINTENANCE
+ };
+ }
+
+ rpc TestMaintenanceWithExplicitScope(ValidRequest) returns (ValidResponse) {
+ option (gitaly.op_type) = {
+ op: MAINTENANCE
+ scope_level: REPOSITORY // repo can be explicitly included
+ };
+ }
+
+ rpc TestMaintenanceWithNestedRequest(ValidNestedRequest) returns (ValidResponse) {
+ option (gitaly.op_type) = {
+ op: MAINTENANCE
+ };
+ }
+
+ rpc TestMaintenanceWithNestedSharedRequest(ValidNestedSharedRequest) returns (ValidResponse) {
+ option (gitaly.op_type) = {
+ op: MAINTENANCE
+ };
+ }
+
+ rpc TestMutatorWithInnerNestedRequest(ValidInnerNestedRequest) returns (ValidResponse) {
+ option (gitaly.op_type) = {
+ op: MAINTENANCE
+ };
+ }
+
}
diff --git a/proto/go/internal/linter/testdata/valid_grpc.pb.go b/proto/go/internal/linter/testdata/valid_grpc.pb.go
index d545af891..c9d929b1f 100644
--- a/proto/go/internal/linter/testdata/valid_grpc.pb.go
+++ b/proto/go/internal/linter/testdata/valid_grpc.pb.go
@@ -114,6 +114,11 @@ type ValidServiceClient interface {
TestMethod9(ctx context.Context, in *ValidStorageNestedRequest, opts ...grpc.CallOption) (*ValidResponse, error)
// Intercepted methods do not need operation type annotations.
TestMethod10(ctx context.Context, in *ValidStorageRequest, opts ...grpc.CallOption) (*ValidResponse, error)
+ TestMaintenance(ctx context.Context, in *ValidRequest, opts ...grpc.CallOption) (*ValidResponse, error)
+ TestMaintenanceWithExplicitScope(ctx context.Context, in *ValidRequest, opts ...grpc.CallOption) (*ValidResponse, error)
+ TestMaintenanceWithNestedRequest(ctx context.Context, in *ValidNestedRequest, opts ...grpc.CallOption) (*ValidResponse, error)
+ TestMaintenanceWithNestedSharedRequest(ctx context.Context, in *ValidNestedSharedRequest, opts ...grpc.CallOption) (*ValidResponse, error)
+ TestMutatorWithInnerNestedRequest(ctx context.Context, in *ValidInnerNestedRequest, opts ...grpc.CallOption) (*ValidResponse, error)
}
type validServiceClient struct {
@@ -205,6 +210,51 @@ func (c *validServiceClient) TestMethod10(ctx context.Context, in *ValidStorageR
return out, nil
}
+func (c *validServiceClient) TestMaintenance(ctx context.Context, in *ValidRequest, opts ...grpc.CallOption) (*ValidResponse, error) {
+ out := new(ValidResponse)
+ err := c.cc.Invoke(ctx, "/test.ValidService/TestMaintenance", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *validServiceClient) TestMaintenanceWithExplicitScope(ctx context.Context, in *ValidRequest, opts ...grpc.CallOption) (*ValidResponse, error) {
+ out := new(ValidResponse)
+ err := c.cc.Invoke(ctx, "/test.ValidService/TestMaintenanceWithExplicitScope", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *validServiceClient) TestMaintenanceWithNestedRequest(ctx context.Context, in *ValidNestedRequest, opts ...grpc.CallOption) (*ValidResponse, error) {
+ out := new(ValidResponse)
+ err := c.cc.Invoke(ctx, "/test.ValidService/TestMaintenanceWithNestedRequest", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *validServiceClient) TestMaintenanceWithNestedSharedRequest(ctx context.Context, in *ValidNestedSharedRequest, opts ...grpc.CallOption) (*ValidResponse, error) {
+ out := new(ValidResponse)
+ err := c.cc.Invoke(ctx, "/test.ValidService/TestMaintenanceWithNestedSharedRequest", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *validServiceClient) TestMutatorWithInnerNestedRequest(ctx context.Context, in *ValidInnerNestedRequest, opts ...grpc.CallOption) (*ValidResponse, error) {
+ out := new(ValidResponse)
+ err := c.cc.Invoke(ctx, "/test.ValidService/TestMutatorWithInnerNestedRequest", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
// ValidServiceServer is the server API for ValidService service.
// All implementations must embed UnimplementedValidServiceServer
// for forward compatibility
@@ -219,6 +269,11 @@ type ValidServiceServer interface {
TestMethod9(context.Context, *ValidStorageNestedRequest) (*ValidResponse, error)
// Intercepted methods do not need operation type annotations.
TestMethod10(context.Context, *ValidStorageRequest) (*ValidResponse, error)
+ TestMaintenance(context.Context, *ValidRequest) (*ValidResponse, error)
+ TestMaintenanceWithExplicitScope(context.Context, *ValidRequest) (*ValidResponse, error)
+ TestMaintenanceWithNestedRequest(context.Context, *ValidNestedRequest) (*ValidResponse, error)
+ TestMaintenanceWithNestedSharedRequest(context.Context, *ValidNestedSharedRequest) (*ValidResponse, error)
+ TestMutatorWithInnerNestedRequest(context.Context, *ValidInnerNestedRequest) (*ValidResponse, error)
mustEmbedUnimplementedValidServiceServer()
}
@@ -253,6 +308,21 @@ func (UnimplementedValidServiceServer) TestMethod9(context.Context, *ValidStorag
func (UnimplementedValidServiceServer) TestMethod10(context.Context, *ValidStorageRequest) (*ValidResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method TestMethod10 not implemented")
}
+func (UnimplementedValidServiceServer) TestMaintenance(context.Context, *ValidRequest) (*ValidResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method TestMaintenance not implemented")
+}
+func (UnimplementedValidServiceServer) TestMaintenanceWithExplicitScope(context.Context, *ValidRequest) (*ValidResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method TestMaintenanceWithExplicitScope not implemented")
+}
+func (UnimplementedValidServiceServer) TestMaintenanceWithNestedRequest(context.Context, *ValidNestedRequest) (*ValidResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method TestMaintenanceWithNestedRequest not implemented")
+}
+func (UnimplementedValidServiceServer) TestMaintenanceWithNestedSharedRequest(context.Context, *ValidNestedSharedRequest) (*ValidResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method TestMaintenanceWithNestedSharedRequest not implemented")
+}
+func (UnimplementedValidServiceServer) TestMutatorWithInnerNestedRequest(context.Context, *ValidInnerNestedRequest) (*ValidResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method TestMutatorWithInnerNestedRequest not implemented")
+}
func (UnimplementedValidServiceServer) mustEmbedUnimplementedValidServiceServer() {}
// UnsafeValidServiceServer may be embedded to opt out of forward compatibility for this service.
@@ -428,6 +498,96 @@ func _ValidService_TestMethod10_Handler(srv interface{}, ctx context.Context, de
return interceptor(ctx, in, info, handler)
}
+func _ValidService_TestMaintenance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ValidRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(ValidServiceServer).TestMaintenance(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/test.ValidService/TestMaintenance",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(ValidServiceServer).TestMaintenance(ctx, req.(*ValidRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _ValidService_TestMaintenanceWithExplicitScope_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ValidRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(ValidServiceServer).TestMaintenanceWithExplicitScope(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/test.ValidService/TestMaintenanceWithExplicitScope",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(ValidServiceServer).TestMaintenanceWithExplicitScope(ctx, req.(*ValidRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _ValidService_TestMaintenanceWithNestedRequest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ValidNestedRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(ValidServiceServer).TestMaintenanceWithNestedRequest(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/test.ValidService/TestMaintenanceWithNestedRequest",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(ValidServiceServer).TestMaintenanceWithNestedRequest(ctx, req.(*ValidNestedRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _ValidService_TestMaintenanceWithNestedSharedRequest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ValidNestedSharedRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(ValidServiceServer).TestMaintenanceWithNestedSharedRequest(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/test.ValidService/TestMaintenanceWithNestedSharedRequest",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(ValidServiceServer).TestMaintenanceWithNestedSharedRequest(ctx, req.(*ValidNestedSharedRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _ValidService_TestMutatorWithInnerNestedRequest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ValidInnerNestedRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(ValidServiceServer).TestMutatorWithInnerNestedRequest(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/test.ValidService/TestMutatorWithInnerNestedRequest",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(ValidServiceServer).TestMutatorWithInnerNestedRequest(ctx, req.(*ValidInnerNestedRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
// ValidService_ServiceDesc is the grpc.ServiceDesc for ValidService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -471,6 +631,26 @@ var ValidService_ServiceDesc = grpc.ServiceDesc{
MethodName: "TestMethod10",
Handler: _ValidService_TestMethod10_Handler,
},
+ {
+ MethodName: "TestMaintenance",
+ Handler: _ValidService_TestMaintenance_Handler,
+ },
+ {
+ MethodName: "TestMaintenanceWithExplicitScope",
+ Handler: _ValidService_TestMaintenanceWithExplicitScope_Handler,
+ },
+ {
+ MethodName: "TestMaintenanceWithNestedRequest",
+ Handler: _ValidService_TestMaintenanceWithNestedRequest_Handler,
+ },
+ {
+ MethodName: "TestMaintenanceWithNestedSharedRequest",
+ Handler: _ValidService_TestMaintenanceWithNestedSharedRequest_Handler,
+ },
+ {
+ MethodName: "TestMutatorWithInnerNestedRequest",
+ Handler: _ValidService_TestMutatorWithInnerNestedRequest_Handler,
+ },
},
Streams: []grpc.StreamDesc{},
Metadata: "go/internal/linter/testdata/valid.proto",
diff --git a/proto/lint.proto b/proto/lint.proto
index 572cc6c7f..e656e1710 100644
--- a/proto/lint.proto
+++ b/proto/lint.proto
@@ -11,6 +11,7 @@ message OperationMsg {
UNKNOWN = 0;
MUTATOR = 1;
ACCESSOR = 2;
+ MAINTENANCE = 3;
}
Operation op = 1;
diff --git a/proto/ref.proto b/proto/ref.proto
index 21cdfa9dd..72eb62c35 100644
--- a/proto/ref.proto
+++ b/proto/ref.proto
@@ -102,7 +102,7 @@ service RefService {
rpc PackRefs(PackRefsRequest) returns (PackRefsResponse) {
option deprecated = true;
option (op_type) = {
- op: MUTATOR
+ op: MAINTENANCE
};
}
diff --git a/proto/repository-service.proto b/proto/repository-service.proto
index bb8660ceb..3fda65d1c 100644
--- a/proto/repository-service.proto
+++ b/proto/repository-service.proto
@@ -18,7 +18,7 @@ service RepositoryService {
rpc RepackIncremental(RepackIncrementalRequest) returns (RepackIncrementalResponse) {
option deprecated = true;
option (op_type) = {
- op: MUTATOR
+ op: MAINTENANCE
};
}
@@ -26,7 +26,7 @@ service RepositoryService {
rpc RepackFull(RepackFullRequest) returns (RepackFullResponse) {
option deprecated = true;
option (op_type) = {
- op: MUTATOR
+ op: MAINTENANCE
};
}
@@ -34,7 +34,7 @@ service RepositoryService {
rpc MidxRepack(MidxRepackRequest) returns (MidxRepackResponse) {
option deprecated = true;
option (op_type) = {
- op: MUTATOR
+ op: MAINTENANCE
};
}
@@ -42,7 +42,7 @@ service RepositoryService {
rpc GarbageCollect(GarbageCollectRequest) returns (GarbageCollectResponse) {
option deprecated = true;
option (op_type) = {
- op: MUTATOR
+ op: MAINTENANCE
};
}
@@ -50,7 +50,7 @@ service RepositoryService {
rpc WriteCommitGraph(WriteCommitGraphRequest) returns (WriteCommitGraphResponse) {
option deprecated = true;
option (op_type) = {
- op: MUTATOR
+ op: MAINTENANCE
};
}
@@ -180,7 +180,7 @@ service RepositoryService {
rpc Cleanup(CleanupRequest) returns (CleanupResponse) {
option deprecated = true;
option (op_type) = {
- op: MUTATOR
+ op: MAINTENANCE
};
}
@@ -251,7 +251,7 @@ service RepositoryService {
// Gitaly has complete control of the on-disk state of repositories.
rpc OptimizeRepository(OptimizeRepositoryRequest) returns (OptimizeRepositoryResponse) {
option (op_type) = {
- op: MUTATOR
+ op: MAINTENANCE
};
}
@@ -268,7 +268,7 @@ service RepositoryService {
// wait 30 minutes, and then call PruneUnreachableObjects.
rpc PruneUnreachableObjects(PruneUnreachableObjectsRequest) returns (PruneUnreachableObjectsResponse) {
option (op_type) = {
- op: MUTATOR
+ op: MAINTENANCE
};
}
diff --git a/ruby/proto/gitaly/lint_pb.rb b/ruby/proto/gitaly/lint_pb.rb
index 6ab97305d..2cfe612e0 100644
--- a/ruby/proto/gitaly/lint_pb.rb
+++ b/ruby/proto/gitaly/lint_pb.rb
@@ -14,6 +14,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
value :UNKNOWN, 0
value :MUTATOR, 1
value :ACCESSOR, 2
+ value :MAINTENANCE, 3
end
add_enum "gitaly.OperationMsg.Scope" do
value :REPOSITORY, 0