Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions entity/mergestrategy/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
load("@rules_go//go:def.bzl", "go_library")

go_library(
name = "mergestrategy",
srcs = ["mergestrategy.go"],
importpath = "github.com/uber/submitqueue/entity/mergestrategy",
visibility = ["//visibility:public"],
)
32 changes: 32 additions & 0 deletions entity/mergestrategy/mergestrategy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) 2025 Uber Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package mergestrategy holds the shared source-control integration strategy
// used across SubmitQueue, runway, and other repo-local domains. It names how a
// change is integrated into the target branch (rebase, squash-rebase, merge).
package mergestrategy

// MergeStrategy defines the possible source control integration methods.
type MergeStrategy string

const (
// MergeStrategyUnknown is the unknown strategy. It is set by default when the structure is initialized. It should never be seen in the system and is used for error control.
MergeStrategyUnknown MergeStrategy = ""
// MergeStrategyRebase rebases commits onto the target branch before landing.
MergeStrategyRebase MergeStrategy = "rebase"
// MergeStrategySquashRebase squashes commits into a single commit before rebasing on top of the target branch.
MergeStrategySquashRebase MergeStrategy = "squash_rebase"
// MergeStrategyMerge merges commits into the target branch by creating a separate merge commit, preserving the commit history along with hashes.
MergeStrategyMerge MergeStrategy = "merge"
)
6 changes: 5 additions & 1 deletion submitqueue/entity/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ go_library(
],
importpath = "github.com/uber/submitqueue/submitqueue/entity",
visibility = ["//visibility:public"],
deps = ["//entity/change"],
deps = [
"//entity/change",
"//entity/mergestrategy",
],
)

go_test(
Expand All @@ -37,6 +40,7 @@ go_test(
embed = [":entity"],
deps = [
"//entity/change",
"//entity/mergestrategy",
"@com_github_stretchr_testify//assert",
"@com_github_stretchr_testify//require",
],
Expand Down
3 changes: 2 additions & 1 deletion submitqueue/entity/land_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"encoding/json"

"github.com/uber/submitqueue/entity/change"
"github.com/uber/submitqueue/entity/mergestrategy"
)

// LandRequest represents the gateway-owned fields of a land request sent over the queue
Expand All @@ -31,7 +32,7 @@ type LandRequest struct {
// Change is the set of code changes to land.
Change change.Change `json:"change"`
// LandStrategy is the source control integration strategy to use for this land operation.
LandStrategy RequestLandStrategy `json:"land_strategy"`
LandStrategy mergestrategy.MergeStrategy `json:"land_strategy"`
}

// ToBytes serializes the LandRequest to JSON bytes for queue message payload.
Expand Down
13 changes: 7 additions & 6 deletions submitqueue/entity/land_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/uber/submitqueue/entity/change"
"github.com/uber/submitqueue/entity/mergestrategy"
)

func TestLandRequest_ToBytes(t *testing.T) {
Expand All @@ -30,7 +31,7 @@ func TestLandRequest_ToBytes(t *testing.T) {
"github://uber/submitqueue/pull/456/abcdef0123456789abcdef0123456789abcdef01",
"github://uber/submitqueue/pull/789/0123456789abcdef0123456789abcdef01234567",
}},
LandStrategy: RequestLandStrategyRebase,
LandStrategy: mergestrategy.MergeStrategyRebase,
}

data, err := req.ToBytes()
Expand All @@ -49,7 +50,7 @@ func TestLandRequestFromBytes(t *testing.T) {
ID: "my-queue/999",
Queue: "my-queue",
Change: change.Change{URIs: []string{"code.uber.internal.com/D111"}},
LandStrategy: RequestLandStrategyMerge,
LandStrategy: mergestrategy.MergeStrategyMerge,
}

// Serialize
Expand Down Expand Up @@ -83,7 +84,7 @@ func TestLandRequestFromBytes_EmptyData(t *testing.T) {
// Empty JSON should deserialize with zero values
assert.Empty(t, req.ID)
assert.Empty(t, req.Queue)
assert.Equal(t, RequestLandStrategyUnknown, req.LandStrategy)
assert.Equal(t, mergestrategy.MergeStrategyUnknown, req.LandStrategy)
}

func TestLandRequest_SerializationRoundTrip(t *testing.T) {
Expand All @@ -101,7 +102,7 @@ func TestLandRequest_SerializationRoundTrip(t *testing.T) {
"github://uber/repo-a/pull/102/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"github://uber/repo-a/pull/103/cccccccccccccccccccccccccccccccccccccccc",
}},
LandStrategy: RequestLandStrategySquashRebase,
LandStrategy: mergestrategy.MergeStrategySquashRebase,
},
},
{
Expand All @@ -110,7 +111,7 @@ func TestLandRequest_SerializationRoundTrip(t *testing.T) {
ID: "queue2/200",
Queue: "queue2",
Change: change.Change{URIs: []string{"code.uber.internal.com/D12345"}},
LandStrategy: RequestLandStrategyRebase,
LandStrategy: mergestrategy.MergeStrategyRebase,
},
},
{
Expand All @@ -119,7 +120,7 @@ func TestLandRequest_SerializationRoundTrip(t *testing.T) {
ID: "queue3/300",
Queue: "queue3",
Change: change.Change{URIs: []string{"github.uber.com/internal/service/999/deadbeef12"}},
LandStrategy: RequestLandStrategyMerge,
LandStrategy: mergestrategy.MergeStrategyMerge,
},
},
}
Expand Down
17 changes: 2 additions & 15 deletions submitqueue/entity/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,7 @@ import (
"encoding/json"

"github.com/uber/submitqueue/entity/change"
)

// RequestLandStrategy defines the possible source control integration methods.
type RequestLandStrategy string

const (
// RequestLandStrategyUnknown is the unknown strategy. It is set by default when the structure is initialized. It should never be seen in the system and used for error control.
RequestLandStrategyUnknown RequestLandStrategy = ""
// RequestLandStrategyRebase rebases commits onto the target branch before landing.
RequestLandStrategyRebase RequestLandStrategy = "rebase"
// RequestLandStrategySquashRebase squashes commits into a single commit before rebasing on top of the target branch.
RequestLandStrategySquashRebase RequestLandStrategy = "squash_rebase"
// RequestLandStrategyMerge merges commits into the target branch by creating a separate merge commit, preserving the commit history along with hashes.
RequestLandStrategyMerge RequestLandStrategy = "merge"
"github.com/uber/submitqueue/entity/mergestrategy"
)

// RequestState defines the possible states of a land request. They are internal and used to implement a state machine. A separate RequestStatus type is used to track the customer-friendly status of a request.
Expand Down Expand Up @@ -96,7 +83,7 @@ type Request struct {
// Change is a number of code changes (such as pull requests) to land into the target branch. Target branch is defined by the queue configuration.
Change change.Change `json:"change"`
// LandStrategy is the source control integration strategy to use for this land operation.
LandStrategy RequestLandStrategy `json:"land_strategy"`
LandStrategy mergestrategy.MergeStrategy `json:"land_strategy"`

// ****************
// Following fields could be changed throughout the lifecycle of the request
Expand Down
13 changes: 7 additions & 6 deletions submitqueue/entity/request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/uber/submitqueue/entity/change"
"github.com/uber/submitqueue/entity/mergestrategy"
)

func TestRequest_ToBytes(t *testing.T) {
Expand All @@ -30,7 +31,7 @@ func TestRequest_ToBytes(t *testing.T) {
"github://uber/submitqueue/pull/456/abcdef0123456789abcdef0123456789abcdef01",
"github://uber/submitqueue/pull/789/0123456789abcdef0123456789abcdef01234567",
}},
LandStrategy: RequestLandStrategyRebase,
LandStrategy: mergestrategy.MergeStrategyRebase,
State: RequestStateStarted,
Version: 1,
}
Expand All @@ -52,7 +53,7 @@ func TestRequestFromBytes(t *testing.T) {
ID: "my-queue/999",
Queue: "my-queue",
Change: change.Change{URIs: []string{"code.uber.internal.com/D111"}},
LandStrategy: RequestLandStrategyMerge,
LandStrategy: mergestrategy.MergeStrategyMerge,
State: RequestStateProcessing,
Version: 3,
}
Expand Down Expand Up @@ -91,7 +92,7 @@ func TestRequestFromBytes_EmptyData(t *testing.T) {
assert.Empty(t, req.ID)
assert.Empty(t, req.Queue)
assert.Equal(t, RequestStateUnknown, req.State)
assert.Equal(t, RequestLandStrategyUnknown, req.LandStrategy)
assert.Equal(t, mergestrategy.MergeStrategyUnknown, req.LandStrategy)
assert.Equal(t, int32(0), req.Version)
}

Expand Down Expand Up @@ -152,7 +153,7 @@ func TestRequest_SerializationRoundTrip(t *testing.T) {
"github://uber/repo-a/pull/102/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"github://uber/repo-a/pull/103/cccccccccccccccccccccccccccccccccccccccc",
}},
LandStrategy: RequestLandStrategySquashRebase,
LandStrategy: mergestrategy.MergeStrategySquashRebase,
State: RequestStateLanded,
Version: 5,
},
Expand All @@ -163,7 +164,7 @@ func TestRequest_SerializationRoundTrip(t *testing.T) {
ID: "queue2/200",
Queue: "queue2",
Change: change.Change{URIs: []string{"code.uber.internal.com/D12345"}},
LandStrategy: RequestLandStrategyRebase,
LandStrategy: mergestrategy.MergeStrategyRebase,
State: RequestStateStarted,
Version: 1,
},
Expand All @@ -174,7 +175,7 @@ func TestRequest_SerializationRoundTrip(t *testing.T) {
ID: "queue3/300",
Queue: "queue3",
Change: change.Change{URIs: []string{"github.uber.com/internal/service/999/deadbeef12"}},
LandStrategy: RequestLandStrategyMerge,
LandStrategy: mergestrategy.MergeStrategyMerge,
State: RequestStateError,
Version: 10,
},
Expand Down
2 changes: 2 additions & 0 deletions submitqueue/gateway/controller/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ go_library(
"//core/errs",
"//core/metrics",
"//entity/change",
"//entity/mergestrategy",
"//entity/messagequeue",
"//extension/counter",
"//submitqueue/core/request",
Expand All @@ -40,6 +41,7 @@ go_test(
deps = [
"//core/consumer",
"//core/errs",
"//entity/mergestrategy",
"//entity/messagequeue",
"//extension/counter/mock",
"//extension/messagequeue/mock",
Expand Down
17 changes: 9 additions & 8 deletions submitqueue/gateway/controller/land.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/uber/submitqueue/core/errs"
"github.com/uber/submitqueue/core/metrics"
"github.com/uber/submitqueue/entity/change"
"github.com/uber/submitqueue/entity/mergestrategy"
entityqueue "github.com/uber/submitqueue/entity/messagequeue"
"github.com/uber/submitqueue/extension/counter"
"github.com/uber/submitqueue/submitqueue/core/topickey"
Expand Down Expand Up @@ -113,7 +114,7 @@ func (c *LandController) Land(ctx context.Context, req *pb.LandRequest) (resp *p
}

// TODO: pass default queue land strategy to resolver function to process a default.
strategy, err := resolveRequestLandStrategy(req.Strategy)
strategy, err := resolveMergeStrategy(req.Strategy)
if err != nil {
return nil, fmt.Errorf("LandController failed to map strategy for queue=%s: %w", req.Queue, err)
}
Expand Down Expand Up @@ -195,19 +196,19 @@ func (c *LandController) publishToQueue(ctx context.Context, landRequest entity.
return nil
}

// protoStrategyToEntity maps a proto Strategy enum to the entity RequestLandStrategy.
func resolveRequestLandStrategy(s pb.Strategy) (entity.RequestLandStrategy, error) {
// resolveMergeStrategy maps a proto Strategy enum to the shared mergestrategy.MergeStrategy.
func resolveMergeStrategy(s pb.Strategy) (mergestrategy.MergeStrategy, error) {
switch s {
case pb.Strategy_DEFAULT:
// TODO: resolve default strategy based on queue configuration
return entity.RequestLandStrategyRebase, nil
return mergestrategy.MergeStrategyRebase, nil
case pb.Strategy_REBASE:
return entity.RequestLandStrategyRebase, nil
return mergestrategy.MergeStrategyRebase, nil
case pb.Strategy_SQUASH_REBASE:
return entity.RequestLandStrategySquashRebase, nil
return mergestrategy.MergeStrategySquashRebase, nil
case pb.Strategy_MERGE:
return entity.RequestLandStrategyMerge, nil
return mergestrategy.MergeStrategyMerge, nil
default:
return entity.RequestLandStrategyUnknown, fmt.Errorf("unknown land strategy in proto message: %v", s)
return mergestrategy.MergeStrategyUnknown, fmt.Errorf("unknown land strategy in proto message: %v", s)
}
}
3 changes: 2 additions & 1 deletion submitqueue/gateway/controller/land_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/uber-go/tally"
"github.com/uber/submitqueue/core/consumer"
"github.com/uber/submitqueue/core/errs"
"github.com/uber/submitqueue/entity/mergestrategy"
entityqueue "github.com/uber/submitqueue/entity/messagequeue"
countermock "github.com/uber/submitqueue/extension/counter/mock"
queuemock "github.com/uber/submitqueue/extension/messagequeue/mock"
Expand Down Expand Up @@ -289,7 +290,7 @@ func TestLand_PublishesToQueue(t *testing.T) {
assert.Equal(t, "test-queue/123", deserializedReq.ID)
assert.Equal(t, "test-queue", deserializedReq.Queue)
assert.Equal(t, []string{"github://uber/backend/pull/456/fedcba9876543210fedcba9876543210fedcba98"}, deserializedReq.Change.URIs)
assert.Equal(t, entity.RequestLandStrategyRebase, deserializedReq.LandStrategy)
assert.Equal(t, mergestrategy.MergeStrategyRebase, deserializedReq.LandStrategy)
}

func TestLand_ContinuesWhenPublishFails(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions submitqueue/orchestrator/controller/batch/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ go_test(
deps = [
"//core/consumer",
"//entity/change",
"//entity/mergestrategy",
"//entity/messagequeue",
"//extension/counter/mock",
"//extension/messagequeue/mock",
Expand Down
5 changes: 3 additions & 2 deletions submitqueue/orchestrator/controller/batch/batch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/uber-go/tally"
"github.com/uber/submitqueue/core/consumer"
"github.com/uber/submitqueue/entity/change"
"github.com/uber/submitqueue/entity/mergestrategy"
entityqueue "github.com/uber/submitqueue/entity/messagequeue"
countermock "github.com/uber/submitqueue/extension/counter/mock"
queuemock "github.com/uber/submitqueue/extension/messagequeue/mock"
Expand Down Expand Up @@ -65,7 +66,7 @@ func testRequest() entity.Request {
ID: "test-queue/123",
Queue: "test-queue",
Change: change.Change{URIs: []string{"github://uber/service/pull/456/abcdef0123456789abcdef0123456789abcdef01"}},
LandStrategy: entity.RequestLandStrategyRebase,
LandStrategy: mergestrategy.MergeStrategyRebase,
State: entity.RequestStateStarted,
Version: 1,
}
Expand Down Expand Up @@ -206,7 +207,7 @@ func TestController_Process_WithDependencies(t *testing.T) {
ID: "test-queue/456",
Queue: "test-queue",
Change: change.Change{URIs: []string{"github://uber/service/pull/789/789abc1234567890abcdef1234567890abcdef12"}},
LandStrategy: entity.RequestLandStrategyRebase,
LandStrategy: mergestrategy.MergeStrategyRebase,
State: entity.RequestStateStarted,
Version: 1,
}
Expand Down
1 change: 1 addition & 0 deletions submitqueue/orchestrator/controller/start/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ go_test(
"//core/consumer",
"//core/errs",
"//entity/change",
"//entity/mergestrategy",
"//entity/messagequeue",
"//extension/messagequeue/mock",
"//submitqueue/core/topickey",
Expand Down
Loading
Loading