From 7ce8f840064f4f83601a7116c285d040a5e8581c Mon Sep 17 00:00:00 2001 From: Victor Chudnovsky Date: Mon, 8 Apr 2024 13:53:27 -0700 Subject: [PATCH] feat: support API versioning in generated protos (#121) If the methods that wind up in a each proto service all have the same "apiVersion" field in the Discovery document, that value becomes part of a new "api_version" annotation in the proto service. If the version numbers for the methods in a service don't match, generation fails. --- .../disco/Document.java | 4 + .../discotoproto3converter/disco/Method.java | 7 +- .../proto3/DocumentToProtoConverter.java | 38 +- .../DiscoToProto3ConverterAppTest.java | 149 +++ ...pute-versioned-two-services.proto.baseline | 761 ++++++++++++ .../v1small/compute-versioned.proto.baseline | 758 ++++++++++++ ....v1small-versioned-inconsistent-empty.json | 1084 ++++++++++++++++ ...ompute.v1small-versioned-inconsistent.json | 1086 ++++++++++++++++ ...ompute.v1small-versioned-two-services.json | 1088 +++++++++++++++++ .../v1small/compute.v1small-versioned.json | 1087 ++++++++++++++++ 10 files changed, 6056 insertions(+), 6 deletions(-) create mode 100644 src/test/resources/google/cloud/compute/v1small/compute-versioned-two-services.proto.baseline create mode 100644 src/test/resources/google/cloud/compute/v1small/compute-versioned.proto.baseline create mode 100644 src/test/resources/google/cloud/compute/v1small/compute.v1small-versioned-inconsistent-empty.json create mode 100644 src/test/resources/google/cloud/compute/v1small/compute.v1small-versioned-inconsistent.json create mode 100644 src/test/resources/google/cloud/compute/v1small/compute.v1small-versioned-two-services.json create mode 100644 src/test/resources/google/cloud/compute/v1small/compute.v1small-versioned.json diff --git a/src/main/java/com/google/cloud/discotoproto3converter/disco/Document.java b/src/main/java/com/google/cloud/discotoproto3converter/disco/Document.java index 1aebb16..6206d6a 100644 --- a/src/main/java/com/google/cloud/discotoproto3converter/disco/Document.java +++ b/src/main/java/com/google/cloud/discotoproto3converter/disco/Document.java @@ -127,6 +127,8 @@ public static Document from(DiscoveryNode root) { return thisDocument; } + // TODO: Combine with parseMethods(). See + // https://github.com/googleapis/disco-to-proto3-converter/issues/123 private static Map> parseResources(DiscoveryNode root) { List methods = new ArrayList<>(); DiscoveryNode methodsNode = root.getObject("methods"); @@ -143,6 +145,8 @@ private static Map> parseResources(DiscoveryNode root) { return resources; } + // TODO: Combine with parseResources(). See + // https://github.com/googleapis/disco-to-proto3-converter/issues/123 private static List parseMethods(DiscoveryNode root) { List methods = new ArrayList<>(); DiscoveryNode methodsNode = root.getObject("methods"); diff --git a/src/main/java/com/google/cloud/discotoproto3converter/disco/Method.java b/src/main/java/com/google/cloud/discotoproto3converter/disco/Method.java index 13a5ff4..e27f88b 100644 --- a/src/main/java/com/google/cloud/discotoproto3converter/disco/Method.java +++ b/src/main/java/com/google/cloud/discotoproto3converter/disco/Method.java @@ -46,6 +46,7 @@ public static Method from(DiscoveryNode root, Node parent) { String id = root.getString("id"); String path = root.getString("path"); String flatPath = root.has("flatPath") ? root.getString("flatPath") : path; + String apiVersion = root.getString("apiVersion"); DiscoveryNode parametersNode = root.getObject("parameters"); Map parameters = new LinkedHashMap<>(); @@ -105,7 +106,8 @@ public static Method from(DiscoveryNode root, Node parent) { response, scopes, supportsMediaDownload, - supportsMediaUpload); + supportsMediaUpload, + apiVersion); thisMethod.parent = parent; if (request != null) { @@ -182,6 +184,9 @@ public Node parent() { /** @return whether or not the method supports media upload. */ public abstract boolean supportsMediaUpload(); + /** @return the API version for this method. */ + public abstract String apiVersion(); + /** * @return if the method acts on a set of resources whose size may be greater than 1, e.g. List * methods. diff --git a/src/main/java/com/google/cloud/discotoproto3converter/proto3/DocumentToProtoConverter.java b/src/main/java/com/google/cloud/discotoproto3converter/proto3/DocumentToProtoConverter.java index 6088d28..6935744 100644 --- a/src/main/java/com/google/cloud/discotoproto3converter/proto3/DocumentToProtoConverter.java +++ b/src/main/java/com/google/cloud/discotoproto3converter/proto3/DocumentToProtoConverter.java @@ -34,6 +34,7 @@ import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; public class DocumentToProtoConverter { @@ -738,6 +739,8 @@ private void readResources(Document document) { GrpcService service = new GrpcService(grpcServiceName, getServiceDescription(originalGrpcServiceName)); service.getOptions().add(createOption("google.api.default_host", endpoint)); + Set methodApiVersions = new HashSet<>(); + String serviceApiVersion = ""; Set authScopes = new HashSet<>(); @@ -748,6 +751,10 @@ private void readResources(Document document) { authScopes.retainAll(method.scopes()); } + // Record all methods' API versions so we can report them in case of error. + serviceApiVersion = method.apiVersion().trim(); + methodApiVersions.add(serviceApiVersion); + // Request String requestName = getRpcMessageName(method, "request").toUpperCamel(); String methodname = getRpcMethodName(method).toUpperCamel(); @@ -839,9 +846,16 @@ private void readResources(Document document) { service.getMethods().add(grpcMethod); } - service - .getOptions() - .add(createOption("google.api.oauth_scopes", String.join(",", authScopes))); + // Check that all the method API versions match. + if (methodApiVersions.size() != 1) { + throw new InconsistentAPIVersionsException(service.getName(), methodApiVersions); + } + + List