I'm trying to get protoc
and protoc-gen-go
to play nice in a multi-repo codebase using go modules.
I've managed to get things more or less working, until I introduced a major version bump in one of my "api" (i.e. protobuf) repos, and I've hit a bit of a barrier.
Here's a simplified picture of my setup:
Let's say I have two repos, github.com/kpruden/base-api
and github.com/kpruden/dep-api
.
base-api
includes base-api.proto
and base-api.pb.go
generated from it.
Similarly, dep-api
contains dep-api.proto
and the corresponding generated code. In addition, dep-api.proto
depends on base-api.proto
via an import github.com/kpruden/base-api/base-api.proto
statement.
Both base-api
and dep-api
use go modules, with dep-api
's go.mod
specifying a dependency on base-api
.
To make this work, I can run go mod vendor
in the dep-api
repo to pull all of its dependencies into a vendor
directory, then add -I./vendor
to my call to protoc
.
This all works well until I decide I need to do a major release of base-api
. This is done by updating base-api/go.mod
's module
line to end with /v2
. I have no need to keep version 1 around, so I don't create a v2
subdirectory in my repo, and the version 2 code and protobuf definitions exist at the root of the repo.
At first, this didn't seem to be a problem. Since I'm not moving any files, protoc
can still find base-api.proto
. However, in the generated go code, version 2 of base-api
must be imported using import "github.com/kpruden/base-api/v2"
, but protoc
is generating the code to import it at github.com/kpruden/base-api
.
My question is: how do I get protoc
to generate the go code for dep-api
to import base-api
at the correct module path? Is this even possible? None of the documentation of either protobuf or gRPC have much of anything to say about go modules. Google has led me to some github issues in these projects that talk about supporting go modules, but they are mostly internal discussions without much in the way of prescriptions, and I've found no mention anywhere of handling major version releases.
I was able to get something working. The setup I describe in the question is actually pretty close to what ultimately ended up working.
In summary, things mostly work as expected:
/v2
to the module
line in go.mod
. Nothing else is required. In particular, the directory layout in source control doesn't need to have v2
anywhere.v2
of the parent module in go code is handled normally. Using the example above, a simple import "github.com/kpruden/base-api/v2"
will do it.import "github.com/kpruden/base-api/v2/base-api.proto"
protoc
use go mod vendor
to copy dependencies into ./vendor
which will lay them such that the protobuf definitions can be found and the import path in (3). At this point protoc -I./vendor ...
works as expected, the imports in the generated go source are correct, and everyone's happy :)