Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions ci/cloudbuild/builds/generate-libraries.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ set -euo pipefail

source "$(dirname "$0")/../../lib/init.sh"
source module ci/cloudbuild/builds/lib/bazel.sh
source module ci/cloudbuild/builds/lib/features.sh
source module ci/cloudbuild/builds/lib/git.sh
source module ci/lib/io.sh

bazel_output_base="$(bazel info output_base)"

Expand Down Expand Up @@ -115,6 +117,11 @@ else
io::log_yellow "Skipping update of protobuf lists/deps."
fi

io::log_h2 "Running doxygen landing-page updates:"
time {
features::libraries | xargs -P "$(nproc)" -n 1 ci/generate-markdown/update-library-landing-dox.sh
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

qq: is this where we hook doc generation to the generator?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Producing the final .dox files is a 2 stage process. The generator produces the dox file with markers for the start/end injection points. This script modified the dox file to inject the information between the injection points. line 80 is the invocation of the generator that produces the dox files.

}

io::log_h2 "Highlight generated code differences"
# We use `--compact-summary` because in almost all cases the delta is at
# least hundreds of lines long, and often it is thousands of lines long. The
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*!
@page golden-env Environment Variables

A number of environment variables can be used to configure the behavior of
the library. There are also functions to configure this behavior in code. The
environment variables are convenient when troubleshooting problems.

@section golden-env-endpoint Endpoint Overrides

<!-- inject-endpoint-env-vars-start -->
<!-- inject-endpoint-env-vars-end -->

@see google::cloud::EndpointOption

@section golden-env-logging Logging

`GOOGLE_CLOUD_CPP_ENABLE_TRACING=rpc`: turns on tracing for most gRPC
calls. The library injects an additional Stub decorator that prints each gRPC
request and response. Unless you have configured your own logging backend,
you should also set `GOOGLE_CLOUD_CPP_ENABLE_CLOG` to produce any output on
the program's console.

@see google::cloud::LoggingComponentsOption

`GOOGLE_CLOUD_CPP_TRACING_OPTIONS=...`: modifies the behavior of gRPC tracing,
including whether messages will be output on multiple lines, or whether
string/bytes fields will be truncated.

@see google::cloud::GrpcTracingOptionsOption

`GOOGLE_CLOUD_CPP_ENABLE_CLOG=yes`: turns on logging in the library, basically
the library always "logs" but the logging infrastructure has no backend to
actually print anything until the application sets a backend or they set this
environment variable.

@see google::cloud::LogBackend
@see google::cloud::LogSink

@section golden-env-project Setting the Default Project

`GOOGLE_CLOUD_PROJECT=...`: is used in examples and integration tests to
configure the GCP project. This has no effect in the library.

*/
10 changes: 10 additions & 0 deletions generator/integration_tests/golden/doc/options.dox
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*!
@defgroup generator-integration_tests-golden-options Test Deprecated Configuration Options

This library uses the same mechanism (`google::cloud::Options`) and the common
[options](@ref options) as all other C++ client libraries for its configuration.
Some `*Option` classes, which are only used in this library, are documented in
this page.

@see @ref options - for an overview of client library configuration.
*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*!
@page golden-override-authentication How to Override the Authentication Credentials

Unless otherwise configured, the client libraries use
[Application Default Credentials] to authenticate with Google Cloud Services.
While this works for most applications, in some cases you may need to override
this default. You can do so by providing the
[UnifiedCredentialsOption](@ref google::cloud::UnifiedCredentialsOption)
The following example shows how to explicitly load a service account key file:

<!-- inject-service-account-snippet-start -->
<!-- inject-service-account-snippet-end -->

Keep in mind that we chose this as an example because it is relatively easy to
understand. Consult the [Best practices for managing service account keys]
guide for more details.

@see @ref guac - for more information on the factory functions to create
`google::cloud::Credentials` objects.

[Best practices for managing service account keys]: https://cloud.google.com/iam/docs/best-practices-for-managing-service-account-keys
[Application Default Credentials]: https://cloud.google.com/docs/authentication#adc

*/

// <!-- inject-authentication-pages-start -->
// <!-- inject-authentication-pages-end -->
15 changes: 15 additions & 0 deletions generator/integration_tests/golden/doc/override-endpoint.dox
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*!
@page golden-override-endpoint How to Override the Default Endpoint

In some cases, you may need to override the default endpoint used by the client
library. Use the
[EndpointOption](@ref google::cloud::EndpointOption) when initializing the
client library to change this default.

<!-- inject-endpoint-snippet-start -->
<!-- inject-endpoint-snippet-end -->

*/

// <!-- inject-endpoint-pages-start -->
// <!-- inject-endpoint-pages-end -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*!
@page golden-override-retry Override Retry, Backoff, and Idempotency Policies

When it is safe to do so, the library automatically retries requests that fail
due to a transient error. The library then uses [exponential backoff] to backoff
before trying again. Which operations are considered safe to retry, which
errors are treated as transient failures, the details of the exponential backoff
algorithm, and for how long the library retries are all configurable via
policies.

This document provides examples showing how to override the default policies.

The policies can be set when the `*Connection` object is created. The library
provides default policies for any policy that is not set. The application can
also override some (or all) policies when the `*Client` object is created. This
can be useful if multiple `*Client` objects share the same `*Connection` object,
but you want different retry behavior in some of the clients. Finally, the
application can override some retry policies when calling a specific member
function.

The library uses three different options to control the retry loop. The options
have per-client names.

@section golden-override-retry-retry-policy Configuring the transient errors and retry duration

The `*RetryPolicyOption` controls:

- Which errors are to be treated as transient errors.
- How long the library will keep retrying transient errors.

You can provide your own class for this option. The library also provides two
built-in policies:

- `*LimitedErrorCountRetryPolicy`: stops retrying after a specified number
of transient errors.
- `*LimitedTimeRetryPolicy`: stops retrying after a specified time.

Note that a library may have more than one version of these classes. Their name
match the `*Client` and `*Connection` object they are intended to be used
with. Some `*Client` objects treat different error codes as transient errors.
In most cases, only [kUnavailable](@ref google::cloud::StatusCode) is treated
as a transient error.

@section golden-override-retry-backoff-policy Controlling the backoff algorithm

The `*BackoffPolicyOption` controls how long the client library will wait
before retrying a request that failed with a transient error. You can provide
your own class for this option.

The only built-in backoff policy is
[`ExponentialBackoffPolicy`](@ref google::cloud::ExponentialBackoffPolicy).
This class implements a truncated exponential backoff algorithm, with jitter.
In summary, it doubles the current backoff time after each failure. The actual
backoff time for an RPC is chosen at random, but never exceeds the current
backoff. The current backoff is doubled after each failure, but never exceeds
(or is "truncated") if it reaches a prescribed maximum.

@section golden-override-retry-idempotency-policy Controlling which operations are retryable

The `*IdempotencyPolicyOption` controls which requests are retryable, as some
requests are never safe to retry.

Only one built-in idempotency policy is provided by the library. The name
matches the name of the client it is intended for. For example, `FooBarClient`
will use `FooBarIdempotencyPolicy`. This policy is very conservative.

@section golden-override-retry-example Example

<!-- inject-retry-snippet-start -->
<!-- inject-retry-snippet-end -->

@section golden-override-retry-more-information More Information

@see google::cloud::Options
@see google::cloud::BackoffPolicy
@see google::cloud::ExponentialBackoffPolicy

[exponential backoff]: https://en.wikipedia.org/wiki/Exponential_backoff

*/

// <!-- inject-retry-pages-start -->
// <!-- inject-retry-pages-end -->
21 changes: 21 additions & 0 deletions generator/integration_tests/test2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

type: google.api.Service
config_version: 3
name: test.googleapis.com
title: Test2

apis:
- name: google.test.rest.only.v1.GoldenRestOnly
21 changes: 21 additions & 0 deletions generator/integration_tests/test_deprecated.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

type: google.api.Service
config_version: 3
name: test.googleapis.com
title: Test Deprecated

apis:
- name: google.test.deprecated.v1.DeprecatedService
60 changes: 37 additions & 23 deletions generator/internal/scaffold_generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -326,44 +326,59 @@ void GenerateMetadata(
void GenerateScaffold(
std::map<std::string, std::string> const& vars,
std::string const& scaffold_templates_path, std::string const& output_path,
google::cloud::cpp::generator::ServiceConfiguration const& service) {
google::cloud::cpp::generator::ServiceConfiguration const& service,
ScaffoldFiles scaffold_files) {
using Generator = std::function<void(
std::ostream&, std::map<std::string, std::string> const&)>;
struct Destination {
std::string name;
Generator generator;
} files[] = {
{"README.md", GenerateReadme},
{"BUILD.bazel", GenerateBuild},
{"CMakeLists.txt", GenerateCMakeLists},
{"doc/main.dox", GenerateDoxygenMainPage},
{"doc/environment-variables.dox", GenerateDoxygenEnvironmentPage},
{"doc/override-authentication.dox", GenerateOverrideAuthenticationPage},
{"doc/override-endpoint.dox", GenerateOverrideEndpointPage},
{"doc/override-retry-policies.dox", GenerateOverrideRetryPoliciesPage},
{"doc/options.dox", GenerateDoxygenOptionsPage},
{"quickstart/README.md", GenerateQuickstartReadme},
{"quickstart/quickstart.cc", GenerateQuickstartSkeleton},
{"quickstart/CMakeLists.txt", GenerateQuickstartCMake},
{"quickstart/Makefile", GenerateQuickstartMakefile},
{"quickstart/BUILD.bazel", GenerateQuickstartBuild},
{"quickstart/.bazelrc", GenerateQuickstartBazelrc},
};

MakeDirectory(output_path + "/");
auto const destination =
output_path + "/" + LibraryPath(service.product_path());
MakeDirectory(destination);
MakeDirectory(destination + "doc/");
MakeDirectory(destination + "quickstart/");

std::vector<Destination> files;
if (scaffold_files == ScaffoldFiles::kDocDir) {
files = {
{"doc/environment-variables.dox", GenerateDoxygenEnvironmentPage},
{"doc/override-authentication.dox", GenerateOverrideAuthenticationPage},
{"doc/override-endpoint.dox", GenerateOverrideEndpointPage},
{"doc/override-retry-policies.dox", GenerateOverrideRetryPoliciesPage},
{"doc/options.dox", GenerateDoxygenOptionsPage},
};
} else {
MakeDirectory(destination + "quickstart/");
files = {
{"README.md", GenerateReadme},
{"BUILD.bazel", GenerateBuild},
{"CMakeLists.txt", GenerateCMakeLists},
{"doc/main.dox", GenerateDoxygenMainPage},
{"doc/environment-variables.dox", GenerateDoxygenEnvironmentPage},
{"doc/override-authentication.dox", GenerateOverrideAuthenticationPage},
{"doc/override-endpoint.dox", GenerateOverrideEndpointPage},
{"doc/override-retry-policies.dox", GenerateOverrideRetryPoliciesPage},
{"doc/options.dox", GenerateDoxygenOptionsPage},
{"quickstart/README.md", GenerateQuickstartReadme},
{"quickstart/quickstart.cc", GenerateQuickstartSkeleton},
{"quickstart/CMakeLists.txt", GenerateQuickstartCMake},
{"quickstart/Makefile", GenerateQuickstartMakefile},
{"quickstart/BUILD.bazel", GenerateQuickstartBuild},
{"quickstart/.bazelrc", GenerateQuickstartBazelrc},
};
std::ifstream is(scaffold_templates_path + kWorkspaceTemplate);
auto const contents = std::string{std::istreambuf_iterator<char>(is), {}};
std::ofstream os(destination + "quickstart/WORKSPACE.bazel");
GenerateQuickstartWorkspace(os, vars, contents);
}
Comment on lines +344 to +376

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is code duplication in this if-else block. The list of documentation files to be generated (environment-variables.dox, override-authentication.dox, etc.) is present in both the if branch (lines 347-351) and the else branch (lines 360-364). To improve maintainability and avoid potential inconsistencies in the future, consider extracting this common list of files into a separate variable and using it in both branches.


for (auto const& f : files) {
std::ofstream os(destination + f.name);
f.generator(os, vars);
}
std::ifstream is(scaffold_templates_path + kWorkspaceTemplate);
auto const contents = std::string{std::istreambuf_iterator<char>(is), {}};
std::ofstream os(destination + "quickstart/WORKSPACE.bazel");
GenerateQuickstartWorkspace(os, vars, contents);
}

void GenerateReadme(std::ostream& os,
Expand Down Expand Up @@ -547,7 +562,6 @@ which should give you a taste of the $title$ C++ client library API.
void GenerateDoxygenEnvironmentPage(
std::ostream& os, std::map<std::string, std::string> const& variables) {
auto constexpr kText = R"""(/*!

@page $library$-env Environment Variables

A number of environment variables can be used to configure the behavior of
Expand Down
8 changes: 7 additions & 1 deletion generator/internal/scaffold_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,17 @@ void GenerateMetadata(
google::cloud::cpp::generator::ServiceConfiguration const& service,
bool allow_placeholders);

enum class ScaffoldFiles {
kAll,
kDocDir, // Does not include main.dox due to all the hand edits.
};

/// Generates the build and documentation scaffold for @p service.
void GenerateScaffold(
std::map<std::string, std::string> const& vars,
std::string const& scaffold_templates_path, std::string const& output_path,
google::cloud::cpp::generator::ServiceConfiguration const& service);
google::cloud::cpp::generator::ServiceConfiguration const& service,
ScaffoldFiles = ScaffoldFiles::kAll);

///@{
/// @name Generators for each scaffold file.
Expand Down
Loading