6.8 KiB
Changelog
Unreleased
New Features
External Proto Import Support (--proto_path / -I)
Added support for importing proto files from external directories via -I / --proto_path flags, with full transitive dependency resolution.
Affected files:
generator/gen.go— AddedProtoPathsfield toZRpcContext; addedresolveImportedProtos()to populateImportedProtosbefore code generation.generator/genpb.go— AddedbuildProtocCmd()to automatically discover and append transitively imported proto files to theprotoccommand; addedrelativeToProtoPath()to compute correct relative paths for protoc output.parser/import.go— New file (major addition). ImplementsResolveImports()for recursive transitive import resolution,ParseImportedProtos()for extractinggo_package/packagemetadata from imported protos, andBuildProtoPackageMap()for O(1) lookup by proto package name.parser/proto.go— AddedImportedProtos []ImportedProtofield to theProtostruct.cli/cli.go— PassesProtoPathsfromRPCNewtoZRpcContext.cli/zrpc.go— PassesVarStringSliceProtoPathtoZRpcContext.ProtoPaths.
Before vs After:
| Before | After | |
|---|---|---|
| Proto imports from external dirs | ❌ Not supported, all types must be in the same file | ✅ Use -I ./ext_protos to add search paths |
| Transitive imports (A → B → C) | ❌ Only direct imports recognized | ✅ Recursively resolves all transitive dependencies |
Imported proto .pb.go generation |
❌ Manual, must run protoc separately for each file | ✅ Automatic, imported protos appended to protoc command |
| Proto search paths | ❌ Only source file directory | ✅ Multiple -I paths, same as protoc |
Behavior:
- Transitively walks all
importdeclarations in proto files, skippinggoogle/*well-known types. - Searches each
-Idirectory for imported files, silently skipping system-level protos not found in user paths. - Appends discovered proto files to the
protoccommand so their.pb.gofiles are generated alongside the main proto.
Cross-Package Type Resolution
When an imported proto has a different go_package from the main proto, goctl now automatically generates the correct Go import paths and qualified type references in server, logic, and client code.
Affected files:
generator/typeref.go— New file. Core type resolution engine:resolveRPCTypeRef()— Resolves proto RPC types (simple, same-package dotted, cross-package dotted, Google WKT) to Go type references with correct import paths.resolveCallTypeRef()— Variant for client code generation with type alias support.googleWKTTable— Mapping table for all 16 Google well-known types to their Go equivalents.
generator/genserver.go—genFunctions()now callsresolveRPCTypeRef()for request/response types and collects extra import paths.generator/genlogic.go—genLogicFunction()usesresolveRPCTypeRef(); addedaddLogicImports()to conditionally include main pb import and cross-package imports.generator/gencall.go—genFunction()andgetInterfaceFuncs()useresolveCallTypeRef()for type aliases and extra imports; addedbuildExtraImportLines()helper.generator/call.tpl— Added{{.extraImports}}placeholder for cross-package import lines.
Before vs After:
| Proto type | Before | After |
|---|---|---|
GetReq (same file) |
pb.GetReq |
pb.GetReq (unchanged) |
ext.ExtReq (same go_package) |
❌ Error: "request type must defined in" | ✅ pb.ExtReq — merged into main package |
common.TypesReq (different go_package) |
❌ Error: "request type must defined in" | ✅ common.TypesReq + auto-generated import "example.com/demo/pb/common" |
google.protobuf.Empty |
❌ Error: "request type must defined in" | ✅ emptypb.Empty + auto-generated import |
Behavior:
- Simple types (e.g.,
GetReq) resolve topb.GetReqwith no extra import. - Same-package dotted types (e.g.,
ext.ExtReqwhereexthas the samego_package) resolve topb.ExtReq. - Cross-package dotted types (e.g.,
common.TypesReqwherecommonhas a differentgo_package) resolve tocommon.TypesReqwith the correct Go import path added automatically.
Google Well-Known Types as RPC Parameters
Google protobuf well-known types can now be used directly as RPC request/response types (not just as message fields).
Affected files:
generator/typeref.go—resolveGoogleWKT()+googleWKTTablehandles all standard types.
Before vs After:
| Proto Type | Before (as RPC param) | After (as RPC param) |
|---|---|---|
google.protobuf.Empty |
❌ Error | ✅ emptypb.Empty |
google.protobuf.Timestamp |
❌ Error | ✅ timestamppb.Timestamp |
google.protobuf.Duration |
❌ Error | ✅ durationpb.Duration |
google.protobuf.Any |
❌ Error | ✅ anypb.Any |
google.protobuf.Struct |
❌ Error | ✅ structpb.Struct |
google.protobuf.FieldMask |
❌ Error | ✅ fieldmaskpb.FieldMask |
google.protobuf.*Value |
❌ Error | ✅ wrapperspb.*Value |
Note: These types were already usable as message fields before. This change allows them as RPC request/response types directly.
Supported types:
| Proto Type | Go Type |
|---|---|
google.protobuf.Empty |
emptypb.Empty |
google.protobuf.Timestamp |
timestamppb.Timestamp |
google.protobuf.Duration |
durationpb.Duration |
google.protobuf.Any |
anypb.Any |
google.protobuf.Struct |
structpb.Struct |
google.protobuf.Value |
structpb.Value |
google.protobuf.ListValue |
structpb.ListValue |
google.protobuf.FieldMask |
fieldmaskpb.FieldMask |
google.protobuf.*Value (wrappers) |
wrapperspb.*Value |
Breaking Changes
Dotted Type Names Now Allowed in RPC Definitions
Previously, goctl rejected any RPC request/response type containing a dot (e.g., base.Req), requiring all types to be defined in the same proto file. This restriction has been removed.
Before vs After:
| Proto Definition | Before | After |
|---|---|---|
rpc Fetch(base.Req) returns (base.Reply) |
❌ Parse error: "request type must defined in xxx.proto" | ✅ Parsed successfully, base.Req resolved via imported proto |
rpc Ping(google.protobuf.Empty) returns (Reply) |
❌ Parse error: "request type must defined in xxx.proto" | ✅ Parsed successfully, resolved to emptypb.Empty |
Affected files:
parser/service.go— Removed the validation loop that rejected dotted type names with"request type must defined in"/"returns type must defined in"errors.parser/parser_test.go—TestDefaultProtoParseCaseInvalidRequestTypeandTestDefaultProtoParseCaseInvalidResponseTyperenamed and updated to verify that dotted types now parse successfully.