Skip to content

Commit fa8e50f

Browse files
refactor(proto): add shared api/base proto contracts (Change, Strategy) (#261)
## Summary ### Why? Each service's gateway proto redefines its own `Change` message (and SubmitQueue its own `Strategy` enum), duplicating wire contracts that are meant to stay identical across domains. This is the proto-level gap mirroring what `platform/base/{change,mergestrategy}` already solved for the Go entities, and Stovepipe's upcoming gateway API would otherwise add a third copy of `Change`. ### What? Introduces an `api/base/` proto tree as the shared-wire-contract analog of `platform/base/`: - Adds `api/base/change` (`uber.base.change.Change`) and `api/base/mergestrategy` (`uber.base.mergestrategy.Strategy`), each a message-only contract that domains import instead of redefining. - Teaches the hermetic codegen rule (`tool/proto/proto_codegen.bzl`) to resolve cross-package proto `import`s (exec-root proto_path + imported sources as action inputs) and to skip the gRPC/YARPC generators for service-less contracts via a new `gen_services` attribute. - Migrates the SubmitQueue gateway proto to import the shared `Change`/`Strategy` and drops its local definitions; updates Go consumers (land controller + unit/integration/e2e tests) to the shared `protopb` packages. - Makefile now creates the `protopb/` output dir and marks copied stubs writable, so net-new proto packages generate cleanly. Known cosmetic gazelle warning: resolving the new cross-proto import prints "multiple rules may be imported" for the `# keep` rules_go go_proto_library alias. It does not change generated BUILD files, the build, or the committed-files path that consumers resolve via the root `# gazelle:resolve go` directives. ## Test Plan - ✅ `make proto` (regenerates stubs, including the message-only base protos) - ✅ `./tool/bazel build //...` (213 targets) - ✅ `make test` (54 unit tests pass) - ✅ `make fmt` ## Issues ## Stack 1. @ #261 1. #259 1. #260 Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 76c316b commit fa8e50f

29 files changed

Lines changed: 981 additions & 310 deletions

File tree

BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ load("@gazelle//:def.bzl", "gazelle")
77
# gazelle:exclude .claude
88

99
# Resolve protobuf import ambiguities - use the actual protopb packages, not the proto aliases
10+
# gazelle:resolve go github.com/uber/submitqueue/api/base/change/protopb //api/base/change/protopb
11+
# gazelle:resolve go github.com/uber/submitqueue/api/base/mergestrategy/protopb //api/base/mergestrategy/protopb
1012
# gazelle:resolve go github.com/uber/submitqueue/api/submitqueue/gateway/protopb //api/submitqueue/gateway/protopb
1113
# gazelle:resolve go github.com/uber/submitqueue/api/submitqueue/orchestrator/protopb //api/submitqueue/orchestrator/protopb
1214
# gazelle:resolve go github.com/uber/submitqueue/api/stovepipe/gateway/protopb //api/stovepipe/gateway/protopb

MODULE.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ bazel_dep(name = "rules_go", version = "0.57.0")
55
bazel_dep(name = "gazelle", version = "0.45.0")
66
bazel_dep(name = "rules_proto", version = "7.1.0")
77

8+
# Direct dep so the well-known type proto_library targets (e.g.
9+
# @protobuf//:descriptor_proto, needed by the message queue topics option that
10+
# extends google.protobuf.MessageOptions) are visible by apparent name.
11+
# Toolchain resolution is unaffected: toolchains_protoc is registered first.
12+
bazel_dep(name = "protobuf", version = "29.1")
13+
814
# Use a prebuilt protoc binary instead of compiling protoc (and its abseil/upb
915
# dependencies) from source on every cold build. Requires
1016
# --incompatible_enable_proto_toolchain_resolution (set in .bazelrc).

Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ GOIMPORTS_VERSION ?= v0.33.0
3131
# (the out_dir convention in tool/proto/BUILD.bazel) and copied back here. A
3232
# package may hold multiple .proto files (e.g. an RPC contract plus messagequeue
3333
# contracts); all generated stubs land in the same protopb/ dir.
34-
PROTO_PACKAGES = api/submitqueue/gateway api/submitqueue/orchestrator api/stovepipe/gateway api/stovepipe/orchestrator
34+
PROTO_PACKAGES = api/base/change api/base/mergestrategy api/base/messagequeue api/submitqueue/gateway api/submitqueue/orchestrator api/stovepipe/gateway api/stovepipe/orchestrator
3535

3636
# Set REPO_ROOT for docker-compose
3737
export REPO_ROOT := $(shell pwd)
@@ -346,8 +346,10 @@ proto: ## Generate protobuf files from .proto definitions
346346
@$(BAZEL) build //tool/proto:generated
347347
@set -e; for pkg in $(PROTO_PACKAGES); do \
348348
out=$$(echo $$pkg | tr / _); \
349+
mkdir -p $$pkg/protopb; \
349350
for f in bazel-bin/tool/proto/$$out/*.go; do \
350351
cp -f $$f $$pkg/protopb/$$(basename $$f); \
352+
chmod 0644 $$pkg/protopb/$$(basename $$f); \
351353
done; \
352354
done
353355
@$(BAZEL) run @rules_go//go -- run golang.org/x/tools/cmd/goimports@$(GOIMPORTS_VERSION) -w $(addsuffix /protopb,$(PROTO_PACKAGES))

api/base/change/proto/BUILD.bazel

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
load("@rules_go//go:def.bzl", "go_library")
2+
load("@rules_go//proto:def.bzl", "go_proto_library")
3+
load("@rules_proto//proto:defs.bzl", "proto_library")
4+
5+
exports_files(
6+
["change.proto"],
7+
visibility = ["//tool/proto:__pkg__"],
8+
)
9+
10+
proto_library(
11+
name = "changepb_proto",
12+
srcs = ["change.proto"],
13+
visibility = ["//visibility:public"],
14+
)
15+
16+
# keep
17+
go_proto_library(
18+
name = "changepb_go_proto",
19+
compilers = [
20+
"@rules_go//proto:go_proto",
21+
"@rules_go//proto:go_grpc_v2",
22+
],
23+
importpath = "github.com/uber/submitqueue/api/base/change/proto",
24+
proto = ":changepb_proto",
25+
visibility = ["//visibility:public"],
26+
)
27+
28+
go_library(
29+
name = "proto",
30+
embed = [":changepb_go_proto"],
31+
importpath = "github.com/uber/submitqueue/api/base/change/proto",
32+
visibility = ["//visibility:public"],
33+
)
34+
35+
go_library(
36+
name = "protopb",
37+
embed = [":changepb_go_proto"],
38+
importpath = "github.com/uber/submitqueue/api/base/change/protopb",
39+
visibility = ["//visibility:public"],
40+
)

api/base/change/proto/change.proto

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) 2025 Uber Technologies, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
syntax = "proto3";
16+
17+
package uber.base.change;
18+
19+
option go_package = "github.com/uber/submitqueue/api/base/change/protopb";
20+
option java_multiple_files = true;
21+
option java_outer_classname = "ChangeProto";
22+
option java_package = "com.uber.submitqueue.base.change";
23+
24+
// Change represents a code change identified by URIs from a code change provider
25+
// (e.g. a GitHub Pull Request, a Phabricator Diff, or a git commit). The provider
26+
// is extracted from the URI scheme.
27+
//
28+
// This is the shared wire contract for change identity, reused across SubmitQueue,
29+
// Stovepipe, and other repo-local domains — the proto-level analog of the
30+
// platform/base/change Go entity. Domains import it rather than redefining their own.
31+
message Change {
32+
// URIs identifying the change(s) (RFC 3986 compliant). The scheme identifies the
33+
// change provider, and the path contains provider-specific resource identifiers.
34+
//
35+
// Supported by default (other providers can be added):
36+
// GitHub PR: "github://<org>/<repo>/pull/<pr>/<head_commit_sha>"
37+
// ("ghe"/"ghes" schemes for GitHub Enterprise)
38+
// git commit: "git://<remote>/<repo>/<ref>/<commit_sha>"
39+
// (<ref> is a fully-qualified, percent-encoded git ref)
40+
//
41+
// The commit SHA must be the full 40-character lowercase hex SHA; abbreviated
42+
// SHAs are rejected because downstream staleness checks compare by strict equality.
43+
repeated string uris = 1;
44+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
load("@rules_go//go:def.bzl", "go_library")
2+
3+
go_library(
4+
name = "protopb",
5+
srcs = ["change.pb.go"],
6+
importpath = "github.com/uber/submitqueue/api/base/change/protopb",
7+
visibility = ["//visibility:public"],
8+
deps = [
9+
"@org_golang_google_protobuf//reflect/protoreflect",
10+
"@org_golang_google_protobuf//runtime/protoimpl",
11+
],
12+
)

api/base/change/protopb/change.pb.go

Lines changed: 157 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
load("@rules_go//go:def.bzl", "go_library")
2+
load("@rules_go//proto:def.bzl", "go_proto_library")
3+
load("@rules_proto//proto:defs.bzl", "proto_library")
4+
5+
exports_files(
6+
["mergestrategy.proto"],
7+
visibility = ["//tool/proto:__pkg__"],
8+
)
9+
10+
proto_library(
11+
name = "mergestrategypb_proto",
12+
srcs = ["mergestrategy.proto"],
13+
visibility = ["//visibility:public"],
14+
)
15+
16+
# keep
17+
go_proto_library(
18+
name = "mergestrategypb_go_proto",
19+
compilers = [
20+
"@rules_go//proto:go_proto",
21+
"@rules_go//proto:go_grpc_v2",
22+
],
23+
importpath = "github.com/uber/submitqueue/api/base/mergestrategy/proto",
24+
proto = ":mergestrategypb_proto",
25+
visibility = ["//visibility:public"],
26+
)
27+
28+
go_library(
29+
name = "proto",
30+
embed = [":mergestrategypb_go_proto"],
31+
importpath = "github.com/uber/submitqueue/api/base/mergestrategy/proto",
32+
visibility = ["//visibility:public"],
33+
)
34+
35+
go_library(
36+
name = "protopb",
37+
embed = [":mergestrategypb_go_proto"],
38+
importpath = "github.com/uber/submitqueue/api/base/mergestrategy/protopb",
39+
visibility = ["//visibility:public"],
40+
)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright (c) 2025 Uber Technologies, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
syntax = "proto3";
16+
17+
package uber.base.mergestrategy;
18+
19+
option go_package = "github.com/uber/submitqueue/api/base/mergestrategy/protopb";
20+
option java_multiple_files = true;
21+
option java_outer_classname = "MergeStrategyProto";
22+
option java_package = "com.uber.submitqueue.base.mergestrategy";
23+
24+
// Strategy defines the possible source control integration methods — how a change
25+
// is integrated into the target branch.
26+
//
27+
// This is the shared wire contract for merge strategy, reused across SubmitQueue
28+
// and other repo-local domains — the proto-level analog of the
29+
// platform/base/mergestrategy Go entity. Domains import it rather than redefining their own.
30+
enum Strategy {
31+
// Default strategy (let the server decide based on configuration).
32+
DEFAULT = 0;
33+
// Rebase commits onto the target branch before landing.
34+
REBASE = 1;
35+
// Same as REBASE but squash commits into a single commit before rebase.
36+
SQUASH_REBASE = 2;
37+
// Merge commits into the target branch by creating a separate merge commit, preserving commit history along with hashes.
38+
MERGE = 3;
39+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
load("@rules_go//go:def.bzl", "go_library")
2+
3+
go_library(
4+
name = "protopb",
5+
srcs = ["mergestrategy.pb.go"],
6+
importpath = "github.com/uber/submitqueue/api/base/mergestrategy/protopb",
7+
visibility = ["//visibility:public"],
8+
deps = [
9+
"@org_golang_google_protobuf//reflect/protoreflect",
10+
"@org_golang_google_protobuf//runtime/protoimpl",
11+
],
12+
)

0 commit comments

Comments
 (0)