Skip to content

Commit a663f96

Browse files
authored
feature(generator): support omitting rpcs from code generation (#6236)
* feature(generator): support omitting rpcs from code generation
1 parent 8f675de commit a663f96

17 files changed

+767
-422
lines changed

ci/etc/generator-golden-md5-hashes.md5

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
af8e0e7f47e6a0778dbb7a2c72fb1434 generator/integration_tests/golden/golden_kitchen_sink_client.gcpcxx.pb.cc
2-
06472f5172a1485c63c3181802ca8363 generator/integration_tests/golden/golden_kitchen_sink_client.gcpcxx.pb.h
2+
4baaff405dac5f2c530bdf2a22376320 generator/integration_tests/golden/golden_kitchen_sink_client.gcpcxx.pb.h
33
eb7a32b0b6202101bcb4fcf038404ee2 generator/integration_tests/golden/golden_kitchen_sink_connection.gcpcxx.pb.cc
44
0baf99d3c955586ffa95b58ea6ec460d generator/integration_tests/golden/golden_kitchen_sink_connection.gcpcxx.pb.h
55
687657c74d693c6f79e12c0e8f5f2185 generator/integration_tests/golden/golden_kitchen_sink_connection_idempotency_policy.gcpcxx.pb.cc

generator/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ function (google_cloud_cpp_generator_define_tests)
116116
internal/codegen_utils_test.cc
117117
internal/descriptor_utils_test.cc
118118
internal/predicate_utils_test.cc
119-
internal/printer_test.cc)
119+
internal/printer_test.cc
120+
internal/service_code_generator_test.cc)
120121

121122
# Export the list of unit tests to a .bzl file so we do not need to maintain
122123
# the list in two places.

generator/google_cloud_cpp_generator_unit_tests.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ google_cloud_cpp_generator_unit_tests = [
2222
"internal/descriptor_utils_test.cc",
2323
"internal/predicate_utils_test.cc",
2424
"internal/printer_test.cc",
25+
"internal/service_code_generator_test.cc",
2526
]

generator/integration_tests/generator_integration_test.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ class GeneratorIntegrationTest
100100
product_path_ = "generator/integration_tests/golden/";
101101
googleapis_commit_hash_ = "59f97e6044a1275f83427ab7962a154c00d915b5";
102102
copyright_year_ = CurrentCopyrightYear();
103+
omit_rpc1_ = "Omitted1";
104+
omit_rpc2_ = "Omitted2";
103105

104106
std::vector<std::string> args;
105107
// empty arg keeps first real arg from being ignored.
@@ -112,6 +114,8 @@ class GeneratorIntegrationTest
112114
args.emplace_back("--cpp_codegen_opt=googleapis_commit_hash=" +
113115
googleapis_commit_hash_);
114116
args.emplace_back("--cpp_codegen_opt=copyright_year=" + copyright_year_);
117+
args.emplace_back("--cpp_codegen_opt=omit_rpc=" + omit_rpc1_);
118+
args.emplace_back("--cpp_codegen_opt=omit_rpc=" + omit_rpc2_);
115119
args.emplace_back("generator/integration_tests/test.proto");
116120

117121
std::vector<char const*> c_args;
@@ -132,6 +136,8 @@ class GeneratorIntegrationTest
132136
std::string golden_path_;
133137
std::string googleapis_commit_hash_;
134138
std::string copyright_year_;
139+
std::string omit_rpc1_;
140+
std::string omit_rpc2_;
135141
};
136142

137143
TEST_P(GeneratorIntegrationTest, CompareGeneratedToGolden) {

generator/integration_tests/golden/golden_kitchen_sink_client.gcpcxx.pb.h

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class GoldenKitchenSinkClient {
8989
* Must be set to a value less than or equal to 3600 (1 hour). If a value is
9090
* not specified, the token's lifetime will be set to a default value of one
9191
* hour.
92-
* @return [::google::test::admin::database::v1::GenerateAccessTokenResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L847)
92+
* @return [::google::test::admin::database::v1::GenerateAccessTokenResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L864)
9393
*/
9494
StatusOr<::google::test::admin::database::v1::GenerateAccessTokenResponse>
9595
GenerateAccessToken(std::string const& name, std::vector<std::string> const& delegates, std::vector<std::string> const& scope, ::google::protobuf::Duration const& lifetime);
@@ -114,7 +114,7 @@ class GoldenKitchenSinkClient {
114114
* grants access to.
115115
* @param include_email Include the service account email in the token. If set to `true`, the
116116
* token will contain `email` and `email_verified` claims.
117-
* @return [::google::test::admin::database::v1::GenerateIdTokenResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L889)
117+
* @return [::google::test::admin::database::v1::GenerateIdTokenResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L906)
118118
*/
119119
StatusOr<::google::test::admin::database::v1::GenerateIdTokenResponse>
120120
GenerateIdToken(std::string const& name, std::vector<std::string> const& delegates, std::string const& audience, bool include_email);
@@ -145,7 +145,7 @@ class GoldenKitchenSinkClient {
145145
* entries in `entries`. If a log entry already has a label with the same key
146146
* as a label in this parameter, then the log entry's label is not changed.
147147
* See [LogEntry][google.logging.v2.LogEntry]. Test delimiter$
148-
* @return [::google::test::admin::database::v1::WriteLogEntriesResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L928)
148+
* @return [::google::test::admin::database::v1::WriteLogEntriesResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L945)
149149
*/
150150
StatusOr<::google::test::admin::database::v1::WriteLogEntriesResponse>
151151
WriteLogEntries(std::string const& log_name, std::map<std::string, std::string> const& labels);
@@ -177,25 +177,25 @@ class GoldenKitchenSinkClient {
177177
* "organization/[ORGANIZATION_ID]/locations/[LOCATION_ID]/buckets/[BUCKET_ID]/views/[VIEW_ID]"
178178
* "billingAccounts/[BILLING_ACCOUNT_ID]/locations/[LOCATION_ID]/buckets/[BUCKET_ID]/views/[VIEW_ID]"
179179
* "folders/[FOLDER_ID]/locations/[LOCATION_ID]/buckets/[BUCKET_ID]/views/[VIEW_ID]"
180-
* @return [::google::test::admin::database::v1::TailLogEntriesResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L1189)
180+
* @return [::google::test::admin::database::v1::TailLogEntriesResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L1206)
181181
*/
182182
StreamRange<::google::test::admin::database::v1::TailLogEntriesResponse>
183183
TailLogEntries(std::vector<std::string> const& resource_names);
184184

185185
/**
186186
* Generates an OAuth 2.0 access token for a service account.
187187
*
188-
* @param request [::google::test::admin::database::v1::GenerateAccessTokenRequest](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L810)
189-
* @return [::google::test::admin::database::v1::GenerateAccessTokenResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L847)
188+
* @param request [::google::test::admin::database::v1::GenerateAccessTokenRequest](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L827)
189+
* @return [::google::test::admin::database::v1::GenerateAccessTokenResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L864)
190190
*/
191191
StatusOr<::google::test::admin::database::v1::GenerateAccessTokenResponse>
192192
GenerateAccessToken(::google::test::admin::database::v1::GenerateAccessTokenRequest const& request);
193193

194194
/**
195195
* Generates an OpenID Connect ID token for a service account.
196196
*
197-
* @param request [::google::test::admin::database::v1::GenerateIdTokenRequest](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L856)
198-
* @return [::google::test::admin::database::v1::GenerateIdTokenResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L889)
197+
* @param request [::google::test::admin::database::v1::GenerateIdTokenRequest](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L873)
198+
* @return [::google::test::admin::database::v1::GenerateIdTokenResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L906)
199199
*/
200200
StatusOr<::google::test::admin::database::v1::GenerateIdTokenResponse>
201201
GenerateIdToken(::google::test::admin::database::v1::GenerateIdTokenRequest const& request);
@@ -209,8 +209,8 @@ class GoldenKitchenSinkClient {
209209
* different resources (projects, organizations, billing accounts or
210210
* folders)
211211
*
212-
* @param request [::google::test::admin::database::v1::WriteLogEntriesRequest](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L895)
213-
* @return [::google::test::admin::database::v1::WriteLogEntriesResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L928)
212+
* @param request [::google::test::admin::database::v1::WriteLogEntriesRequest](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L912)
213+
* @return [::google::test::admin::database::v1::WriteLogEntriesResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L945)
214214
*/
215215
StatusOr<::google::test::admin::database::v1::WriteLogEntriesResponse>
216216
WriteLogEntries(::google::test::admin::database::v1::WriteLogEntriesRequest const& request);
@@ -219,7 +219,7 @@ class GoldenKitchenSinkClient {
219219
* Lists the logs in projects, organizations, folders, or billing accounts.
220220
* Only logs that have entries are listed.
221221
*
222-
* @param request [::google::test::admin::database::v1::ListLogsRequest](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L931)
222+
* @param request [::google::test::admin::database::v1::ListLogsRequest](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L948)
223223
*/
224224
StreamRange<std::string>
225225
ListLogs(::google::test::admin::database::v1::ListLogsRequest request);
@@ -228,8 +228,8 @@ class GoldenKitchenSinkClient {
228228
* Streaming read of log entries as they are ingested. Until the stream is
229229
* terminated, it will continue reading logs.
230230
*
231-
* @param request [::google::test::admin::database::v1::TailLogEntriesRequest](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L1157)
232-
* @return [::google::test::admin::database::v1::TailLogEntriesResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L1189)
231+
* @param request [::google::test::admin::database::v1::TailLogEntriesRequest](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L1174)
232+
* @return [::google::test::admin::database::v1::TailLogEntriesResponse](https://github.com/googleapis/googleapis/blob/59f97e6044a1275f83427ab7962a154c00d915b5/generator/integration_tests/test.proto#L1206)
233233
*/
234234
StreamRange<::google::test::admin::database::v1::TailLogEntriesResponse>
235235
TailLogEntries(::google::test::admin::database::v1::TailLogEntriesRequest const& request);

generator/integration_tests/golden/tests/golden_kitchen_sink_stub_test.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,40 @@ class MockGrpcGoldenKitchenSinkStub : public ::google::test::admin::database::
155155
request,
156156
::grpc::CompletionQueue* cq),
157157
(override));
158+
MOCK_METHOD(::grpc::Status, Omitted1,
159+
(::grpc::ClientContext * context,
160+
const ::google::protobuf::Empty& request,
161+
::google::protobuf::Empty* response),
162+
(override));
163+
MOCK_METHOD(
164+
::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::Empty>*,
165+
AsyncOmitted1Raw,
166+
(::grpc::ClientContext * context,
167+
const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq),
168+
(override));
169+
MOCK_METHOD(
170+
::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::Empty>*,
171+
PrepareAsyncOmitted1Raw,
172+
(::grpc::ClientContext * context,
173+
const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq),
174+
(override));
175+
MOCK_METHOD(::grpc::Status, Omitted2,
176+
(::grpc::ClientContext * context,
177+
const ::google::protobuf::Empty& request,
178+
::google::protobuf::Empty* response),
179+
(override));
180+
MOCK_METHOD(
181+
::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::Empty>*,
182+
AsyncOmitted2Raw,
183+
(::grpc::ClientContext * context,
184+
const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq),
185+
(override));
186+
MOCK_METHOD(
187+
::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::Empty>*,
188+
PrepareAsyncOmitted2Raw,
189+
(::grpc::ClientContext * context,
190+
const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq),
191+
(override));
158192
};
159193

160194
class GoldenKitchenSinkStubTest : public ::testing::Test {

generator/integration_tests/test.proto

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,23 @@ service GoldenKitchenSink {
805805
};
806806
option (google.api.method_signature) = "resource_names";
807807
}
808+
809+
// Does nothing and should be ommited by command line arg.
810+
rpc Omitted1(google.protobuf.Empty) returns (google.protobuf.Empty) {
811+
option (google.api.http) = {
812+
post: "/v1/omit:omit"
813+
body: "*"
814+
};
815+
}
816+
817+
// Does nothing and should be ommited by command line arg.
818+
rpc Omitted2(google.protobuf.Empty) returns (google.protobuf.Empty) {
819+
option (google.api.http) = {
820+
post: "/v1/omit:omit"
821+
body: "*"
822+
};
823+
}
824+
808825
}
809826

810827
message GenerateAccessTokenRequest {

generator/internal/codegen_utils.cc

Lines changed: 82 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "google/cloud/internal/absl_str_cat_quiet.h"
1717
#include "google/cloud/internal/absl_str_join_quiet.h"
1818
#include "google/cloud/internal/absl_str_replace_quiet.h"
19+
#include "absl/container/flat_hash_set.h"
1920
#include "absl/strings/str_split.h"
2021
#include "absl/time/clock.h"
2122
#include "absl/time/time.h"
@@ -32,6 +33,81 @@ std::vector<std::pair<std::string, std::string>> const& SnakeCaseExceptions() {
3233
{"big_query", "bigquery"}};
3334
return kExceptions;
3435
}
36+
37+
Status ProcessArgProductPath(
38+
std::vector<std::pair<std::string, std::string>>& command_line_args) {
39+
auto product_path =
40+
std::find_if(command_line_args.begin(), command_line_args.end(),
41+
[](std::pair<std::string, std::string> const& p) {
42+
return p.first == "product_path";
43+
});
44+
if (product_path == command_line_args.end() || product_path->second.empty()) {
45+
return Status(StatusCode::kInvalidArgument,
46+
"--cpp_codegen_opt=product_path=<path> must be specified.");
47+
}
48+
49+
auto& path = product_path->second;
50+
if (path.front() == '/') {
51+
path = path.substr(1);
52+
}
53+
if (path.back() != '/') {
54+
path += '/';
55+
}
56+
return {};
57+
}
58+
59+
Status ProcessArgGoogleapisCommitHash(
60+
std::vector<std::pair<std::string, std::string>>& command_line_args) {
61+
auto googleapis_commit_hash =
62+
std::find_if(command_line_args.begin(), command_line_args.end(),
63+
[](std::pair<std::string, std::string> const& p) {
64+
return p.first == "googleapis_commit_hash";
65+
});
66+
if (googleapis_commit_hash == command_line_args.end() ||
67+
googleapis_commit_hash->second.empty()) {
68+
return Status(
69+
StatusCode::kInvalidArgument,
70+
"--cpp_codegen_opt=googleapis_commit_hash=<hash> must be specified.");
71+
}
72+
return {};
73+
}
74+
75+
void ProcessArgCopyrightYear(
76+
std::vector<std::pair<std::string, std::string>>& command_line_args) {
77+
auto copyright_year =
78+
std::find_if(command_line_args.begin(), command_line_args.end(),
79+
[](std::pair<std::string, std::string> const& p) {
80+
return p.first == "copyright_year";
81+
});
82+
if (copyright_year == command_line_args.end()) {
83+
command_line_args.emplace_back("copyright_year", CurrentCopyrightYear());
84+
} else if (copyright_year->second.empty()) {
85+
copyright_year->second = CurrentCopyrightYear();
86+
}
87+
}
88+
89+
void ProcessArgOmitRpc(
90+
std::vector<std::pair<std::string, std::string>>& command_line_args) {
91+
absl::flat_hash_set<std::string> omitted_rpcs;
92+
auto iter = std::find_if(command_line_args.begin(), command_line_args.end(),
93+
[](std::pair<std::string, std::string> const& p) {
94+
return p.first == "omit_rpc";
95+
});
96+
while (iter != command_line_args.end()) {
97+
omitted_rpcs.insert(iter->second);
98+
command_line_args.erase(iter);
99+
iter = std::find_if(command_line_args.begin(), command_line_args.end(),
100+
[](std::pair<std::string, std::string> const& p) {
101+
return p.first == "omit_rpc";
102+
});
103+
}
104+
if (!omitted_rpcs.empty()) {
105+
command_line_args.emplace_back(
106+
"omitted_rpcs",
107+
absl::StrJoin(omitted_rpcs.begin(), omitted_rpcs.end(), ","));
108+
}
109+
}
110+
35111
} // namespace
36112
std::string CurrentCopyrightYear() {
37113
static std::string const kCurrentCopyrightYear =
@@ -115,48 +191,14 @@ ProcessCommandLineArgs(std::string const& parameters) {
115191
std::vector<std::pair<std::string, std::string>> command_line_args;
116192
google::protobuf::compiler::ParseGeneratorParameter(parameters,
117193
&command_line_args);
194+
auto status = ProcessArgProductPath(command_line_args);
195+
if (!status.ok()) return status;
118196

119-
auto product_path =
120-
std::find_if(command_line_args.begin(), command_line_args.end(),
121-
[](std::pair<std::string, std::string> const& p) {
122-
return p.first == "product_path";
123-
});
124-
if (product_path == command_line_args.end() || product_path->second.empty()) {
125-
return Status(StatusCode::kInvalidArgument,
126-
"--cpp_codegen_opt=product_path=<path> must be specified.");
127-
}
128-
129-
auto& path = product_path->second;
130-
if (path.front() == '/') {
131-
path = path.substr(1);
132-
}
133-
if (path.back() != '/') {
134-
path += '/';
135-
}
136-
137-
auto googleapis_commit_hash =
138-
std::find_if(command_line_args.begin(), command_line_args.end(),
139-
[](std::pair<std::string, std::string> const& p) {
140-
return p.first == "googleapis_commit_hash";
141-
});
142-
if (googleapis_commit_hash == command_line_args.end() ||
143-
googleapis_commit_hash->second.empty()) {
144-
return Status(
145-
StatusCode::kInvalidArgument,
146-
"--cpp_codegen_opt=googleapis_commit_hash=<hash> must be specified.");
147-
}
148-
149-
auto copyright_year =
150-
std::find_if(command_line_args.begin(), command_line_args.end(),
151-
[](std::pair<std::string, std::string> const& p) {
152-
return p.first == "copyright_year";
153-
});
154-
if (copyright_year == command_line_args.end()) {
155-
command_line_args.emplace_back("copyright_year", CurrentCopyrightYear());
156-
} else if (copyright_year->second.empty()) {
157-
copyright_year->second = CurrentCopyrightYear();
158-
}
197+
status = ProcessArgGoogleapisCommitHash(command_line_args);
198+
if (!status.ok()) return status;
159199

200+
ProcessArgCopyrightYear(command_line_args);
201+
ProcessArgOmitRpc(command_line_args);
160202
return command_line_args;
161203
}
162204

0 commit comments

Comments
 (0)