diff --git a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java
index 5969ed4693..539e06cd69 100644
--- a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java
+++ b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java
@@ -32,7 +32,6 @@
import com.google.api.core.ApiFunction;
import com.google.api.core.BetaApi;
import com.google.api.core.InternalApi;
-import com.google.api.core.InternalExtensionOnly;
import com.google.api.gax.core.ExecutorProvider;
import com.google.api.gax.rpc.FixedHeaderProvider;
import com.google.api.gax.rpc.HeaderProvider;
@@ -82,13 +81,14 @@
* The client lib header and generator header values are used to form a value that goes into the
* http header of requests to the service.
*/
-@InternalExtensionOnly
public final class InstantiatingGrpcChannelProvider implements TransportChannelProvider {
+
+ private static String systemProductName;
+
@VisibleForTesting
static final Logger LOG = Logger.getLogger(InstantiatingGrpcChannelProvider.class.getName());
- private static final String DIRECT_PATH_ENV_DISABLE_DIRECT_PATH =
- "GOOGLE_CLOUD_DISABLE_DIRECT_PATH";
+ static final String DIRECT_PATH_ENV_DISABLE_DIRECT_PATH = "GOOGLE_CLOUD_DISABLE_DIRECT_PATH";
private static final String DIRECT_PATH_ENV_ENABLE_XDS = "GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS";
static final long DIRECT_PATH_KEEP_ALIVE_TIME_SECONDS = 3600;
static final long DIRECT_PATH_KEEP_ALIVE_TIMEOUT_SECONDS = 20;
@@ -147,6 +147,19 @@ private InstantiatingGrpcChannelProvider(Builder builder) {
: builder.directPathServiceConfig;
}
+ /**
+ * Package-Private constructor that is only visible for testing DirectPath functionality inside
+ * tests. This overrides the computed systemProductName when the class is initialized to help
+ * configure the result of {@link #isOnComputeEngine()} check.
+ *
+ *
If productName is null, that represents the result of an IOException
+ */
+ @VisibleForTesting
+ InstantiatingGrpcChannelProvider(Builder builder, String productName) {
+ this(builder);
+ systemProductName = productName;
+ }
+
/**
* @deprecated If executor is not set, this channel provider will create channels with default
* grpc executor.
@@ -257,8 +270,8 @@ private boolean isDirectPathEnabled() {
return false;
}
- @VisibleForTesting
- boolean isDirectPathXdsEnabled() {
+ @InternalApi
+ public boolean isDirectPathXdsEnabled() {
// Method 1: Enable DirectPath xDS by option.
if (Boolean.TRUE.equals(attemptDirectPathXds)) {
return true;
@@ -320,19 +333,29 @@ boolean isCredentialDirectPathCompatible() {
static boolean isOnComputeEngine() {
String osName = System.getProperty("os.name");
if ("Linux".equals(osName)) {
- try {
- String result =
- Files.asCharSource(new File("/sys/class/dmi/id/product_name"), StandardCharsets.UTF_8)
- .readFirstLine();
- return result.contains(GCE_PRODUCTION_NAME_PRIOR_2016)
- || result.contains(GCE_PRODUCTION_NAME_AFTER_2016);
- } catch (IOException ignored) {
- return false;
- }
+ String systemProductName = getSystemProductName();
+ // systemProductName will be empty string if not on Compute Engine
+ return systemProductName.contains(GCE_PRODUCTION_NAME_PRIOR_2016)
+ || systemProductName.contains(GCE_PRODUCTION_NAME_AFTER_2016);
}
return false;
}
+ private static String getSystemProductName() {
+ // The static field systemProductName should only be set in tests
+ if (systemProductName != null) {
+ return systemProductName;
+ }
+ try {
+ return Files.asCharSource(new File("/sys/class/dmi/id/product_name"), StandardCharsets.UTF_8)
+ .readFirstLine();
+ } catch (IOException e) {
+ // If not on Compute Engine, FileNotFoundException will be thrown. Use empty string
+ // as it won't match with the GCE_PRODUCTION_NAME constants
+ return "";
+ }
+ }
+
// Universe Domain configuration is currently only supported in the GDU
@VisibleForTesting
boolean canUseDirectPathWithUniverseDomain() {
@@ -370,10 +393,7 @@ private ManagedChannel createSingleChannel() throws IOException {
// Check DirectPath traffic.
boolean useDirectPathXds = false;
- if (isDirectPathEnabled()
- && isCredentialDirectPathCompatible()
- && isOnComputeEngine()
- && canUseDirectPathWithUniverseDomain()) {
+ if (canUseDirectPath()) {
CallCredentials callCreds = MoreCallCredentials.from(credentials);
ChannelCredentials channelCreds =
GoogleDefaultChannelCredentials.newBuilder().callCredentials(callCreds).build();
@@ -446,6 +466,24 @@ && canUseDirectPathWithUniverseDomain()) {
return managedChannel;
}
+ /**
+ * Marked as Internal Api and intended for internal use. DirectPath must be enabled via the
+ * settings and a few other configurations/settings must also be valid for the request to go
+ * through DirectPath.
+ *
+ *
Checks: 1. Credentials are compatible 2.Running on Compute Engine 3. Universe Domain is
+ * configured to for the Google Default Universe
+ *
+ * @return if DirectPath is enabled for the client AND if the configurations are valid
+ */
+ @InternalApi
+ public boolean canUseDirectPath() {
+ return isDirectPathEnabled()
+ && isCredentialDirectPathCompatible()
+ && isOnComputeEngine()
+ && canUseDirectPathWithUniverseDomain();
+ }
+
/** The endpoint to be used for the channel. */
@Override
public String getEndpoint() {
@@ -753,6 +791,12 @@ public Builder setAttemptDirectPathXds() {
return this;
}
+ @VisibleForTesting
+ Builder setEnvProvider(EnvironmentProvider envProvider) {
+ this.envProvider = envProvider;
+ return this;
+ }
+
/**
* Sets a service config for direct path. If direct path is not enabled, the provided service
* config will be ignored.
diff --git a/gax-java/gax-grpc/src/test/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProviderTest.java b/gax-java/gax-grpc/src/test/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProviderTest.java
index 2647ac6d13..d982ec98c3 100644
--- a/gax-java/gax-grpc/src/test/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProviderTest.java
+++ b/gax-java/gax-grpc/src/test/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProviderTest.java
@@ -29,6 +29,7 @@
*/
package com.google.api.gax.grpc;
+import static com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.GCE_PRODUCTION_NAME_AFTER_2016;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -37,13 +38,17 @@
import com.google.api.core.ApiFunction;
import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.Builder;
import com.google.api.gax.rpc.HeaderProvider;
+import com.google.api.gax.rpc.TransportChannel;
import com.google.api.gax.rpc.TransportChannelProvider;
+import com.google.api.gax.rpc.internal.EnvironmentProvider;
import com.google.api.gax.rpc.mtls.AbstractMtlsTransportChannelTest;
import com.google.api.gax.rpc.mtls.MtlsProvider;
+import com.google.auth.Credentials;
import com.google.auth.oauth2.CloudShellCredentials;
import com.google.auth.oauth2.ComputeEngineCredentials;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.truth.Truth;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.alts.ComputeEngineChannelBuilder;
@@ -57,16 +62,39 @@
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.threeten.bp.Duration;
class InstantiatingGrpcChannelProviderTest extends AbstractMtlsTransportChannelTest {
+ private static final String DEFAULT_ENDPOINT = "test.googleapis.com:443";
+ private static String originalOSName;
+ private ComputeEngineCredentials computeEngineCredentials;
+
+ @BeforeAll
+ public static void setupClass() {
+ originalOSName = System.getProperty("os.name");
+ }
+
+ @BeforeEach
+ public void setup() throws IOException {
+ System.setProperty("os.name", "Linux");
+ computeEngineCredentials = Mockito.mock(ComputeEngineCredentials.class);
+ }
+
+ @AfterEach
+ public void cleanup() {
+ System.setProperty("os.name", originalOSName);
+ }
@Test
void testEndpoint() {
@@ -300,7 +328,7 @@ void testDirectPathWithGDUEndpoint() {
InstantiatingGrpcChannelProvider.newBuilder()
.setAttemptDirectPath(true)
.setAttemptDirectPathXds()
- .setEndpoint("test.googleapis.com:443")
+ .setEndpoint(DEFAULT_ENDPOINT)
.build();
assertThat(provider.canUseDirectPathWithUniverseDomain()).isTrue();
}
@@ -322,7 +350,7 @@ void testDirectPathXdsEnabled() throws IOException {
InstantiatingGrpcChannelProvider.newBuilder()
.setAttemptDirectPath(true)
.setAttemptDirectPathXds()
- .setEndpoint("test.googleapis.com:443")
+ .setEndpoint(DEFAULT_ENDPOINT)
.build();
assertThat(provider.isDirectPathXdsEnabled()).isTrue();
@@ -552,13 +580,16 @@ void testLogDirectPathMisconfigAttrempDirectPathNotSet() throws Exception {
.setEndpoint("localhost:8080")
.build();
- provider.getTransportChannel();
+ TransportChannel transportChannel = provider.getTransportChannel();
assertThat(logHandler.getAllMessages())
.contains(
"DirectPath is misconfigured. Please set the attemptDirectPath option along with the"
+ " attemptDirectPathXds option.");
InstantiatingGrpcChannelProvider.LOG.removeHandler(logHandler);
+
+ transportChannel.close();
+ transportChannel.awaitTermination(10, TimeUnit.SECONDS);
}
@Test
@@ -584,16 +615,19 @@ void testLogDirectPathMisconfigWrongCredential() throws Exception {
.setAttemptDirectPath(true)
.setHeaderProvider(Mockito.mock(HeaderProvider.class))
.setExecutor(Mockito.mock(Executor.class))
- .setEndpoint("test.googleapis.com:443")
+ .setEndpoint(DEFAULT_ENDPOINT)
.build();
- provider.getTransportChannel();
+ TransportChannel transportChannel = provider.getTransportChannel();
assertThat(logHandler.getAllMessages())
.contains(
"DirectPath is misconfigured. Please make sure the credential is an instance of"
+ " com.google.auth.oauth2.ComputeEngineCredentials .");
InstantiatingGrpcChannelProvider.LOG.removeHandler(logHandler);
+
+ transportChannel.close();
+ transportChannel.awaitTermination(10, TimeUnit.SECONDS);
}
@Test
@@ -607,10 +641,10 @@ void testLogDirectPathMisconfigNotOnGCE() throws Exception {
.setAllowNonDefaultServiceAccount(true)
.setHeaderProvider(Mockito.mock(HeaderProvider.class))
.setExecutor(Mockito.mock(Executor.class))
- .setEndpoint("test.googleapis.com:443")
+ .setEndpoint(DEFAULT_ENDPOINT)
.build();
- provider.getTransportChannel();
+ TransportChannel transportChannel = provider.getTransportChannel();
if (!InstantiatingGrpcChannelProvider.isOnComputeEngine()) {
assertThat(logHandler.getAllMessages())
@@ -618,6 +652,161 @@ void testLogDirectPathMisconfigNotOnGCE() throws Exception {
"DirectPath is misconfigured. DirectPath is only available in a GCE environment.");
}
InstantiatingGrpcChannelProvider.LOG.removeHandler(logHandler);
+
+ transportChannel.close();
+ transportChannel.awaitTermination(10, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void canUseDirectPath_happyPath() {
+ EnvironmentProvider envProvider = Mockito.mock(EnvironmentProvider.class);
+ Mockito.when(
+ envProvider.getenv(
+ InstantiatingGrpcChannelProvider.DIRECT_PATH_ENV_DISABLE_DIRECT_PATH))
+ .thenReturn("false");
+ InstantiatingGrpcChannelProvider.Builder builder =
+ InstantiatingGrpcChannelProvider.newBuilder()
+ .setAttemptDirectPath(true)
+ .setCredentials(computeEngineCredentials)
+ .setEndpoint(DEFAULT_ENDPOINT)
+ .setEnvProvider(envProvider);
+ InstantiatingGrpcChannelProvider provider =
+ new InstantiatingGrpcChannelProvider(builder, GCE_PRODUCTION_NAME_AFTER_2016);
+ Truth.assertThat(provider.canUseDirectPath()).isTrue();
+ }
+
+ @Test
+ public void canUseDirectPath_directPathEnvVarDisabled() {
+ EnvironmentProvider envProvider = Mockito.mock(EnvironmentProvider.class);
+ Mockito.when(
+ envProvider.getenv(
+ InstantiatingGrpcChannelProvider.DIRECT_PATH_ENV_DISABLE_DIRECT_PATH))
+ .thenReturn("true");
+ InstantiatingGrpcChannelProvider.Builder builder =
+ InstantiatingGrpcChannelProvider.newBuilder()
+ .setAttemptDirectPath(true)
+ .setCredentials(computeEngineCredentials)
+ .setEndpoint(DEFAULT_ENDPOINT)
+ .setEnvProvider(envProvider);
+ InstantiatingGrpcChannelProvider provider =
+ new InstantiatingGrpcChannelProvider(builder, GCE_PRODUCTION_NAME_AFTER_2016);
+ Truth.assertThat(provider.canUseDirectPath()).isFalse();
+ }
+
+ @Test
+ public void canUseDirectPath_directPathEnvVarNotSet_attemptDirectPathIsTrue() {
+ InstantiatingGrpcChannelProvider.Builder builder =
+ InstantiatingGrpcChannelProvider.newBuilder()
+ .setAttemptDirectPath(true)
+ .setCredentials(computeEngineCredentials)
+ .setEndpoint(DEFAULT_ENDPOINT);
+ InstantiatingGrpcChannelProvider provider =
+ new InstantiatingGrpcChannelProvider(builder, GCE_PRODUCTION_NAME_AFTER_2016);
+ Truth.assertThat(provider.canUseDirectPath()).isTrue();
+ }
+
+ @Test
+ public void canUseDirectPath_directPathEnvVarNotSet_attemptDirectPathIsFalse() {
+ InstantiatingGrpcChannelProvider.Builder builder =
+ InstantiatingGrpcChannelProvider.newBuilder()
+ .setAttemptDirectPath(false)
+ .setCredentials(computeEngineCredentials)
+ .setEndpoint(DEFAULT_ENDPOINT);
+ InstantiatingGrpcChannelProvider provider =
+ new InstantiatingGrpcChannelProvider(builder, GCE_PRODUCTION_NAME_AFTER_2016);
+ Truth.assertThat(provider.canUseDirectPath()).isFalse();
+ }
+
+ @Test
+ public void canUseDirectPath_nonComputeCredentials() {
+ Credentials credentials = Mockito.mock(Credentials.class);
+ EnvironmentProvider envProvider = Mockito.mock(EnvironmentProvider.class);
+ Mockito.when(
+ envProvider.getenv(
+ InstantiatingGrpcChannelProvider.DIRECT_PATH_ENV_DISABLE_DIRECT_PATH))
+ .thenReturn("false");
+ InstantiatingGrpcChannelProvider.Builder builder =
+ InstantiatingGrpcChannelProvider.newBuilder()
+ .setAttemptDirectPath(true)
+ .setCredentials(credentials)
+ .setEndpoint(DEFAULT_ENDPOINT)
+ .setEnvProvider(envProvider);
+ InstantiatingGrpcChannelProvider provider =
+ new InstantiatingGrpcChannelProvider(builder, GCE_PRODUCTION_NAME_AFTER_2016);
+ Truth.assertThat(provider.canUseDirectPath()).isFalse();
+ }
+
+ @Test
+ public void canUseDirectPath_isNotOnComputeEngine_invalidOsNameSystemProperty() {
+ System.setProperty("os.name", "Not Linux");
+ EnvironmentProvider envProvider = Mockito.mock(EnvironmentProvider.class);
+ Mockito.when(
+ envProvider.getenv(
+ InstantiatingGrpcChannelProvider.DIRECT_PATH_ENV_DISABLE_DIRECT_PATH))
+ .thenReturn("false");
+ InstantiatingGrpcChannelProvider.Builder builder =
+ InstantiatingGrpcChannelProvider.newBuilder()
+ .setAttemptDirectPath(true)
+ .setCredentials(computeEngineCredentials)
+ .setEndpoint(DEFAULT_ENDPOINT)
+ .setEnvProvider(envProvider);
+ InstantiatingGrpcChannelProvider provider =
+ new InstantiatingGrpcChannelProvider(builder, GCE_PRODUCTION_NAME_AFTER_2016);
+ Truth.assertThat(provider.canUseDirectPath()).isFalse();
+ }
+
+ @Test
+ public void canUseDirectPath_isNotOnComputeEngine_invalidSystemProductName() {
+ EnvironmentProvider envProvider = Mockito.mock(EnvironmentProvider.class);
+ Mockito.when(
+ envProvider.getenv(
+ InstantiatingGrpcChannelProvider.DIRECT_PATH_ENV_DISABLE_DIRECT_PATH))
+ .thenReturn("false");
+ InstantiatingGrpcChannelProvider.Builder builder =
+ InstantiatingGrpcChannelProvider.newBuilder()
+ .setAttemptDirectPath(true)
+ .setCredentials(computeEngineCredentials)
+ .setEndpoint(DEFAULT_ENDPOINT)
+ .setEnvProvider(envProvider);
+ InstantiatingGrpcChannelProvider provider =
+ new InstantiatingGrpcChannelProvider(builder, "testing");
+ Truth.assertThat(provider.canUseDirectPath()).isFalse();
+ }
+
+ @Test
+ public void canUseDirectPath_isNotOnComputeEngine_unableToGetSystemProductName() {
+ EnvironmentProvider envProvider = Mockito.mock(EnvironmentProvider.class);
+ Mockito.when(
+ envProvider.getenv(
+ InstantiatingGrpcChannelProvider.DIRECT_PATH_ENV_DISABLE_DIRECT_PATH))
+ .thenReturn("false");
+ InstantiatingGrpcChannelProvider.Builder builder =
+ InstantiatingGrpcChannelProvider.newBuilder()
+ .setAttemptDirectPath(true)
+ .setCredentials(computeEngineCredentials)
+ .setEndpoint(DEFAULT_ENDPOINT)
+ .setEnvProvider(envProvider);
+ InstantiatingGrpcChannelProvider provider = new InstantiatingGrpcChannelProvider(builder, "");
+ Truth.assertThat(provider.canUseDirectPath()).isFalse();
+ }
+
+ @Test
+ public void canUseDirectPath_nonGDUUniverseDomain() {
+ EnvironmentProvider envProvider = Mockito.mock(EnvironmentProvider.class);
+ Mockito.when(
+ envProvider.getenv(
+ InstantiatingGrpcChannelProvider.DIRECT_PATH_ENV_DISABLE_DIRECT_PATH))
+ .thenReturn("false");
+ String nonGDUEndpoint = "test.random.com:443";
+ InstantiatingGrpcChannelProvider.Builder builder =
+ InstantiatingGrpcChannelProvider.newBuilder()
+ .setAttemptDirectPath(true)
+ .setCredentials(computeEngineCredentials)
+ .setEndpoint(nonGDUEndpoint)
+ .setEnvProvider(envProvider);
+ InstantiatingGrpcChannelProvider provider =
+ new InstantiatingGrpcChannelProvider(builder, GCE_PRODUCTION_NAME_AFTER_2016);
+ Truth.assertThat(provider.canUseDirectPath()).isFalse();
}
private static class FakeLogHandler extends Handler {
diff --git a/gax-java/gax-httpjson/pom.xml b/gax-java/gax-httpjson/pom.xml
index 2c9b7b0808..7c7e14246d 100644
--- a/gax-java/gax-httpjson/pom.xml
+++ b/gax-java/gax-httpjson/pom.xml
@@ -3,7 +3,7 @@
4.0.0
gax-httpjson
- 2.49.0
+ 2.50.0
jar
GAX (Google Api eXtensions) for Java (HTTP JSON)
Google Api eXtensions for Java (HTTP JSON)
@@ -11,7 +11,7 @@
com.google.api
gax-parent
- 2.49.0
+ 2.50.0
diff --git a/gax-java/gax/clirr-ignored-differences.xml b/gax-java/gax/clirr-ignored-differences.xml
index b08615ef13..b58200572e 100644
--- a/gax-java/gax/clirr-ignored-differences.xml
+++ b/gax-java/gax/clirr-ignored-differences.xml
@@ -47,4 +47,10 @@
com/google/api/gax/rpc/StubSettings
* getServiceName()
+
+
+ 6011
+ com/google/api/gax/tracing/MetricsTracer
+ *
+
diff --git a/gax-java/gax/pom.xml b/gax-java/gax/pom.xml
index afecf42fd3..467ffb97e1 100644
--- a/gax-java/gax/pom.xml
+++ b/gax-java/gax/pom.xml
@@ -3,7 +3,7 @@
4.0.0
gax
- 2.49.0
+ 2.50.0
jar
GAX (Google Api eXtensions) for Java (Core)
Google Api eXtensions for Java (Core)
@@ -11,7 +11,7 @@
com.google.api
gax-parent
- 2.49.0
+ 2.50.0
diff --git a/gax-java/gax/src/main/java/com/google/api/gax/tracing/MetricsTracer.java b/gax-java/gax/src/main/java/com/google/api/gax/tracing/MetricsTracer.java
index 7938bde82b..237e686896 100644
--- a/gax-java/gax/src/main/java/com/google/api/gax/tracing/MetricsTracer.java
+++ b/gax-java/gax/src/main/java/com/google/api/gax/tracing/MetricsTracer.java
@@ -53,7 +53,7 @@
@BetaApi
@InternalApi
public class MetricsTracer implements ApiTracer {
- public static final String METHOD_NAME_ATTRIBUTE = "method_name";
+ public static final String METHOD_ATTRIBUTE = "method";
public static final String LANGUAGE_ATTRIBUTE = "language";
public static final String STATUS_ATTRIBUTE = "status";
public static final String DEFAULT_LANGUAGE = "Java";
@@ -61,12 +61,13 @@ public class MetricsTracer implements ApiTracer {
"Operation has already been completed";
private Stopwatch attemptTimer;
private final Stopwatch operationTimer = Stopwatch.createStarted();
+ // These are RPC specific attributes and pertain to a specific API Trace
private final Map attributes = new HashMap<>();
private final MetricsRecorder metricsRecorder;
private final AtomicBoolean operationFinished;
public MetricsTracer(MethodName methodName, MetricsRecorder metricsRecorder) {
- this.attributes.put(METHOD_NAME_ATTRIBUTE, methodName.toString());
+ this.attributes.put(METHOD_ATTRIBUTE, methodName.toString());
this.attributes.put(LANGUAGE_ATTRIBUTE, DEFAULT_LANGUAGE);
this.metricsRecorder = metricsRecorder;
this.operationFinished = new AtomicBoolean();
diff --git a/gax-java/gax/src/main/java/com/google/api/gax/tracing/MetricsTracerFactory.java b/gax-java/gax/src/main/java/com/google/api/gax/tracing/MetricsTracerFactory.java
index d2b8d87fb4..3aa17bfb6c 100644
--- a/gax-java/gax/src/main/java/com/google/api/gax/tracing/MetricsTracerFactory.java
+++ b/gax-java/gax/src/main/java/com/google/api/gax/tracing/MetricsTracerFactory.java
@@ -31,6 +31,8 @@
import com.google.api.core.BetaApi;
import com.google.api.core.InternalApi;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
/**
* A {@link ApiTracerFactory} to build instances of {@link MetricsTracer}.
@@ -45,13 +47,29 @@
public class MetricsTracerFactory implements ApiTracerFactory {
protected MetricsRecorder metricsRecorder;
+ /** Mapping of client attributes that are set for every MetricsTracer */
+ private final Map attributes;
+
+ /** Creates a MetricsTracerFactory with no additional client level attributes. */
public MetricsTracerFactory(MetricsRecorder metricsRecorder) {
+ this(metricsRecorder, ImmutableMap.of());
+ }
+
+ /**
+ * Pass in a Map of client level attributes which will be added to every single MetricsTracer
+ * created from the ApiTracerFactory.
+ */
+ public MetricsTracerFactory(MetricsRecorder metricsRecorder, Map attributes) {
this.metricsRecorder = metricsRecorder;
+ this.attributes = ImmutableMap.copyOf(attributes);
}
@Override
public ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType) {
- return new MetricsTracer(
- MethodName.of(spanName.getClientName(), spanName.getMethodName()), metricsRecorder);
+ MetricsTracer metricsTracer =
+ new MetricsTracer(
+ MethodName.of(spanName.getClientName(), spanName.getMethodName()), metricsRecorder);
+ attributes.forEach(metricsTracer::addAttributes);
+ return metricsTracer;
}
}
diff --git a/gax-java/gax/src/main/java/com/google/api/gax/tracing/OpenTelemetryMetricsRecorder.java b/gax-java/gax/src/main/java/com/google/api/gax/tracing/OpenTelemetryMetricsRecorder.java
index fdf1dd2d09..a029f42fde 100644
--- a/gax-java/gax/src/main/java/com/google/api/gax/tracing/OpenTelemetryMetricsRecorder.java
+++ b/gax-java/gax/src/main/java/com/google/api/gax/tracing/OpenTelemetryMetricsRecorder.java
@@ -55,6 +55,8 @@
@BetaApi
@InternalApi
public class OpenTelemetryMetricsRecorder implements MetricsRecorder {
+
+ public static final String GAX_METER_NAME = "gax-java";
private final DoubleHistogram attemptLatencyRecorder;
private final DoubleHistogram operationLatencyRecorder;
private final LongCounter operationCountRecorder;
@@ -76,7 +78,7 @@ public class OpenTelemetryMetricsRecorder implements MetricsRecorder {
public OpenTelemetryMetricsRecorder(OpenTelemetry openTelemetry, String serviceName) {
Meter meter =
openTelemetry
- .meterBuilder("gax-java")
+ .meterBuilder(GAX_METER_NAME)
.setInstrumentationVersion(GaxProperties.getGaxVersion())
.build();
this.attemptLatencyRecorder =
diff --git a/gax-java/gax/src/test/java/com/google/api/gax/tracing/MetricsTracerFactoryTest.java b/gax-java/gax/src/test/java/com/google/api/gax/tracing/MetricsTracerFactoryTest.java
index 16e2078bc0..28a621f5f8 100644
--- a/gax-java/gax/src/test/java/com/google/api/gax/tracing/MetricsTracerFactoryTest.java
+++ b/gax-java/gax/src/test/java/com/google/api/gax/tracing/MetricsTracerFactoryTest.java
@@ -33,12 +33,16 @@
import static org.mockito.Mockito.when;
import com.google.api.gax.tracing.ApiTracerFactory.OperationType;
+import com.google.common.collect.ImmutableMap;
import com.google.common.truth.Truth;
+import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
class MetricsTracerFactoryTest {
+ private static final int DEFAULT_ATTRIBUTES_COUNT = 2;
+
@Mock private MetricsRecorder metricsRecorder;
@Mock private ApiTracer parent;
private SpanName spanName;
@@ -60,22 +64,36 @@ void testNewTracer_notNull() {
ApiTracer apiTracer = metricsTracerFactory.newTracer(parent, spanName, OperationType.Unary);
// Assert that the apiTracer created has expected type and not null
- Truth.assertThat(apiTracer).isInstanceOf(MetricsTracer.class);
Truth.assertThat(apiTracer).isNotNull();
+ Truth.assertThat(apiTracer).isInstanceOf(MetricsTracer.class);
}
@Test
- void testNewTracer_HasCorrectParameters() {
-
- // Call the newTracer method
- ApiTracer apiTracer = metricsTracerFactory.newTracer(parent, spanName, OperationType.Unary);
+ void testNewTracer_hasCorrectNumberAttributes_hasDefaultAttributes() {
+ MetricsTracer metricsTracer =
+ (MetricsTracer) metricsTracerFactory.newTracer(parent, spanName, OperationType.Unary);
+ Map attributes = metricsTracer.getAttributes();
+ Truth.assertThat(attributes.size()).isEqualTo(DEFAULT_ATTRIBUTES_COUNT);
+ Truth.assertThat(attributes.get(MetricsTracer.METHOD_ATTRIBUTE))
+ .isEqualTo("testService.testMethod");
+ Truth.assertThat(attributes.get(MetricsTracer.LANGUAGE_ATTRIBUTE))
+ .isEqualTo(MetricsTracer.DEFAULT_LANGUAGE);
+ }
- // Assert that the apiTracer created has expected type and not null
- Truth.assertThat(apiTracer).isInstanceOf(MetricsTracer.class);
- Truth.assertThat(apiTracer).isNotNull();
+ @Test
+ void testClientAttributes_additionalClientAttributes() {
+ Map clientAttributes =
+ ImmutableMap.of("attribute1", "value1", "attribute2", "value2");
+ MetricsTracerFactory metricsTracerFactory =
+ new MetricsTracerFactory(metricsRecorder, clientAttributes);
- MetricsTracer metricsTracer = (MetricsTracer) apiTracer;
- Truth.assertThat(metricsTracer.getAttributes().get("method_name"))
- .isEqualTo("testService.testMethod");
+ MetricsTracer metricsTracer =
+ (MetricsTracer) metricsTracerFactory.newTracer(parent, spanName, OperationType.Unary);
+ Map attributes = metricsTracer.getAttributes();
+ Truth.assertThat(attributes.size())
+ .isEqualTo(DEFAULT_ATTRIBUTES_COUNT + clientAttributes.size());
+ // Default attributes already tested above
+ Truth.assertThat(attributes.containsKey("attribute1")).isTrue();
+ Truth.assertThat(attributes.containsKey("attribute2")).isTrue();
}
}
diff --git a/gax-java/gax/src/test/java/com/google/api/gax/tracing/MetricsTracerTest.java b/gax-java/gax/src/test/java/com/google/api/gax/tracing/MetricsTracerTest.java
index 5c0945a411..f409d27ec4 100644
--- a/gax-java/gax/src/test/java/com/google/api/gax/tracing/MetricsTracerTest.java
+++ b/gax-java/gax/src/test/java/com/google/api/gax/tracing/MetricsTracerTest.java
@@ -65,11 +65,11 @@ void setUp() {
private ImmutableMap getAttributes(Code statusCode) {
return ImmutableMap.of(
- "status",
+ MetricsTracer.STATUS_ATTRIBUTE,
statusCode.toString(),
- "method_name",
+ MetricsTracer.METHOD_ATTRIBUTE,
DEFAULT_METHOD_NAME,
- "language",
+ MetricsTracer.LANGUAGE_ATTRIBUTE,
MetricsTracer.DEFAULT_LANGUAGE);
}
diff --git a/gax-java/pom.xml b/gax-java/pom.xml
index 9ef34bd850..535c686841 100644
--- a/gax-java/pom.xml
+++ b/gax-java/pom.xml
@@ -4,14 +4,14 @@
com.google.api
gax-parent
pom
- 2.49.0
+ 2.50.0
GAX (Google Api eXtensions) for Java (Parent)
Google Api eXtensions for Java (Parent)
com.google.api
gapic-generator-java-pom-parent
- 2.41.0
+ 2.42.0
../gapic-generator-java-pom-parent
@@ -50,7 +50,7 @@
com.google.api
api-common
- 2.32.0
+ 2.33.0
com.google.auth
@@ -98,24 +98,24 @@
com.google.api
gax
- 2.49.0
+ 2.50.0
com.google.api
gax
- 2.49.0
+ 2.50.0
test-jar
testlib
com.google.api.grpc
proto-google-common-protos
- 2.40.0
+ 2.41.0
com.google.api.grpc
grpc-google-common-protos
- 2.40.0
+ 2.41.0
io.grpc
diff --git a/generation_config.yaml b/generation_config.yaml
index 151abe3886..7dbbd5e0a3 100644
--- a/generation_config.yaml
+++ b/generation_config.yaml
@@ -1,5 +1,5 @@
-gapic_generator_version: 2.41.0 # {x-version-update:gapic-generator-java:current}
-googleapis_commitish: 3b6f144d47b0a1d2115ab2445ec06e80cc324a44
+gapic_generator_version: 2.42.0 # {x-version-update:gapic-generator-java:current}
+googleapis_commitish: 7160b0c31e9b99fe896d1fa29b6fe6cfbf42588f
# the libraries are ordered with respect to library name, which is
# java-{library.library_name} or java-{library.api-shortname} when
# library.library_name is not defined.
diff --git a/java-common-protos/grpc-google-common-protos/pom.xml b/java-common-protos/grpc-google-common-protos/pom.xml
index 8c65cc8abe..fa772f91fd 100644
--- a/java-common-protos/grpc-google-common-protos/pom.xml
+++ b/java-common-protos/grpc-google-common-protos/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
grpc-google-common-protos
- 2.40.0
+ 2.41.0
grpc-google-common-protos
GRPC library for grpc-google-common-protos
com.google.api.grpc
google-common-protos-parent
- 2.40.0
+ 2.41.0
diff --git a/java-common-protos/pom.xml b/java-common-protos/pom.xml
index 280a6a67d0..78b5a8d463 100644
--- a/java-common-protos/pom.xml
+++ b/java-common-protos/pom.xml
@@ -4,7 +4,7 @@
com.google.api.grpc
google-common-protos-parent
pom
- 2.40.0
+ 2.41.0
Google Common Protos Parent
Java idiomatic client for Google Cloud Platform services.
@@ -13,7 +13,7 @@
com.google.api
gapic-generator-java-pom-parent
- 2.41.0
+ 2.42.0
../gapic-generator-java-pom-parent
@@ -61,7 +61,7 @@
com.google.cloud
third-party-dependencies
- 3.31.0
+ 3.32.0
pom
import
@@ -75,7 +75,7 @@
com.google.api.grpc
grpc-google-common-protos
- 2.40.0
+ 2.41.0
io.grpc
@@ -87,7 +87,7 @@
com.google.api.grpc
proto-google-common-protos
- 2.40.0
+ 2.41.0
com.google.guava
@@ -119,7 +119,7 @@
org.apache.maven.plugins
maven-project-info-reports-plugin
- 3.5.0
+ 3.6.0
diff --git a/java-common-protos/proto-google-common-protos/pom.xml b/java-common-protos/proto-google-common-protos/pom.xml
index 2df1e930cf..69345b0769 100644
--- a/java-common-protos/proto-google-common-protos/pom.xml
+++ b/java-common-protos/proto-google-common-protos/pom.xml
@@ -3,13 +3,13 @@
4.0.0
com.google.api.grpc
proto-google-common-protos
- 2.40.0
+ 2.41.0
proto-google-common-protos
PROTO library for proto-google-common-protos
com.google.api.grpc
google-common-protos-parent
- 2.40.0
+ 2.41.0
diff --git a/java-core/google-cloud-core-bom/pom.xml b/java-core/google-cloud-core-bom/pom.xml
index bf76c17d06..f1b31cf19f 100644
--- a/java-core/google-cloud-core-bom/pom.xml
+++ b/java-core/google-cloud-core-bom/pom.xml
@@ -3,13 +3,13 @@
4.0.0
com.google.cloud
google-cloud-core-bom
- 2.39.0
+ 2.40.0
pom
com.google.api
gapic-generator-java-pom-parent
- 2.41.0
+ 2.42.0
../../gapic-generator-java-pom-parent
@@ -23,17 +23,17 @@
com.google.cloud
google-cloud-core
- 2.39.0
+ 2.40.0
com.google.cloud
google-cloud-core-grpc
- 2.39.0
+ 2.40.0
com.google.cloud
google-cloud-core-http
- 2.39.0
+ 2.40.0
diff --git a/java-core/google-cloud-core-grpc/pom.xml b/java-core/google-cloud-core-grpc/pom.xml
index e83df65ef6..2d2977d1b0 100644
--- a/java-core/google-cloud-core-grpc/pom.xml
+++ b/java-core/google-cloud-core-grpc/pom.xml
@@ -3,7 +3,7 @@
4.0.0
com.google.cloud
google-cloud-core-grpc
- 2.39.0
+ 2.40.0
jar
Google Cloud Core gRPC
@@ -12,7 +12,7 @@
com.google.cloud
google-cloud-core-parent
- 2.39.0
+ 2.40.0
google-cloud-core-grpc
diff --git a/java-core/google-cloud-core-http/pom.xml b/java-core/google-cloud-core-http/pom.xml
index 3c1c805485..a42ca666a7 100644
--- a/java-core/google-cloud-core-http/pom.xml
+++ b/java-core/google-cloud-core-http/pom.xml
@@ -3,7 +3,7 @@
4.0.0
com.google.cloud
google-cloud-core-http
- 2.39.0
+ 2.40.0
jar
Google Cloud Core HTTP
@@ -12,7 +12,7 @@
com.google.cloud
google-cloud-core-parent
- 2.39.0
+ 2.40.0
google-cloud-core-http
diff --git a/java-core/google-cloud-core/pom.xml b/java-core/google-cloud-core/pom.xml
index c80d715c1e..e21db09cd2 100644
--- a/java-core/google-cloud-core/pom.xml
+++ b/java-core/google-cloud-core/pom.xml
@@ -3,7 +3,7 @@
4.0.0
com.google.cloud
google-cloud-core
- 2.39.0
+ 2.40.0
jar
Google Cloud Core
@@ -12,7 +12,7 @@
com.google.cloud
google-cloud-core-parent
- 2.39.0
+ 2.40.0
google-cloud-core
diff --git a/java-core/pom.xml b/java-core/pom.xml
index 02400fcbcc..bff9b65f9f 100644
--- a/java-core/pom.xml
+++ b/java-core/pom.xml
@@ -4,7 +4,7 @@
com.google.cloud
google-cloud-core-parent
pom
- 2.39.0
+ 2.40.0
Google Cloud Core Parent
Java idiomatic client for Google Cloud Platform services.
@@ -13,7 +13,7 @@
com.google.api
gapic-generator-java-pom-parent
- 2.41.0
+ 2.42.0
../gapic-generator-java-pom-parent
@@ -33,7 +33,7 @@
com.google.cloud
google-cloud-shared-dependencies
- 3.31.0
+ 3.32.0
pom
import
@@ -53,7 +53,7 @@
org.easymock
easymock
- 5.2.0
+ 5.3.0
test
diff --git a/java-iam/.OwlBot-hermetic.yaml b/java-iam/.OwlBot-hermetic.yaml
index 907bd5cd5e..0ea858eb78 100644
--- a/java-iam/.OwlBot-hermetic.yaml
+++ b/java-iam/.OwlBot-hermetic.yaml
@@ -17,10 +17,6 @@ deep-remove-regex:
- "/java-iam/grpc-google-.*/src"
- "/java-iam/proto-google-.*/src"
-deep-preserve-regex:
- - "/java-iam/proto-google-iam-v1/src/main/java/com/google/iam/v1/logging"
- - "/java-iam/proto-google-iam-v1/src/main/proto/google/iam/v1"
-
deep-copy-regex:
- source: "/google/iam/(v.*)/.*-java/grpc-google-.*/src"
dest: "/owl-bot-staging/java-iam/$1/grpc-google-iam-$1/src"
diff --git a/java-iam/.repo-metadata.json b/java-iam/.repo-metadata.json
index c3194cecd8..1758363ab3 100644
--- a/java-iam/.repo-metadata.json
+++ b/java-iam/.repo-metadata.json
@@ -5,7 +5,7 @@
"api_description": "Manages access control for Google Cloud Platform resources",
"client_documentation": "https://cloud.google.com/java/docs/reference/proto-google-iam-v1/latest/overview",
"release_level": "stable",
- "transport": "grpc",
+ "transport": "both",
"language": "java",
"repo": "googleapis/sdk-platform-java",
"repo_short": "java-iam",
diff --git a/java-iam/grpc-google-iam-v1/pom.xml b/java-iam/grpc-google-iam-v1/pom.xml
index a4bff066b7..48c65eb27e 100644
--- a/java-iam/grpc-google-iam-v1/pom.xml
+++ b/java-iam/grpc-google-iam-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
grpc-google-iam-v1
- 1.35.0
+ 1.36.0
grpc-google-iam-v1
GRPC library for grpc-google-iam-v1
com.google.cloud
google-iam-parent
- 1.35.0
+ 1.36.0
diff --git a/java-iam/grpc-google-iam-v2/pom.xml b/java-iam/grpc-google-iam-v2/pom.xml
index 03e52d1088..a51184808f 100644
--- a/java-iam/grpc-google-iam-v2/pom.xml
+++ b/java-iam/grpc-google-iam-v2/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
grpc-google-iam-v2
- 1.35.0
+ 1.36.0
grpc-google-iam-v2
GRPC library for proto-google-iam-v2
com.google.cloud
google-iam-parent
- 1.35.0
+ 1.36.0
diff --git a/java-iam/grpc-google-iam-v2beta/pom.xml b/java-iam/grpc-google-iam-v2beta/pom.xml
index f9e2dac6d2..4cadf90de1 100644
--- a/java-iam/grpc-google-iam-v2beta/pom.xml
+++ b/java-iam/grpc-google-iam-v2beta/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
grpc-google-iam-v2beta
- 1.35.0
+ 1.36.0
grpc-google-iam-v2beta
GRPC library for proto-google-iam-v1
com.google.cloud
google-iam-parent
- 1.35.0
+ 1.36.0
diff --git a/java-iam/pom.xml b/java-iam/pom.xml
index 638da0ca20..170233017f 100644
--- a/java-iam/pom.xml
+++ b/java-iam/pom.xml
@@ -4,7 +4,7 @@
com.google.cloud
google-iam-parent
pom
- 1.35.0
+ 1.36.0
Google IAM Parent
Java idiomatic client for Google Cloud Platform services.
@@ -13,7 +13,7 @@
com.google.api
gapic-generator-java-pom-parent
- 2.41.0
+ 2.42.0
../gapic-generator-java-pom-parent
@@ -60,7 +60,7 @@
com.google.cloud
third-party-dependencies
- 3.31.0
+ 3.32.0
pom
import
@@ -88,44 +88,44 @@
com.google.api
gax-bom
- 2.49.0
+ 2.50.0
pom
import
com.google.api.grpc
proto-google-iam-v2
- 1.35.0
+ 1.36.0
com.google.api.grpc
grpc-google-iam-v2
- 1.35.0
+ 1.36.0
com.google.api.grpc
proto-google-common-protos
- 2.40.0
+ 2.41.0
com.google.api.grpc
proto-google-iam-v2beta
- 1.35.0
+ 1.36.0
com.google.api.grpc
grpc-google-iam-v1
- 1.35.0
+ 1.36.0
com.google.api.grpc
grpc-google-iam-v2beta
- 1.35.0
+ 1.36.0
com.google.api.grpc
proto-google-iam-v1
- 1.35.0
+ 1.36.0
javax.annotation
@@ -156,7 +156,7 @@
org.apache.maven.plugins
maven-project-info-reports-plugin
- 3.5.0
+ 3.6.0
diff --git a/java-iam/proto-google-iam-v1/pom.xml b/java-iam/proto-google-iam-v1/pom.xml
index ea044eb560..4b8be92b2f 100644
--- a/java-iam/proto-google-iam-v1/pom.xml
+++ b/java-iam/proto-google-iam-v1/pom.xml
@@ -3,13 +3,13 @@
4.0.0
com.google.api.grpc
proto-google-iam-v1
- 1.35.0
+ 1.36.0
proto-google-iam-v1
PROTO library for proto-google-iam-v1
com.google.cloud
google-iam-parent
- 1.35.0
+ 1.36.0
diff --git a/java-iam/proto-google-iam-v1/src/main/java/com/google/iam/v1/logging/AuditData.java b/java-iam/proto-google-iam-v1/src/main/java/com/google/iam/v1/logging/AuditData.java
index 268cbc4d2b..85f9ce4883 100644
--- a/java-iam/proto-google-iam-v1/src/main/java/com/google/iam/v1/logging/AuditData.java
+++ b/java-iam/proto-google-iam-v1/src/main/java/com/google/iam/v1/logging/AuditData.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/iam/v1/logging/audit_data.proto
+// Protobuf Java Version: 3.25.3
package com.google.iam.v1.logging;
/**
@@ -47,63 +48,6 @@ protected java.lang.Object newInstance(UnusedPrivateParameter unused) {
return new AuditData();
}
- @java.lang.Override
- public final com.google.protobuf.UnknownFieldSet getUnknownFields() {
- return this.unknownFields;
- }
-
- private AuditData(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- this();
- if (extensionRegistry == null) {
- throw new java.lang.NullPointerException();
- }
- com.google.protobuf.UnknownFieldSet.Builder unknownFields =
- com.google.protobuf.UnknownFieldSet.newBuilder();
- try {
- boolean done = false;
- while (!done) {
- int tag = input.readTag();
- switch (tag) {
- case 0:
- done = true;
- break;
- case 18:
- {
- com.google.iam.v1.PolicyDelta.Builder subBuilder = null;
- if (policyDelta_ != null) {
- subBuilder = policyDelta_.toBuilder();
- }
- policyDelta_ =
- input.readMessage(com.google.iam.v1.PolicyDelta.parser(), extensionRegistry);
- if (subBuilder != null) {
- subBuilder.mergeFrom(policyDelta_);
- policyDelta_ = subBuilder.buildPartial();
- }
-
- break;
- }
- default:
- {
- if (!parseUnknownField(input, unknownFields, extensionRegistry, tag)) {
- done = true;
- }
- break;
- }
- }
- }
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- throw e.setUnfinishedMessage(this);
- } catch (java.io.IOException e) {
- throw new com.google.protobuf.InvalidProtocolBufferException(e).setUnfinishedMessage(this);
- } finally {
- this.unknownFields = unknownFields.build();
- makeExtensionsImmutable();
- }
- }
-
public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {
return com.google.iam.v1.logging.AuditDataProto
.internal_static_google_iam_v1_logging_AuditData_descriptor;
@@ -119,6 +63,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {
com.google.iam.v1.logging.AuditData.Builder.class);
}
+ private int bitField0_;
public static final int POLICY_DELTA_FIELD_NUMBER = 2;
private com.google.iam.v1.PolicyDelta policyDelta_;
/**
@@ -134,7 +79,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {
*/
@java.lang.Override
public boolean hasPolicyDelta() {
- return policyDelta_ != null;
+ return ((bitField0_ & 0x00000001) != 0);
}
/**
*
@@ -162,7 +107,7 @@ public com.google.iam.v1.PolicyDelta getPolicyDelta() {
*/
@java.lang.Override
public com.google.iam.v1.PolicyDeltaOrBuilder getPolicyDeltaOrBuilder() {
- return getPolicyDelta();
+ return policyDelta_ == null ? com.google.iam.v1.PolicyDelta.getDefaultInstance() : policyDelta_;
}
private byte memoizedIsInitialized = -1;
@@ -179,10 +124,10 @@ public final boolean isInitialized() {
@java.lang.Override
public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException {
- if (policyDelta_ != null) {
+ if (((bitField0_ & 0x00000001) != 0)) {
output.writeMessage(2, getPolicyDelta());
}
- unknownFields.writeTo(output);
+ getUnknownFields().writeTo(output);
}
@java.lang.Override
@@ -191,10 +136,10 @@ public int getSerializedSize() {
if (size != -1) return size;
size = 0;
- if (policyDelta_ != null) {
+ if (((bitField0_ & 0x00000001) != 0)) {
size += com.google.protobuf.CodedOutputStream.computeMessageSize(2, getPolicyDelta());
}
- size += unknownFields.getSerializedSize();
+ size += getUnknownFields().getSerializedSize();
memoizedSize = size;
return size;
}
@@ -213,7 +158,7 @@ public boolean equals(final java.lang.Object obj) {
if (hasPolicyDelta()) {
if (!getPolicyDelta().equals(other.getPolicyDelta())) return false;
}
- if (!unknownFields.equals(other.unknownFields)) return false;
+ if (!getUnknownFields().equals(other.getUnknownFields())) return false;
return true;
}
@@ -228,7 +173,7 @@ public int hashCode() {
hash = (37 * hash) + POLICY_DELTA_FIELD_NUMBER;
hash = (53 * hash) + getPolicyDelta().hashCode();
}
- hash = (29 * hash) + unknownFields.hashCode();
+ hash = (29 * hash) + getUnknownFields().hashCode();
memoizedHashCode = hash;
return hash;
}
@@ -368,16 +313,18 @@ private Builder(com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
}
private void maybeForceBuilderInitialization() {
- if (com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders) {}
+ if (com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders) {
+ getPolicyDeltaFieldBuilder();
+ }
}
@java.lang.Override
public Builder clear() {
super.clear();
- if (policyDeltaBuilder_ == null) {
- policyDelta_ = null;
- } else {
- policyDelta_ = null;
+ bitField0_ = 0;
+ policyDelta_ = null;
+ if (policyDeltaBuilder_ != null) {
+ policyDeltaBuilder_.dispose();
policyDeltaBuilder_ = null;
}
return this;
@@ -406,15 +353,24 @@ public com.google.iam.v1.logging.AuditData build() {
@java.lang.Override
public com.google.iam.v1.logging.AuditData buildPartial() {
com.google.iam.v1.logging.AuditData result = new com.google.iam.v1.logging.AuditData(this);
- if (policyDeltaBuilder_ == null) {
- result.policyDelta_ = policyDelta_;
- } else {
- result.policyDelta_ = policyDeltaBuilder_.build();
+ if (bitField0_ != 0) {
+ buildPartial0(result);
}
onBuilt();
return result;
}
+ private void buildPartial0(com.google.iam.v1.logging.AuditData result) {
+ int from_bitField0_ = bitField0_;
+ int to_bitField0_ = 0;
+ if (((from_bitField0_ & 0x00000001) != 0)) {
+ result.policyDelta_ =
+ policyDeltaBuilder_ == null ? policyDelta_ : policyDeltaBuilder_.build();
+ to_bitField0_ |= 0x00000001;
+ }
+ result.bitField0_ |= to_bitField0_;
+ }
+
@java.lang.Override
public Builder clone() {
return super.clone();
@@ -463,7 +419,7 @@ public Builder mergeFrom(com.google.iam.v1.logging.AuditData other) {
if (other.hasPolicyDelta()) {
mergePolicyDelta(other.getPolicyDelta());
}
- this.mergeUnknownFields(other.unknownFields);
+ this.mergeUnknownFields(other.getUnknownFields());
onChanged();
return this;
}
@@ -478,20 +434,42 @@ public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
- com.google.iam.v1.logging.AuditData parsedMessage = null;
+ if (extensionRegistry == null) {
+ throw new java.lang.NullPointerException();
+ }
try {
- parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+ boolean done = false;
+ while (!done) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ done = true;
+ break;
+ case 18:
+ {
+ input.readMessage(getPolicyDeltaFieldBuilder().getBuilder(), extensionRegistry);
+ bitField0_ |= 0x00000001;
+ break;
+ } // case 18
+ default:
+ {
+ if (!super.parseUnknownField(input, extensionRegistry, tag)) {
+ done = true; // was an endgroup tag
+ }
+ break;
+ } // default:
+ } // switch (tag)
+ } // while (!done)
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
- parsedMessage = (com.google.iam.v1.logging.AuditData) e.getUnfinishedMessage();
throw e.unwrapIOException();
} finally {
- if (parsedMessage != null) {
- mergeFrom(parsedMessage);
- }
- }
+ onChanged();
+ } // finally
return this;
}
+ private int bitField0_;
+
private com.google.iam.v1.PolicyDelta policyDelta_;
private com.google.protobuf.SingleFieldBuilderV3<
com.google.iam.v1.PolicyDelta,
@@ -510,7 +488,7 @@ public Builder mergeFrom(
* @return Whether the policyDelta field is set.
*/
public boolean hasPolicyDelta() {
- return policyDeltaBuilder_ != null || policyDelta_ != null;
+ return ((bitField0_ & 0x00000001) != 0);
}
/**
*
@@ -547,11 +525,11 @@ public Builder setPolicyDelta(com.google.iam.v1.PolicyDelta value) {
throw new NullPointerException();
}
policyDelta_ = value;
- onChanged();
} else {
policyDeltaBuilder_.setMessage(value);
}
-
+ bitField0_ |= 0x00000001;
+ onChanged();
return this;
}
/**
@@ -566,11 +544,11 @@ public Builder setPolicyDelta(com.google.iam.v1.PolicyDelta value) {
public Builder setPolicyDelta(com.google.iam.v1.PolicyDelta.Builder builderForValue) {
if (policyDeltaBuilder_ == null) {
policyDelta_ = builderForValue.build();
- onChanged();
} else {
policyDeltaBuilder_.setMessage(builderForValue.build());
}
-
+ bitField0_ |= 0x00000001;
+ onChanged();
return this;
}
/**
@@ -584,19 +562,20 @@ public Builder setPolicyDelta(com.google.iam.v1.PolicyDelta.Builder builderForVa
*/
public Builder mergePolicyDelta(com.google.iam.v1.PolicyDelta value) {
if (policyDeltaBuilder_ == null) {
- if (policyDelta_ != null) {
- policyDelta_ =
- com.google.iam.v1.PolicyDelta.newBuilder(policyDelta_)
- .mergeFrom(value)
- .buildPartial();
+ if (((bitField0_ & 0x00000001) != 0)
+ && policyDelta_ != null
+ && policyDelta_ != com.google.iam.v1.PolicyDelta.getDefaultInstance()) {
+ getPolicyDeltaBuilder().mergeFrom(value);
} else {
policyDelta_ = value;
}
- onChanged();
} else {
policyDeltaBuilder_.mergeFrom(value);
}
-
+ if (policyDelta_ != null) {
+ bitField0_ |= 0x00000001;
+ onChanged();
+ }
return this;
}
/**
@@ -609,14 +588,13 @@ public Builder mergePolicyDelta(com.google.iam.v1.PolicyDelta value) {
* .google.iam.v1.PolicyDelta policy_delta = 2;
*/
public Builder clearPolicyDelta() {
- if (policyDeltaBuilder_ == null) {
- policyDelta_ = null;
- onChanged();
- } else {
- policyDelta_ = null;
+ bitField0_ = (bitField0_ & ~0x00000001);
+ policyDelta_ = null;
+ if (policyDeltaBuilder_ != null) {
+ policyDeltaBuilder_.dispose();
policyDeltaBuilder_ = null;
}
-
+ onChanged();
return this;
}
/**
@@ -629,7 +607,7 @@ public Builder clearPolicyDelta() {
* .google.iam.v1.PolicyDelta policy_delta = 2;
*/
public com.google.iam.v1.PolicyDelta.Builder getPolicyDeltaBuilder() {
-
+ bitField0_ |= 0x00000001;
onChanged();
return getPolicyDeltaFieldBuilder().getBuilder();
}
@@ -709,7 +687,18 @@ public AuditData parsePartialFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
- return new AuditData(input, extensionRegistry);
+ Builder builder = newBuilder();
+ try {
+ builder.mergeFrom(input, extensionRegistry);
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(builder.buildPartial());
+ } catch (com.google.protobuf.UninitializedMessageException e) {
+ throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());
+ } catch (java.io.IOException e) {
+ throw new com.google.protobuf.InvalidProtocolBufferException(e)
+ .setUnfinishedMessage(builder.buildPartial());
+ }
+ return builder.buildPartial();
}
};
diff --git a/java-iam/proto-google-iam-v1/src/main/java/com/google/iam/v1/logging/AuditDataOrBuilder.java b/java-iam/proto-google-iam-v1/src/main/java/com/google/iam/v1/logging/AuditDataOrBuilder.java
index 8076902f48..fc36bcab08 100644
--- a/java-iam/proto-google-iam-v1/src/main/java/com/google/iam/v1/logging/AuditDataOrBuilder.java
+++ b/java-iam/proto-google-iam-v1/src/main/java/com/google/iam/v1/logging/AuditDataOrBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/iam/v1/logging/audit_data.proto
+// Protobuf Java Version: 3.25.3
package com.google.iam.v1.logging;
public interface AuditDataOrBuilder
diff --git a/java-iam/proto-google-iam-v1/src/main/java/com/google/iam/v1/logging/AuditDataProto.java b/java-iam/proto-google-iam-v1/src/main/java/com/google/iam/v1/logging/AuditDataProto.java
index 7a5309a6ca..e93d753477 100644
--- a/java-iam/proto-google-iam-v1/src/main/java/com/google/iam/v1/logging/AuditDataProto.java
+++ b/java-iam/proto-google-iam-v1/src/main/java/com/google/iam/v1/logging/AuditDataProto.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/iam/v1/logging/audit_data.proto
+// Protobuf Java Version: 3.25.3
package com.google.iam.v1.logging;
public final class AuditDataProto {
@@ -41,20 +42,18 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() {
static {
java.lang.String[] descriptorData = {
"\n&google/iam/v1/logging/audit_data.proto"
- + "\022\025google.iam.v1.logging\032\034google/api/anno"
- + "tations.proto\032\032google/iam/v1/policy.prot"
- + "o\"=\n\tAuditData\0220\n\014policy_delta\030\002 \001(\0132\032.g"
- + "oogle.iam.v1.PolicyDeltaB\211\001\n\031com.google."
- + "iam.v1.loggingB\016AuditDataProtoP\001Z4.0.0
com.google.api.grpc
proto-google-iam-v2
- 1.35.0
+ 1.36.0
proto-google-iam-v2
Proto library for proto-google-iam-v1
com.google.cloud
google-iam-parent
- 1.35.0
+ 1.36.0
diff --git a/java-iam/proto-google-iam-v2beta/pom.xml b/java-iam/proto-google-iam-v2beta/pom.xml
index b759d0ffae..20556223c9 100644
--- a/java-iam/proto-google-iam-v2beta/pom.xml
+++ b/java-iam/proto-google-iam-v2beta/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
proto-google-iam-v2beta
- 1.35.0
+ 1.36.0
proto-google-iam-v2beta
Proto library for proto-google-iam-v1
com.google.cloud
google-iam-parent
- 1.35.0
+ 1.36.0
diff --git a/java-shared-dependencies/README.md b/java-shared-dependencies/README.md
index cdbbcc91bd..2e537bf5af 100644
--- a/java-shared-dependencies/README.md
+++ b/java-shared-dependencies/README.md
@@ -14,7 +14,7 @@ If you are using Maven, add this to the `dependencyManagement` section.
com.google.cloud
google-cloud-shared-dependencies
- 3.31.0
+ 3.32.0
pom
import
diff --git a/java-shared-dependencies/dependency-analyzer/pom.xml b/java-shared-dependencies/dependency-analyzer/pom.xml
index 41283a61a7..18c38eaa06 100644
--- a/java-shared-dependencies/dependency-analyzer/pom.xml
+++ b/java-shared-dependencies/dependency-analyzer/pom.xml
@@ -41,7 +41,7 @@
org.apache.maven.plugins
maven-surefire-plugin
- 3.2.5
+ 3.3.0
+ 3.32.0
Dependency convergence test for certain artifacts in Google Cloud Shared Dependencies
An dependency convergence test case for the shared dependencies BOM. A failure of this test case means
diff --git a/java-shared-dependencies/first-party-dependencies/pom.xml b/java-shared-dependencies/first-party-dependencies/pom.xml
index 2cce1cab38..9c6c20fd7b 100644
--- a/java-shared-dependencies/first-party-dependencies/pom.xml
+++ b/java-shared-dependencies/first-party-dependencies/pom.xml
@@ -6,7 +6,7 @@
com.google.cloud
first-party-dependencies
pom
- 3.31.0
+ 3.32.0
Google Cloud First-party Shared Dependencies
Shared first-party dependencies for Google Cloud Java libraries.
@@ -15,14 +15,14 @@
com.google.cloud
google-cloud-shared-config
- 1.8.0
+ 1.8.1
UTF-8
${project.artifactId}
- 1.6.0
+ 1.6.1
1.36.0
2.6.0
@@ -33,7 +33,7 @@
com.google.api
gapic-generator-java-bom
- 2.41.0
+ 2.42.0
pom
import
@@ -45,7 +45,7 @@
com.google.cloud
google-cloud-core-bom
- 2.39.0
+ 2.40.0
pom
import
@@ -69,13 +69,13 @@
com.google.cloud
google-cloud-core
- 2.39.0
+ 2.40.0
test-jar
com.google.cloud
google-cloud-core
- 2.39.0
+ 2.40.0
tests
diff --git a/java-shared-dependencies/pom.xml b/java-shared-dependencies/pom.xml
index 57c262313b..8f45c4f242 100644
--- a/java-shared-dependencies/pom.xml
+++ b/java-shared-dependencies/pom.xml
@@ -4,7 +4,7 @@
com.google.cloud
google-cloud-shared-dependencies
pom
- 3.31.0
+ 3.32.0
first-party-dependencies
third-party-dependencies
@@ -17,7 +17,7 @@
com.google.api
gapic-generator-java-pom-parent
- 2.41.0
+ 2.42.0
../gapic-generator-java-pom-parent
@@ -31,14 +31,14 @@
com.google.cloud
first-party-dependencies
- 3.31.0
+ 3.32.0
pom
import
com.google.cloud
third-party-dependencies
- 3.31.0
+ 3.32.0
pom
import
diff --git a/java-shared-dependencies/third-party-dependencies/pom.xml b/java-shared-dependencies/third-party-dependencies/pom.xml
index e4e1f556b5..93815ef374 100644
--- a/java-shared-dependencies/third-party-dependencies/pom.xml
+++ b/java-shared-dependencies/third-party-dependencies/pom.xml
@@ -6,7 +6,7 @@
com.google.cloud
third-party-dependencies
pom
- 3.31.0
+ 3.32.0
Google Cloud Third-party Shared Dependencies
Shared third-party dependencies for Google Cloud Java libraries.
@@ -15,7 +15,7 @@
com.google.api
gapic-generator-java-pom-parent
- 2.41.0
+ 2.42.0
../../gapic-generator-java-pom-parent
@@ -33,7 +33,7 @@
4.4.16
4.5.14
- 3.43.0
+ 3.44.0
0.27.0
3.0.0
0.29.0
diff --git a/java-shared-dependencies/upper-bound-check/pom.xml b/java-shared-dependencies/upper-bound-check/pom.xml
index 3d8ee8e16f..0a4e47f2ef 100644
--- a/java-shared-dependencies/upper-bound-check/pom.xml
+++ b/java-shared-dependencies/upper-bound-check/pom.xml
@@ -4,7 +4,7 @@
com.google.cloud
shared-dependencies-upper-bound-test
pom
- 3.31.0
+ 3.32.0
Upper bound test for Google Cloud Shared Dependencies
An upper bound test case for the shared dependencies BOM. A failure of this test case means
@@ -16,7 +16,7 @@
com.google.cloud
google-cloud-shared-config
- 1.8.0
+ 1.8.1
@@ -30,7 +30,7 @@
com.google.cloud
google-cloud-shared-dependencies
- 3.31.0
+ 3.32.0
pom
import
diff --git a/library_generation/cli/entry_point.py b/library_generation/cli/entry_point.py
index 0bb499e9f2..dbcc18b267 100644
--- a/library_generation/cli/entry_point.py
+++ b/library_generation/cli/entry_point.py
@@ -135,8 +135,7 @@ def generate(
target_library_names=config_change.get_changed_libraries(),
)
generate_pr_descriptions(
- config=config_change.current_config,
- baseline_commit=config_change.baseline_config.googleapis_commitish,
+ config_change=config_change,
description_path=repository_path,
)
diff --git a/library_generation/generate_composed_library.py b/library_generation/generate_composed_library.py
index 11c98e2dd9..46e1491ccc 100755
--- a/library_generation/generate_composed_library.py
+++ b/library_generation/generate_composed_library.py
@@ -66,14 +66,14 @@ def generate_composed_library(
base_arguments = __construct_tooling_arg(config=config)
owlbot_cli_source_folder = util.sh_util("mktemp -d")
os.makedirs(f"{library_path}", exist_ok=True)
- for gapic in library.gapic_configs:
+ for gapic in library.get_sorted_gapic_configs():
build_file_folder = Path(f"{output_folder}/{gapic.proto_path}").resolve()
print(f"build_file_folder: {build_file_folder}")
gapic_inputs = parse_build_file(build_file_folder, gapic.proto_path)
- # generate prerequisite files (.repo-metadata.json, .OwlBot-hermetic.yaml,
+ # generate postprocessing prerequisite files (.repo-metadata.json, .OwlBot-hermetic.yaml,
# owlbot.py) here because transport is parsed from BUILD.bazel,
# which lives in a versioned proto_path.
- util.generate_prerequisite_files(
+ util.generate_postprocessing_prerequisite_files(
config=config,
library=library,
proto_path=util.remove_version_from(gapic.proto_path),
diff --git a/library_generation/generate_library.sh b/library_generation/generate_library.sh
index f6875bfe6d..ecf8c64a50 100755
--- a/library_generation/generate_library.sh
+++ b/library_generation/generate_library.sh
@@ -143,7 +143,7 @@ folder_name=$(extract_folder_name "${destination_path}")
pushd "${output_folder}"
find_depth=""
case "${proto_path}" in
- "google/api" | "google/cloud" | "google/iam/v1" | "google/rpc")
+ "google/api" | "google/cloud" | "google/rpc")
find_depth="-maxdepth 1"
;;
esac
@@ -273,14 +273,6 @@ case "${proto_path}" in
"google/devtools/containeranalysis/v1beta1"*)
proto_files="${proto_files} google/devtools/containeranalysis/v1beta1/cvss/cvss.proto"
;;
- "google/iam/v1")
- # these protos are excluded from //google/iam/v1:google-iam-v1-java
- prefix="google/iam/v1"
- protos="${prefix}/options.proto ${prefix}/policy.proto"
- for removed_proto in ${protos}; do
- proto_files="${proto_files//${removed_proto}/}"
- done
- ;;
esac
# copy proto files to proto-*/src/main/proto
for proto_src in ${proto_files}; do
diff --git a/library_generation/generate_pr_description.py b/library_generation/generate_pr_description.py
index e4852b6eab..75d6671e43 100644
--- a/library_generation/generate_pr_description.py
+++ b/library_generation/generate_pr_description.py
@@ -17,10 +17,12 @@
import shutil
from typing import Dict
from git import Commit, Repo
-from library_generation.model.generation_config import GenerationConfig
+
+from library_generation.model.config_change import ConfigChange
from library_generation.utils.proto_path_utils import find_versioned_proto_path
from library_generation.utils.commit_message_formatter import (
format_commit_message,
+ format_repo_level_change,
commit_link,
)
from library_generation.utils.commit_message_formatter import wrap_override_commit
@@ -29,42 +31,38 @@
def generate_pr_descriptions(
- config: GenerationConfig,
- baseline_commit: str,
+ config_change: ConfigChange,
description_path: str,
repo_url: str = "https://github.com/googleapis/googleapis.git",
) -> None:
"""
- Generate pull request description from baseline_commit (exclusive) to the
- googleapis commit (inclusive) in the given generation config.
+ Generate pull request description from configuration comparison result.
+
+ The pull request description contains repo-level changes, if applicable,
+ and googleapis commit from baseline config (exclusive) to current config
+ (inclusive).
The pull request description will be generated into
description_path/pr_description.txt.
- If baseline_commit is the same as googleapis commit in the given generation
- config, no pr_description.txt will be generated.
+ No pr_description.txt will be generated if no changes in the configurations.
- :param config: a GenerationConfig object. The googleapis commit in this
- configuration is the latest commit, inclusively, from which the commit
- message is considered.
- :param baseline_commit: The baseline (oldest) commit, exclusively, from
- which the commit message is considered. This commit should be an ancestor
- of googleapis commit in configuration.
+ :param config_change: a ConfigChange object, containing changes in baseline
+ and current generation configurations.
:param description_path: the path to which the pull request description
file goes.
:param repo_url: the GitHub repository from which retrieves the commit
history.
"""
- if baseline_commit == config.googleapis_commitish:
- return
-
- paths = config.get_proto_path_to_library_name()
- description = get_commit_messages(
+ repo_level_message = format_repo_level_change(config_change)
+ paths = config_change.current_config.get_proto_path_to_library_name()
+ description = get_repo_level_commit_messages(
repo_url=repo_url,
- current_commit_sha=config.googleapis_commitish,
- baseline_commit_sha=baseline_commit,
+ current_commit_sha=config_change.current_config.googleapis_commitish,
+ baseline_commit_sha=config_change.baseline_config.googleapis_commitish,
paths=paths,
- is_monorepo=config.is_monorepo(),
+ is_monorepo=config_change.current_config.is_monorepo(),
+ repo_level_message=repo_level_message,
)
if description == EMPTY_MESSAGE:
@@ -77,12 +75,13 @@ def generate_pr_descriptions(
f.write(description)
-def get_commit_messages(
+def get_repo_level_commit_messages(
repo_url: str,
current_commit_sha: str,
baseline_commit_sha: str,
paths: Dict[str, str],
is_monorepo: bool,
+ repo_level_message: list[str] = None,
) -> str:
"""
Combine commit messages of a repository from latest_commit to
@@ -97,10 +96,13 @@ def get_commit_messages(
selecting commit message. This commit should be an ancestor of
:param paths: a mapping from file paths to library_name.
:param is_monorepo: whether to generate commit messages in a monorepo.
+ :param repo_level_message: commit messages regarding repo-level changes.
:return: commit messages.
:raise ValueError: if current_commit is older than or equal to
baseline_commit.
"""
+ if current_commit_sha == baseline_commit_sha:
+ return EMPTY_MESSAGE
tmp_dir = "/tmp/repo"
shutil.rmtree(tmp_dir, ignore_errors=True)
os.mkdir(tmp_dir)
@@ -134,6 +136,7 @@ def get_commit_messages(
baseline_commit=baseline_commit,
commits=qualified_commits,
is_monorepo=is_monorepo,
+ repo_level_message=repo_level_message,
)
@@ -160,20 +163,19 @@ def __combine_commit_messages(
baseline_commit: Commit,
commits: Dict[Commit, str],
is_monorepo: bool,
+ repo_level_message: list[str],
) -> str:
- messages = [
- f"This pull request is generated with proto changes between {commit_link(baseline_commit)} (exclusive) "
- f"and {commit_link(current_commit)} (inclusive).",
- "",
+ description = [
+ f"This pull request is generated with proto changes between "
+ f"{commit_link(baseline_commit)} (exclusive) "
+ f"and {commit_link(current_commit)} (inclusive).\n",
]
-
- messages.extend(
- wrap_override_commit(
- format_commit_message(commits=commits, is_monorepo=is_monorepo)
- )
+ commit_message = repo_level_message
+ commit_message.extend(
+ format_commit_message(commits=commits, is_monorepo=is_monorepo)
)
-
- return "\n".join(messages)
+ description.extend(wrap_override_commit(commit_message))
+ return "\n".join(description)
def __get_commit_timestamp(commit: Commit) -> int:
diff --git a/library_generation/model/gapic_config.py b/library_generation/model/gapic_config.py
index bec1645823..3bbba39454 100644
--- a/library_generation/model/gapic_config.py
+++ b/library_generation/model/gapic_config.py
@@ -12,6 +12,11 @@
# 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.
+import re
+from typing import Optional
+
+ALPHA_VERSION = "alpha"
+BETA_VERSION = "beta"
class GapicConfig:
@@ -22,3 +27,73 @@ class GapicConfig:
def __init__(self, proto_path: str):
self.proto_path = proto_path
+ self.version = self.__parse_version()
+
+ def is_stable(self):
+ return (
+ self.version
+ and (ALPHA_VERSION not in self.version)
+ and (BETA_VERSION not in self.version)
+ )
+
+ def get_version(self):
+ return self.version
+
+ def __parse_version(self) -> Optional[str]:
+ version_regex = re.compile(r"^v[1-9]+(p[1-9]+)*(alpha|beta)?.*")
+ for directory in self.proto_path.split("/"):
+ if version_regex.search(directory):
+ return directory
+ return None
+
+ def __eq__(self, other) -> bool:
+ if not isinstance(other, GapicConfig):
+ return False
+ return self.proto_path == other.proto_path
+
+ def __lt__(self, other) -> bool:
+ if not isinstance(other, GapicConfig):
+ raise ValueError(
+ f"Type {type(other)} can't be comparable " f"with GapicConfig."
+ )
+
+ self_version = self.get_version()
+ other_version = other.get_version()
+ self_dirs = self.proto_path.split("/")
+ other_dirs = other.proto_path.split("/")
+ # Case 1: if both of the configs don't have a version in proto_path,
+ # the one with lower depth is smaller.
+ if (not self_version) and (not other_version):
+ return len(self_dirs) < len(other_dirs)
+ # Case 2: if only one config has a version in proto_path, it is smaller
+ # than the other one.
+ if self_version and (not other_version):
+ return True
+ if (not self_version) and other_version:
+ return False
+ # Two configs both have a version in proto_path.
+ self_stable = self.is_stable()
+ other_stable = other.is_stable()
+ # Case 3, if only config has a stable version in proto_path, it is
+ # smaller than the other one.
+ if self_stable and (not other_stable):
+ return True
+ if (not self_stable) and other_stable:
+ return False
+ # Case 4, if two configs have a non-stable version in proto_path,
+ # the one with higher version is smaller.
+ # Note that using string comparison may lead unexpected result,
+ # e.g., v1beta10 is smaller than v1beta2.
+ # In reality, however, there's unlikely that a library has >10 beta
+ # versions.
+ if (not self_stable) and (not other_stable):
+ return self_version > other_version
+ # Two configs both have a stable version in proto_path.
+ # Case 5, if two configs have different depth in proto_path, the one
+ # with lower depth is smaller.
+ if len(self_dirs) != len(other_dirs):
+ return len(self_dirs) < len(other_dirs)
+ # Case 6, the config with higher stable version is smaller.
+ self_num = int(self_version[1:])
+ other_num = int(other_version[1:])
+ return self_num > other_num
diff --git a/library_generation/model/generation_config.py b/library_generation/model/generation_config.py
index 4503daf163..8a2b0829c4 100644
--- a/library_generation/model/generation_config.py
+++ b/library_generation/model/generation_config.py
@@ -21,6 +21,8 @@
LIBRARY_LEVEL_PARAMETER = "Library level parameter"
GAPIC_LEVEL_PARAMETER = "GAPIC level parameter"
COMMON_PROTOS_LIBRARY_NAME = "common-protos"
+GAPIC_GENERATOR_VERSION = "gapic_generator_version"
+LIBRARIES_BOM_VERSION = "libraries_bom_version"
class GenerationConfig:
@@ -139,19 +141,21 @@ def from_yaml(path_to_yaml: str) -> GenerationConfig:
extra_versioned_modules=__optional(
library, "extra_versioned_modules", None
),
+ recommended_package=__optional(library, "recommended_package", None),
+ min_java_version=__optional(library, "min_java_version", None),
)
parsed_libraries.append(new_library)
parsed_config = GenerationConfig(
gapic_generator_version=__required(
- config, "gapic_generator_version", REPO_LEVEL_PARAMETER
+ config, GAPIC_GENERATOR_VERSION, REPO_LEVEL_PARAMETER
),
googleapis_commitish=__required(
config, "googleapis_commitish", REPO_LEVEL_PARAMETER
),
grpc_version=__optional(config, "grpc_version", None),
protoc_version=__optional(config, "protoc_version", None),
- libraries_bom_version=__optional(config, "libraries_bom_version", None),
+ libraries_bom_version=__optional(config, LIBRARIES_BOM_VERSION, None),
libraries=parsed_libraries,
)
diff --git a/library_generation/model/library_config.py b/library_generation/model/library_config.py
index 30d923da81..52e15891b6 100644
--- a/library_generation/model/library_config.py
+++ b/library_generation/model/library_config.py
@@ -14,7 +14,7 @@
# limitations under the License.
from hashlib import sha1
-from typing import List, Optional
+from typing import Optional
from library_generation.model.gapic_config import GapicConfig
@@ -29,7 +29,7 @@ def __init__(
api_description: str,
name_pretty: str,
product_documentation: str,
- gapic_configs: List[GapicConfig],
+ gapic_configs: list[GapicConfig],
library_type: Optional[str] = None,
release_level: Optional[str] = None,
api_id: Optional[str] = None,
@@ -48,6 +48,8 @@ def __init__(
cloud_api: Optional[bool] = True,
requires_billing: Optional[bool] = True,
extra_versioned_modules: Optional[str] = None,
+ recommended_package: Optional[str] = None,
+ min_java_version: Optional[int] = None,
):
self.api_shortname = api_shortname
self.api_description = api_description
@@ -72,6 +74,8 @@ def __init__(
self.cloud_api = cloud_api
self.requires_billing = requires_billing
self.extra_versioned_modules = extra_versioned_modules
+ self.recommended_package = recommended_package
+ self.min_java_version = min_java_version
def get_library_name(self) -> str:
"""
@@ -80,6 +84,9 @@ def get_library_name(self) -> str:
"""
return self.library_name if self.library_name else self.api_shortname
+ def get_sorted_gapic_configs(self) -> list[GapicConfig]:
+ return sorted(self.gapic_configs)
+
def __eq__(self, other):
return (
self.api_shortname == other.api_shortname
@@ -105,6 +112,8 @@ def __eq__(self, other):
and self.cloud_api == other.cloud_api
and self.requires_billing == other.requires_billing
and self.extra_versioned_modules == other.extra_versioned_modules
+ and self.recommended_package == other.recommended_package
+ and self.min_java_version == other.min_java_version
)
def __hash__(self):
@@ -134,6 +143,8 @@ def __hash__(self):
self.cloud_api,
self.requires_billing,
self.extra_versioned_modules,
+ self.recommended_package,
+ self.min_java_version,
]
+ [config.proto_path for config in self.gapic_configs]
).encode("utf-8")
diff --git a/library_generation/owlbot/templates/java_library/.github/CODEOWNERS b/library_generation/owlbot/templates/java_library/.github/CODEOWNERS
new file mode 100644
index 0000000000..5002a1b08f
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/CODEOWNERS
@@ -0,0 +1,20 @@
+# Code owners file.
+# This file controls who is tagged for review for any given pull request.
+
+# For syntax help see:
+# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax
+{% if 'codeowner_team' in metadata['repo'] %}
+# The {{ metadata['repo']['codeowner_team'] }} is the default owner for changes in this repo
+* @googleapis/yoshi-java {{ metadata['repo']['codeowner_team'] }}
+{% if 'library_type' in metadata['repo'] and metadata['repo']['library_type'] != 'GAPIC_AUTO' %}
+# for handwritten libraries, keep codeowner_team in .repo-metadata.json as owner
+**/*.java {{ metadata['repo']['codeowner_team'] }}
+{% endif %}
+{% else %}
+* @googleapis/yoshi-java
+{% endif %}
+# The java-samples-reviewers team is the default owner for samples changes
+samples/**/*.java @googleapis/java-samples-reviewers
+
+# Generated snippets should not be owned by samples reviewers
+samples/snippets/generated/ @googleapis/yoshi-java
diff --git a/library_generation/owlbot/templates/java_library/.github/ISSUE_TEMPLATE/bug_report.md b/library_generation/owlbot/templates/java_library/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000000..c7539a6878
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,56 @@
+---
+name: Bug report
+about: Create a report to help us improve
+
+---
+{% if migrated_split_repo %}
+:bus: This library has moved to
+[google-cloud-java/{{ metadata['repo']['repo_short'] }}](
+https://github.com/googleapis/google-cloud-java/tree/main/{{ metadata['repo']['repo_short'] }}).
+This repository will be archived in the future.
+{% endif %}
+Thanks for stopping by to let us know something could be better!
+
+**PLEASE READ**: If you have a support contract with Google, please create an issue in the [support console](https://cloud.google.com/support/) instead of filing on GitHub. This will ensure a timely response.
+
+Please run down the following list and make sure you've tried the usual "quick fixes":
+
+ - Search the issues already opened: https://github.com/googleapis/{{metadata['repo']['repo_short']}}/issues
+ - Check for answers on StackOverflow: http://stackoverflow.com/questions/tagged/google-cloud-platform
+
+If you are still having issues, please include as much information as possible:
+
+#### Environment details
+
+1. Specify the API at the beginning of the title. For example, "BigQuery: ...").
+ General, Core, and Other are also allowed as types
+2. OS type and version:
+3. Java version:
+4. {{metadata['repo']['name']}} version(s):
+
+#### Steps to reproduce
+
+ 1. ?
+ 2. ?
+
+#### Code example
+
+```java
+// example
+```
+
+#### Stack trace
+```
+Any relevant stacktrace here.
+```
+
+#### External references such as API reference guides
+
+- ?
+
+#### Any additional information below
+
+
+Following these steps guarantees the quickest resolution possible.
+
+Thanks!
diff --git a/library_generation/owlbot/templates/java_library/.github/ISSUE_TEMPLATE/feature_request.md b/library_generation/owlbot/templates/java_library/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000000..f89a7dc59e
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,26 @@
+---
+name: Feature request
+about: Suggest an idea for this library
+
+---
+{% if migrated_split_repo %}
+:bus: This library has moved to
+[google-cloud-java/{{ metadata['repo']['repo_short'] }}](
+https://github.com/googleapis/google-cloud-java/tree/main/{{ metadata['repo']['repo_short'] }}).
+This repository will be archived in the future.
+{% endif %}
+Thanks for stopping by to let us know something could be better!
+
+**PLEASE READ**: If you have a support contract with Google, please create an issue in the [support console](https://cloud.google.com/support/) instead of filing on GitHub. This will ensure a timely response.
+
+**Is your feature request related to a problem? Please describe.**
+What the problem is. Example: I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+What you want to happen.
+
+**Describe alternatives you've considered**
+Any alternative solutions or features you've considered.
+
+**Additional context**
+Any other context or screenshots about the feature request.
diff --git a/library_generation/owlbot/templates/java_library/.github/ISSUE_TEMPLATE/support_request.md b/library_generation/owlbot/templates/java_library/.github/ISSUE_TEMPLATE/support_request.md
new file mode 100644
index 0000000000..9958690321
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/ISSUE_TEMPLATE/support_request.md
@@ -0,0 +1,7 @@
+---
+name: Support request
+about: If you have a support contract with Google, please create an issue in the Google Cloud Support console.
+
+---
+
+**PLEASE READ**: If you have a support contract with Google, please create an issue in the [support console](https://cloud.google.com/support/) instead of filing on GitHub. This will ensure a timely response.
diff --git a/library_generation/owlbot/templates/java_library/.github/PULL_REQUEST_TEMPLATE.md b/library_generation/owlbot/templates/java_library/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000000..b3640828ab
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,10 @@
+Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly:
+- [ ] Make sure to open an issue as a [bug/issue](https://github.com/{{ metadata['repo']['repo'] }}/issues/new/choose) before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea
+- [ ] Ensure the tests and linter pass
+- [ ] Code coverage does not decrease (if any source code was changed)
+- [ ] Appropriate docs were updated (if necessary)
+
+Fixes # ☕️
+
+If you write sample code, please follow the [samples format](
+https://github.com/GoogleCloudPlatform/java-docs-samples/blob/main/SAMPLE_FORMAT.md).
diff --git a/library_generation/owlbot/templates/java_library/.github/auto-label.yaml b/library_generation/owlbot/templates/java_library/.github/auto-label.yaml
new file mode 100644
index 0000000000..4caef688b7
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/auto-label.yaml
@@ -0,0 +1,15 @@
+# Copyright 2021 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
+#
+# http://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.
+requestsize:
+ enabled: true
diff --git a/library_generation/owlbot/templates/java_library/.github/blunderbuss.yml b/library_generation/owlbot/templates/java_library/.github/blunderbuss.yml
new file mode 100644
index 0000000000..2176b05432
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/blunderbuss.yml
@@ -0,0 +1,7 @@
+# Configuration for the Blunderbuss GitHub app. For more info see
+# https://github.com/googleapis/repo-automation-bots/tree/main/packages/blunderbuss
+assign_prs_by:
+- labels:
+ - samples
+ to:
+ - googleapis/java-samples-reviewers
\ No newline at end of file
diff --git a/library_generation/owlbot/templates/java_library/.github/dependabot.yml b/library_generation/owlbot/templates/java_library/.github/dependabot.yml
new file mode 100644
index 0000000000..203f9eaccf
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/dependabot.yml
@@ -0,0 +1,19 @@
+version: 2
+updates:
+ - package-ecosystem: "maven"
+ directory: "/"
+ schedule:
+ interval: "daily"
+ # Disable version updates for Maven dependencies
+ # we use renovate-bot as well as shared-dependencies BOM to update maven dependencies.
+ ignore:
+ - dependency-name: "*"
+ - package-ecosystem: "pip"
+ directory: "/"
+ schedule:
+ interval: "daily"
+ # Disable version updates for pip dependencies
+ # If a security vulnerability comes in, we will be notified about
+ # it via template in the synthtool repository.
+ ignore:
+ - dependency-name: "*"
diff --git a/library_generation/owlbot/templates/java_library/.github/generated-files-bot.yml b/library_generation/owlbot/templates/java_library/.github/generated-files-bot.yml
new file mode 100644
index 0000000000..c644a24e11
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/generated-files-bot.yml
@@ -0,0 +1,12 @@
+externalManifests:
+- type: json
+ file: 'synth.metadata'
+ jsonpath: '$.generatedFiles[*]'
+- type: json
+ file: '.github/readme/synth.metadata/synth.metadata'
+ jsonpath: '$.generatedFiles[*]'
+ignoreAuthors:
+- 'renovate-bot'
+- 'yoshi-automation'
+- 'release-please[bot]'
+- 'gcf-owl-bot[bot]'
diff --git a/library_generation/owlbot/templates/java_library/.github/release-please.yml b/library_generation/owlbot/templates/java_library/.github/release-please.yml
new file mode 100644
index 0000000000..8ca7f9cabc
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/release-please.yml
@@ -0,0 +1,3 @@
+bumpMinorPreMajor: true
+handleGHRelease: true
+releaseType: java-yoshi
diff --git a/library_generation/owlbot/templates/java_library/.github/release-trigger.yml b/library_generation/owlbot/templates/java_library/.github/release-trigger.yml
new file mode 100644
index 0000000000..5056d3a13b
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/release-trigger.yml
@@ -0,0 +1,2 @@
+enabled: true
+multiScmName: {{ metadata['repo']['repo_short'] }}
diff --git a/library_generation/owlbot/templates/java_library/.github/scripts/update_generation_config.sh b/library_generation/owlbot/templates/java_library/.github/scripts/update_generation_config.sh
new file mode 100644
index 0000000000..561a313040
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/scripts/update_generation_config.sh
@@ -0,0 +1,121 @@
+#!/bin/bash
+set -e
+# This script should be run at the root of the repository.
+# This script is used to update googleapis_commitish, gapic_generator_version,
+# and libraries_bom_version in generation configuration at the time of running
+# and create a pull request.
+
+# The following commands need to be installed before running the script:
+# 1. git
+# 2. gh
+# 3. jq
+
+# Utility functions
+# Get the latest released version of a Maven artifact.
+function get_latest_released_version() {
+ local group_id=$1
+ local artifact_id=$2
+ latest=$(curl -s "https://search.maven.org/solrsearch/select?q=g:${group_id}+AND+a:${artifact_id}&core=gav&rows=500&wt=json" | jq -r '.response.docs[] | select(.v | test("^[0-9]+(\\.[0-9]+)*$")) | .v' | sort -V | tail -n 1)
+ echo "${latest}"
+}
+
+# Update a key to a new value in the generation config.
+function update_config() {
+ local key_word=$1
+ local new_value=$2
+ local file=$3
+ echo "Update ${key_word} to ${new_value} in ${file}"
+ sed -i -e "s/^${key_word}.*$/${key_word}: ${new_value}/" "${file}"
+}
+
+# The parameters of this script is:
+# 1. base_branch, the base branch of the result pull request.
+# 2. repo, organization/repo-name, e.g., googleapis/google-cloud-java
+# 3. [optional] generation_config, the path to the generation configuration,
+# the default value is generation_config.yaml in the repository root.
+while [[ $# -gt 0 ]]; do
+key="$1"
+case "${key}" in
+ --base_branch)
+ base_branch="$2"
+ shift
+ ;;
+ --repo)
+ repo="$2"
+ shift
+ ;;
+ --generation_config)
+ generation_config="$2"
+ shift
+ ;;
+ *)
+ echo "Invalid option: [$1]"
+ exit 1
+ ;;
+esac
+shift
+done
+
+if [ -z "${base_branch}" ]; then
+ echo "missing required argument --base_branch"
+ exit 1
+fi
+
+if [ -z "${repo}" ]; then
+ echo "missing required argument --repo"
+ exit 1
+fi
+
+if [ -z "${generation_config}" ]; then
+ generation_config="generation_config.yaml"
+ echo "Use default generation config: ${generation_config}"
+fi
+
+current_branch="generate-libraries-${base_branch}"
+title="chore: Update generation configuration at $(date)"
+
+# try to find a open pull request associated with the branch
+pr_num=$(gh pr list -s open -H "${current_branch}" -q . --json number | jq ".[] | .number")
+# create a branch if there's no open pull request associated with the
+# branch; otherwise checkout the pull request.
+if [ -z "${pr_num}" ]; then
+ git checkout -b "${current_branch}"
+else
+ gh pr checkout "${pr_num}"
+fi
+
+mkdir tmp-googleapis
+# use partial clone because only commit history is needed.
+git clone --filter=blob:none https://github.com/googleapis/googleapis.git tmp-googleapis
+pushd tmp-googleapis
+git pull
+latest_commit=$(git rev-parse HEAD)
+popd
+rm -rf tmp-googleapis
+update_config "googleapis_commitish" "${latest_commit}" "${generation_config}"
+
+# update gapic-generator-java version to the latest
+latest_version=$(get_latest_released_version "com.google.api" "gapic-generator-java")
+update_config "gapic_generator_version" "${latest_version}" "${generation_config}"
+
+# update libraries-bom version to the latest
+latest_version=$(get_latest_released_version "com.google.cloud" "libraries-bom")
+update_config "libraries_bom_version" "${latest_version}" "${generation_config}"
+
+git add "${generation_config}"
+changed_files=$(git diff --cached --name-only)
+if [[ "${changed_files}" == "" ]]; then
+ echo "The latest generation config is not changed."
+ echo "Skip committing to the pull request."
+ exit 0
+fi
+git commit -m "${title}"
+if [ -z "${pr_num}" ]; then
+ git remote add remote_repo https://cloud-java-bot:"${GH_TOKEN}@github.com/${repo}.git"
+ git fetch -q --unshallow remote_repo
+ git push -f remote_repo "${current_branch}"
+ gh pr create --title "${title}" --head "${current_branch}" --body "${title}" --base "${base_branch}"
+else
+ git push
+ gh pr edit "${pr_num}" --title "${title}" --body "${title}"
+fi
diff --git a/library_generation/owlbot/templates/java_library/.github/snippet-bot.yml b/library_generation/owlbot/templates/java_library/.github/snippet-bot.yml
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/library_generation/owlbot/templates/java_library/.github/sync-repo-settings.yaml b/library_generation/owlbot/templates/java_library/.github/sync-repo-settings.yaml
new file mode 100644
index 0000000000..bbfd4c0314
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/sync-repo-settings.yaml
@@ -0,0 +1,64 @@
+# Copyright 2022 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
+#
+# http://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.
+# Whether or not rebase-merging is enabled on this repository.
+# Defaults to `true`
+rebaseMergeAllowed: false
+
+# Whether or not squash-merging is enabled on this repository.
+# Defaults to `true`
+squashMergeAllowed: true
+
+# Whether or not PRs are merged with a merge commit on this repository.
+# Defaults to `false`
+mergeCommitAllowed: false
+
+# Rules for main branch protection
+branchProtectionRules:
+# Identifies the protection rule pattern. Name of the branch to be protected.
+# Defaults to `main`
+- pattern: main
+ # Can admins overwrite branch protection.
+ # Defaults to `true`
+ isAdminEnforced: true
+ # Number of approving reviews required to update matching branches.
+ # Defaults to `1`
+ requiredApprovingReviewCount: 1
+ # Are reviews from code owners required to update matching branches.
+ # Defaults to `false`
+ requiresCodeOwnerReviews: true
+ # Require up to date branches
+ requiresStrictStatusChecks: false
+ # List of required status check contexts that must pass for commits to be accepted to matching branches.
+ requiredStatusCheckContexts:
+ - "dependencies (17)"
+ - "lint"
+ - "javadoc"
+ - "units (8)"
+ - "units (11)"
+ - "Kokoro - Test: Integration"
+ - "cla/google"
+ - "OwlBot Post Processor"
+ - "Kokoro - Test: Java GraalVM Native Image"
+ - "Kokoro - Test: Java 17 GraalVM Native Image"
+# List of explicit permissions to add (additive only)
+permissionRules:
+- team: yoshi-admins
+ permission: admin
+- team: yoshi-java-admins
+ permission: admin
+- team: yoshi-java
+ permission: push
+- team: java-samples-reviewers
+ permission: push
+
diff --git a/library_generation/owlbot/templates/java_library/.github/trusted-contribution.yml b/library_generation/owlbot/templates/java_library/.github/trusted-contribution.yml
new file mode 100644
index 0000000000..88d3ac9bf1
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/trusted-contribution.yml
@@ -0,0 +1,9 @@
+trustedContributors:
+- renovate-bot
+- gcf-owl-bot[bot]
+
+annotations:
+- type: comment
+ text: "/gcbrun"
+- type: label
+ text: "kokoro:force-run"
diff --git a/library_generation/owlbot/templates/java_library/.github/workflows/approve-readme.yaml b/library_generation/owlbot/templates/java_library/.github/workflows/approve-readme.yaml
new file mode 100644
index 0000000000..bbef6d37cc
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/workflows/approve-readme.yaml
@@ -0,0 +1,69 @@
+# Copyright 2022 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
+#
+# http://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.
+# Github action job to test core java library features on
+# downstream client libraries before they are released.
+on:
+ pull_request:
+name: auto-merge-readme
+jobs:
+ approve:
+ runs-on: ubuntu-latest
+ if: github.repository_owner == 'googleapis' && github.head_ref == 'autosynth-readme'
+ steps:
+ - uses: actions/github-script@v7
+ with:
+ github-token: {{ '${{secrets.YOSHI_APPROVER_TOKEN}}' }}
+ script: |
+ // only approve PRs from yoshi-automation
+ if (context.payload.pull_request.user.login !== "yoshi-automation") {
+ return;
+ }
+
+ // only approve PRs like "chore: release "
+ if (!context.payload.pull_request.title === "chore: regenerate README") {
+ return;
+ }
+
+ // only approve PRs with README.md and synth.metadata changes
+ const files = new Set(
+ (
+ await github.paginate(
+ github.pulls.listFiles.endpoint({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ pull_number: context.payload.pull_request.number,
+ })
+ )
+ ).map(file => file.filename)
+ );
+ if (files.size != 2 || !files.has("README.md") || !files.has(".github/readme/synth.metadata/synth.metadata")) {
+ return;
+ }
+
+ // approve README regeneration PR
+ await github.pulls.createReview({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: 'Rubber stamped PR!',
+ pull_number: context.payload.pull_request.number,
+ event: 'APPROVE'
+ });
+
+ // attach automerge label
+ await github.issues.addLabels({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.payload.pull_request.number,
+ labels: ['automerge']
+ });
diff --git a/library_generation/owlbot/templates/java_library/.github/workflows/ci.yaml b/library_generation/owlbot/templates/java_library/.github/workflows/ci.yaml
new file mode 100644
index 0000000000..50487eeb3b
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/workflows/ci.yaml
@@ -0,0 +1,123 @@
+# Copyright 2022 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
+#
+# http://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.
+# Github action job to test core java library features on
+# downstream client libraries before they are released.
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+name: ci
+jobs:
+ units:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ java: [11, 17, 21]
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: ${{'{{matrix.java}}'}}
+ - run: java -version
+ - run: .kokoro/build.sh
+ env:
+ JOB_TYPE: test
+ units-java8:
+ # Building using Java 17 and run the tests with Java 8 runtime
+ name: "units (8)"
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-java@v4
+ with:
+ java-version: 8
+ distribution: temurin
+ - name: "Set jvm system property environment variable for surefire plugin (unit tests)"
+ # Maven surefire plugin (unit tests) allows us to specify JVM to run the tests.
+ # https://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#jvm
+ run: echo "SUREFIRE_JVM_OPT=-Djvm=${JAVA_HOME}/bin/java" >> $GITHUB_ENV
+ shell: bash
+ - uses: actions/setup-java@v4
+ with:
+ java-version: 17
+ distribution: temurin
+ - run: .kokoro/build.sh
+ env:
+ JOB_TYPE: test
+ windows:
+ runs-on: windows-latest
+ steps:
+ - name: Support longpaths
+ run: git config --system core.longpaths true
+ - uses: actions/checkout@v4
+ - uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: 8
+ - run: java -version
+ - run: .kokoro/build.bat
+ env:
+ JOB_TYPE: test
+ dependencies:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ java: [17]
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: ${{'{{matrix.java}}'}}
+ - run: java -version
+ - run: .kokoro/dependencies.sh
+ javadoc:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: 17
+ - run: java -version
+ - run: .kokoro/build.sh
+ env:
+ JOB_TYPE: javadoc
+ lint:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: 11
+ - run: java -version
+ - run: .kokoro/build.sh
+ env:
+ JOB_TYPE: lint
+ clirr:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: 8
+ - run: java -version
+ - run: .kokoro/build.sh
+ env:
+ JOB_TYPE: clirr
diff --git a/library_generation/owlbot/templates/java_library/.github/workflows/renovate_config_check.yaml b/library_generation/owlbot/templates/java_library/.github/workflows/renovate_config_check.yaml
new file mode 100644
index 0000000000..7c5ec7865e
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/workflows/renovate_config_check.yaml
@@ -0,0 +1,25 @@
+name: Renovate Bot Config Validation
+
+on:
+ pull_request:
+ paths:
+ - 'renovate.json'
+
+jobs:
+ renovate_bot_config_validation:
+ runs-on: ubuntu-22.04
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+
+ - name: Install Renovate and Config Validator
+ run: |
+ npm install -g npm@latest
+ npm install --global renovate
+ renovate-config-validator
diff --git a/library_generation/owlbot/templates/java_library/.github/workflows/samples.yaml b/library_generation/owlbot/templates/java_library/.github/workflows/samples.yaml
new file mode 100644
index 0000000000..03b2939567
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/workflows/samples.yaml
@@ -0,0 +1,30 @@
+# Copyright 2022 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
+#
+# http://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.
+# Github action job to test core java library features on
+# downstream client libraries before they are released.
+on:
+ pull_request:
+name: samples
+jobs:
+ checkstyle:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: 8
+ - name: Run checkstyle
+ run: mvn -P lint --quiet --batch-mode checkstyle:check
+ working-directory: samples/snippets
diff --git a/library_generation/owlbot/templates/java_library/.github/workflows/update_generation_config.yaml b/library_generation/owlbot/templates/java_library/.github/workflows/update_generation_config.yaml
new file mode 100644
index 0000000000..e7d5690e0e
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.github/workflows/update_generation_config.yaml
@@ -0,0 +1,42 @@
+# Copyright 2024 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
+#
+# http://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.
+# GitHub action job to test core java library features on
+# downstream client libraries before they are released.
+name: Update generation configuration
+on:
+ schedule:
+ - cron: '0 2 * * *'
+ workflow_dispatch:
+
+jobs:
+ update-generation-config:
+ runs-on: ubuntu-22.04
+ env:
+ # the branch into which the pull request is merged
+ base_branch: main
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }}
+ - name: Update params in generation config to latest
+ shell: bash
+ run: |
+ set -x
+ [ -z "$(git config user.email)" ] && git config --global user.email "cloud-java-bot@google.com"
+ [ -z "$(git config user.name)" ] && git config --global user.name "cloud-java-bot"
+ bash .github/scripts/update_generation_config.sh \
+ --base_branch "${base_branch}" \
+ --repo ${{ github.repository }}
+ env:
+ GH_TOKEN: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }}
diff --git a/library_generation/owlbot/templates/java_library/.kokoro/build.sh b/library_generation/owlbot/templates/java_library/.kokoro/build.sh
new file mode 100755
index 0000000000..eda70322e3
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.kokoro/build.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Copyright 2018 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.
+
+set -eo pipefail
+
+cd github/synthtool
+
+# Disable buffering, so that the logs stream through.
+export PYTHONUNBUFFERED=1
+
+# Run tests
+nox -s lint test
+
+# remove all files, preventing kokoro from trying to sync them.
+rm -rf *
diff --git a/library_generation/owlbot/templates/java_library/.kokoro/common.cfg b/library_generation/owlbot/templates/java_library/.kokoro/common.cfg
new file mode 100644
index 0000000000..653d0e51ec
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.kokoro/common.cfg
@@ -0,0 +1,19 @@
+# Format: //devtools/kokoro/config/proto/build.proto
+
+# Download trampoline resources.
+gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"
+
+# Use the trampoline script to run in docker.
+build_file: "synthtool/.kokoro/trampoline.sh"
+
+# Configure the docker image for kokoro-trampoline.
+env_vars: {
+ key: "TRAMPOLINE_IMAGE"
+ value: "gcr.io/cloud-devrel-kokoro-resources/python"
+}
+
+# Tell the trampoline which build file to use.
+env_vars: {
+ key: "TRAMPOLINE_BUILD_FILE"
+ value: "github/synthtool/.kokoro/build.sh"
+}
diff --git a/library_generation/owlbot/templates/java_library/.kokoro/continuous.cfg b/library_generation/owlbot/templates/java_library/.kokoro/continuous.cfg
new file mode 100644
index 0000000000..18a4c35325
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.kokoro/continuous.cfg
@@ -0,0 +1 @@
+# Format: //devtools/kokoro/config/proto/build.proto
diff --git a/library_generation/owlbot/templates/java_library/.kokoro/presubmit.cfg b/library_generation/owlbot/templates/java_library/.kokoro/presubmit.cfg
new file mode 100644
index 0000000000..18a4c35325
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.kokoro/presubmit.cfg
@@ -0,0 +1 @@
+# Format: //devtools/kokoro/config/proto/build.proto
diff --git a/library_generation/owlbot/templates/java_library/.kokoro/trampoline.sh b/library_generation/owlbot/templates/java_library/.kokoro/trampoline.sh
new file mode 100755
index 0000000000..0efc3be388
--- /dev/null
+++ b/library_generation/owlbot/templates/java_library/.kokoro/trampoline.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+# Copyright 2017 Google Inc.
+#
+# 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
+#
+# http://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.
+set -eo pipefail
+# Always run the cleanup script, regardless of the success of bouncing into
+# the container.
+function cleanup() {
+ chmod +x ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh
+ ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh
+ echo "cleanup";
+}
+trap cleanup EXIT
+python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py"
diff --git a/library_generation/test/generate_pr_description_unit_tests.py b/library_generation/test/generate_pr_description_unit_tests.py
index 1a86770ac0..b727cc3da9 100644
--- a/library_generation/test/generate_pr_description_unit_tests.py
+++ b/library_generation/test/generate_pr_description_unit_tests.py
@@ -13,12 +13,23 @@
# limitations under the License.
import os
import unittest
+from filecmp import cmp
from library_generation.generate_pr_description import (
- get_commit_messages,
+ get_repo_level_commit_messages,
generate_pr_descriptions,
)
+from library_generation.model.config_change import (
+ ConfigChange,
+ ChangeType,
+ LibraryChange,
+)
+from library_generation.model.gapic_config import GapicConfig
from library_generation.model.generation_config import GenerationConfig
+from library_generation.model.library_config import LibraryConfig
+
+script_dir = os.path.dirname(os.path.realpath(__file__))
+resources_dir = os.path.join(script_dir, "resources", "goldens")
class GeneratePrDescriptionTest(unittest.TestCase):
@@ -30,7 +41,7 @@ def test_get_commit_messages_current_is_older_raise_exception(self):
self.assertRaisesRegex(
ValueError,
"newer than",
- get_commit_messages,
+ get_repo_level_commit_messages,
"https://github.com/googleapis/googleapis.git",
current_commit,
baseline_commit,
@@ -38,36 +49,43 @@ def test_get_commit_messages_current_is_older_raise_exception(self):
True,
)
- def test_get_commit_messages_current_and_baseline_are_same_raise_exception(self):
+ def test_get_commit_messages_with_same_current_and_baseline_returns_empty_message(
+ self,
+ ):
# committed on April 1st, 2024
current_commit = "36441693dddaf0ed73951ad3a15c215a332756aa"
baseline_commit = "36441693dddaf0ed73951ad3a15c215a332756aa"
- self.assertRaisesRegex(
- ValueError,
- "newer than",
- get_commit_messages,
- "https://github.com/googleapis/googleapis.git",
- current_commit,
- baseline_commit,
- {},
- True,
+ self.assertEqual(
+ "",
+ get_repo_level_commit_messages(
+ "https://github.com/googleapis/googleapis.git",
+ current_commit,
+ baseline_commit,
+ {},
+ True,
+ ),
)
- def test_generate_pr_description_with_same_googleapis_commits(self):
+ def test_generate_pr_description_with_no_change_in_config(self):
commit_sha = "36441693dddaf0ed73951ad3a15c215a332756aa"
- cwd = os.getcwd()
+ config = GenerationConfig(
+ gapic_generator_version="",
+ googleapis_commitish=commit_sha,
+ libraries_bom_version="",
+ # use empty libraries to make sure no qualified commit between
+ # two commit sha.
+ libraries=[],
+ )
+ pr_description_path = os.path.join(os.getcwd(), "no_config_change")
generate_pr_descriptions(
- config=GenerationConfig(
- gapic_generator_version="",
- googleapis_commitish=commit_sha,
- grpc_version="",
- protoc_version="",
- libraries=[],
+ config_change=ConfigChange(
+ change_to_libraries={},
+ baseline_config=config,
+ current_config=config,
),
- baseline_commit=commit_sha,
- description_path=cwd,
+ description_path=pr_description_path,
)
- self.assertFalse(os.path.isfile(f"{cwd}/pr_description.txt"))
+ self.assertFalse(os.path.isfile(f"{pr_description_path}/pr_description.txt"))
def test_generate_pr_description_does_not_create_pr_description_without_qualified_commit(
self,
@@ -76,19 +94,77 @@ def test_generate_pr_description_does_not_create_pr_description_without_qualifie
old_commit_sha = "30717c0b0c9966906880703208a4c820411565c4"
# committed on May 23rd, 2024
new_commit_sha = "eeed69d446a90eb4a4a2d1762c49d637075390c1"
+ pr_description_path = os.path.join(os.getcwd(), "no_qualified_commit")
+ generate_pr_descriptions(
+ config_change=ConfigChange(
+ change_to_libraries={},
+ baseline_config=GenerationConfig(
+ gapic_generator_version="",
+ googleapis_commitish=old_commit_sha,
+ # use empty libraries to make sure no qualified commit between
+ # two commit sha.
+ libraries=[],
+ ),
+ current_config=GenerationConfig(
+ gapic_generator_version="",
+ googleapis_commitish=new_commit_sha,
+ # use empty libraries to make sure no qualified commit between
+ # two commit sha.
+ libraries=[],
+ ),
+ ),
+ description_path=pr_description_path,
+ )
+ self.assertFalse(os.path.isfile(f"{pr_description_path}/pr_description.txt"))
+
+ def test_generate_pr_description_with_combined_message(
+ self,
+ ):
+ # no other commits between these two commits.
+ baseline_commit_sha = "3b6f144d47b0a1d2115ab2445ec06e80cc324a44"
+ documentai_commit_sha = "0cea7170404bec3d994f43db4fa292f5034cbe9a"
cwd = os.getcwd()
+ library = LibraryConfig(
+ api_shortname="documentai",
+ api_description="",
+ name_pretty="",
+ product_documentation="",
+ gapic_configs=[GapicConfig(proto_path="google/cloud/documentai/v1")],
+ )
generate_pr_descriptions(
- config=GenerationConfig(
- gapic_generator_version="",
- googleapis_commitish=new_commit_sha,
- libraries_bom_version="",
- grpc_version="",
- protoc_version="",
- # use empty libraries to make sure no qualified commit between
- # two commit sha.
- libraries=[],
+ config_change=ConfigChange(
+ change_to_libraries={
+ ChangeType.REPO_LEVEL_CHANGE: [
+ LibraryChange(
+ changed_param="gapic_generator_version",
+ current_value="1.2.3",
+ ),
+ LibraryChange(
+ changed_param="libraries_bom_version", current_value="2.3.4"
+ ),
+ ],
+ ChangeType.GOOGLEAPIS_COMMIT: [],
+ },
+ baseline_config=GenerationConfig(
+ gapic_generator_version="",
+ googleapis_commitish=baseline_commit_sha,
+ libraries=[library],
+ ),
+ current_config=GenerationConfig(
+ gapic_generator_version="1.2.3",
+ googleapis_commitish=documentai_commit_sha,
+ libraries_bom_version="2.3.4",
+ libraries=[library],
+ ),
),
- baseline_commit=old_commit_sha,
description_path=cwd,
)
- self.assertFalse(os.path.isfile(f"{cwd}/pr_description.txt"))
+ self.assertTrue(os.path.isfile(f"{cwd}/pr_description.txt"))
+ self.assertTrue(
+ cmp(
+ f"{resources_dir}/pr_description-golden.txt",
+ f"{cwd}/pr_description.txt",
+ ),
+ "The generated PR description does not match the expected golden file",
+ )
+ os.remove(f"{cwd}/pr_description.txt")
diff --git a/library_generation/test/model/gapic_config_unit_tests.py b/library_generation/test/model/gapic_config_unit_tests.py
new file mode 100644
index 0000000000..64d8556648
--- /dev/null
+++ b/library_generation/test/model/gapic_config_unit_tests.py
@@ -0,0 +1,122 @@
+# Copyright 2024 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.
+import unittest
+
+from library_generation.model.gapic_config import GapicConfig
+
+
+class GapicConfigTest(unittest.TestCase):
+ def test_get_version_returns_none(self):
+ self.assertIsNone(GapicConfig(proto_path="example/dir1/dir2").get_version())
+
+ def test_get_version_returns_non_stable_version(self):
+ self.assertEqual(
+ "v2p2beta1",
+ GapicConfig(proto_path="example/dir1/dir2/v2p2beta1").get_version(),
+ )
+ self.assertEqual(
+ "v2beta1",
+ GapicConfig(proto_path="example/dir1/dir2/v2beta1").get_version(),
+ )
+
+ def test_get_version_returns_stable_version(self):
+ self.assertEqual(
+ "v20",
+ GapicConfig(proto_path="example/dir1/dir2/v20").get_version(),
+ )
+
+ def test_is_stable_with_no_version_returns_false(self):
+ self.assertFalse(
+ GapicConfig(proto_path="example/dir1/dir2/non_version").is_stable(),
+ )
+
+ def test_is_stable_with_non_stable_version_returns_false(self):
+ self.assertFalse(
+ GapicConfig(proto_path="example/dir1/dir2/v20alpha").is_stable(),
+ )
+ self.assertFalse(
+ GapicConfig(proto_path="example/dir1/dir2/v20beta2").is_stable(),
+ )
+
+ def test_is_stable_with_stable_version_returns_true(self):
+ self.assertTrue(
+ GapicConfig(proto_path="example/dir1/dir2/v30").is_stable(),
+ )
+
+ def test_compare_configs_without_a_version(self):
+ config_len_3 = GapicConfig(proto_path="example/dir1/dir2")
+ config_len_4 = GapicConfig(proto_path="example/dir1/dir2/dir3")
+ self.assertLess(
+ config_len_3,
+ config_len_4,
+ "config_len_3 should be smaller since it has a lower depth.",
+ )
+
+ def test_compare_configs_only_one_has_a_stable_version(self):
+ versioned_config = GapicConfig(proto_path="example/dir1/dir2/dir3/dir4/v1")
+ non_versioned_config = GapicConfig(proto_path="example/dir1/dir2/dir3")
+ self.assertLess(
+ versioned_config,
+ non_versioned_config,
+ "versioned_config should be smaller since it has a version.",
+ )
+
+ def test_compare_configs_only_one_has_a_non_stable_version(self):
+ non_stable_versioned_config = GapicConfig(
+ proto_path="example/dir1/dir2/dir3/dir4/v1beta"
+ )
+ non_versioned_config = GapicConfig(proto_path="example/dir1/dir2/dir3")
+ self.assertLess(
+ non_stable_versioned_config,
+ non_versioned_config,
+ "non_stable_versioned_config should be smaller since it has a version.",
+ )
+
+ def test_compare_configs_one_has_non_stable_and_one_has_stable_version(self):
+ stable_versioned_config = GapicConfig(
+ proto_path="example/dir1/dir2/dir3/dir4/v1"
+ )
+ non_stable_versioned_config = GapicConfig(proto_path="example/dir1/dir2/v2beta")
+ self.assertLess(
+ stable_versioned_config,
+ non_stable_versioned_config,
+ "stable_versioned_config should be smaller since it has a stable version.",
+ )
+
+ def test_compare_configs_two_have_non_stable_version(self):
+ v3p2beta = GapicConfig(proto_path="example/dir1/dir2/dir3/dir4/v3p2beta")
+ v2p4beta = GapicConfig(proto_path="example/dir1/dir2/v2p4beta")
+ self.assertLess(
+ v3p2beta,
+ v2p4beta,
+ "v3p2beta should be smaller since it has a higher version.",
+ )
+
+ def test_compare_configs_two_have_stable_version_different_depth(self):
+ v3 = GapicConfig(proto_path="example/dir1/dir2/v3")
+ v4 = GapicConfig(proto_path="example/dir1/dir2/dir3/dir4/v4")
+ self.assertLess(
+ v3,
+ v4,
+ "v3 should be smaller since it has lower depth",
+ )
+
+ def test_compare_configs_two_have_stable_version_same_depth(self):
+ v4 = GapicConfig(proto_path="example/dir1/dir2/v4")
+ v3 = GapicConfig(proto_path="example/dir1/dir2/v3")
+ self.assertLess(
+ v4,
+ v3,
+ "v4 should be smaller since it has a higher version",
+ )
diff --git a/library_generation/test/model/library_config_unit_tests.py b/library_generation/test/model/library_config_unit_tests.py
index 1c0b0d0690..35ba5be3e4 100644
--- a/library_generation/test/model/library_config_unit_tests.py
+++ b/library_generation/test/model/library_config_unit_tests.py
@@ -13,6 +13,7 @@
# limitations under the License.
import unittest
+from library_generation.model.gapic_config import GapicConfig
from library_generation.model.library_config import LibraryConfig
@@ -37,3 +38,29 @@ def test_get_library_returns_api_shortname(self):
gapic_configs=list(),
)
self.assertEqual("secret", library.get_library_name())
+
+ def test_get_sorted_gapic_configs_returns_correct_order(self):
+ v1beta1 = GapicConfig(proto_path="google/spanner/v1beta1")
+ v1 = GapicConfig(proto_path="google/spanner/v1")
+ v1alpha1 = GapicConfig(proto_path="google/spanner/v1alpha")
+ v2 = GapicConfig(proto_path="google/spanner/v2")
+ admin_v2 = GapicConfig(proto_path="google/spanner/admin/v2")
+ non_versioned = GapicConfig(proto_path="google/spanner/type")
+ library = LibraryConfig(
+ api_shortname="secret",
+ name_pretty="",
+ product_documentation="",
+ api_description="",
+ gapic_configs=[v1alpha1, v1, v2, admin_v2, non_versioned, v1beta1],
+ )
+ self.assertEqual(
+ [
+ v2,
+ v1,
+ admin_v2,
+ v1beta1,
+ v1alpha1,
+ non_versioned,
+ ],
+ library.get_sorted_gapic_configs(),
+ )
diff --git a/library_generation/test/resources/goldens/.repo-metadata-monorepo-golden.json b/library_generation/test/resources/goldens/.repo-metadata-monorepo-golden.json
index 88ee68b2e1..0b3bbc2b55 100644
--- a/library_generation/test/resources/goldens/.repo-metadata-monorepo-golden.json
+++ b/library_generation/test/resources/goldens/.repo-metadata-monorepo-golden.json
@@ -14,5 +14,7 @@
"library_type": "GAPIC_AUTO",
"requires_billing": true,
"rest_documentation": "https://cloud.google.com/bare-metal/docs/reference/rest",
- "rpc_documentation": "https://cloud.google.com/bare-metal/docs/reference/rpc"
+ "rpc_documentation": "https://cloud.google.com/bare-metal/docs/reference/rpc",
+ "recommended_package": "com.google.example",
+ "min_java_version": 8
}
\ No newline at end of file
diff --git a/library_generation/test/resources/goldens/.repo-metadata-non-monorepo-golden.json b/library_generation/test/resources/goldens/.repo-metadata-non-monorepo-golden.json
index 9e4a878d67..b39c297a85 100644
--- a/library_generation/test/resources/goldens/.repo-metadata-non-monorepo-golden.json
+++ b/library_generation/test/resources/goldens/.repo-metadata-non-monorepo-golden.json
@@ -15,5 +15,7 @@
"requires_billing": true,
"rest_documentation": "https://cloud.google.com/bare-metal/docs/reference/rest",
"rpc_documentation": "https://cloud.google.com/bare-metal/docs/reference/rpc",
- "extra_versioned_modules": "test-module"
+ "extra_versioned_modules": "test-module",
+ "recommended_package": "com.google.example",
+ "min_java_version": 8
}
\ No newline at end of file
diff --git a/library_generation/test/resources/goldens/.repo-metadata-proto-only-golden.json b/library_generation/test/resources/goldens/.repo-metadata-proto-only-golden.json
index 995607bae4..7730cd6987 100644
--- a/library_generation/test/resources/goldens/.repo-metadata-proto-only-golden.json
+++ b/library_generation/test/resources/goldens/.repo-metadata-proto-only-golden.json
@@ -13,5 +13,7 @@
"library_type": "OTHER",
"requires_billing": true,
"rest_documentation": "https://cloud.google.com/bare-metal/docs/reference/rest",
- "rpc_documentation": "https://cloud.google.com/bare-metal/docs/reference/rpc"
+ "rpc_documentation": "https://cloud.google.com/bare-metal/docs/reference/rpc",
+ "recommended_package": "com.google.example",
+ "min_java_version": 8
}
\ No newline at end of file
diff --git a/library_generation/test/resources/goldens/pr_description-golden.txt b/library_generation/test/resources/goldens/pr_description-golden.txt
new file mode 100644
index 0000000000..1a0f874936
--- /dev/null
+++ b/library_generation/test/resources/goldens/pr_description-golden.txt
@@ -0,0 +1,17 @@
+This pull request is generated with proto changes between [googleapis/googleapis@3b6f144](https://github.com/googleapis/googleapis/commit/3b6f144d47b0a1d2115ab2445ec06e80cc324a44) (exclusive) and [googleapis/googleapis@0cea717](https://github.com/googleapis/googleapis/commit/0cea7170404bec3d994f43db4fa292f5034cbe9a) (inclusive).
+
+BEGIN_COMMIT_OVERRIDE
+BEGIN_NESTED_COMMIT
+fix(deps): update the Java code generator (gapic-generator-java) to 1.2.3
+END_NESTED_COMMIT
+BEGIN_NESTED_COMMIT
+chore: update the libraries_bom version to 2.3.4
+END_NESTED_COMMIT
+BEGIN_NESTED_COMMIT
+feat: Make Layout Parser generally available in V1
+
+PiperOrigin-RevId: 638924855
+
+Source Link: [googleapis/googleapis@0cea717](https://github.com/googleapis/googleapis/commit/0cea7170404bec3d994f43db4fa292f5034cbe9a)
+END_NESTED_COMMIT
+END_COMMIT_OVERRIDE
\ No newline at end of file
diff --git a/library_generation/test/utilities_unit_tests.py b/library_generation/test/utilities_unit_tests.py
index 1d522114cc..c38016fcba 100644
--- a/library_generation/test/utilities_unit_tests.py
+++ b/library_generation/test/utilities_unit_tests.py
@@ -40,6 +40,8 @@
library_name="bare-metal-solution",
rest_documentation="https://cloud.google.com/bare-metal/docs/reference/rest",
rpc_documentation="https://cloud.google.com/bare-metal/docs/reference/rpc",
+ recommended_package="com.google.example",
+ min_java_version=8,
)
library_2 = LibraryConfig(
api_shortname="secretmanager",
@@ -167,8 +169,8 @@ def test_eprint_valid_input_succeeds(self):
# print() appends a `\n` each time it's called
self.assertEqual(test_input + "\n", result)
- def test_generate_prerequisite_files_non_monorepo_success(self):
- library_path = self.__setup_prerequisite_files(
+ def test_generate_postprocessing_prerequisite_files_non_monorepo_success(self):
+ library_path = self.__setup_postprocessing_prerequisite_files(
combination=1, library_type="GAPIC_COMBO"
)
@@ -185,10 +187,12 @@ def test_generate_prerequisite_files_non_monorepo_success(self):
file_comparator.compare_files(
f"{library_path}/owlbot.py", f"{library_path}/owlbot-golden.py"
)
- self.__remove_prerequisite_files(path=library_path, is_monorepo=False)
+ self.__remove_postprocessing_prerequisite_files(
+ path=library_path, is_monorepo=False
+ )
- def test_generate_prerequisite_files_monorepo_success(self):
- library_path = self.__setup_prerequisite_files(combination=2)
+ def test_generate_postprocessing_prerequisite_files_monorepo_success(self):
+ library_path = self.__setup_postprocessing_prerequisite_files(combination=2)
file_comparator.compare_files(
f"{library_path}/.repo-metadata.json",
@@ -201,10 +205,10 @@ def test_generate_prerequisite_files_monorepo_success(self):
file_comparator.compare_files(
f"{library_path}/owlbot.py", f"{library_path}/owlbot-golden.py"
)
- self.__remove_prerequisite_files(path=library_path)
+ self.__remove_postprocessing_prerequisite_files(path=library_path)
- def test_generate_prerequisite_files_proto_only_repo_success(self):
- library_path = self.__setup_prerequisite_files(
+ def test_generate_postprocessing_prerequisite_files_proto_only_repo_success(self):
+ library_path = self.__setup_postprocessing_prerequisite_files(
combination=3, library_type="OTHER"
)
@@ -219,7 +223,7 @@ def test_generate_prerequisite_files_proto_only_repo_success(self):
file_comparator.compare_files(
f"{library_path}/owlbot.py", f"{library_path}/owlbot-golden.py"
)
- self.__remove_prerequisite_files(path=library_path)
+ self.__remove_postprocessing_prerequisite_files(path=library_path)
def test_prepare_repo_monorepo_success(self):
gen_config = self.__get_a_gen_config(2)
@@ -256,7 +260,7 @@ def test_prepare_repo_split_repo_success(self):
self.assertEqual(["misc"], library_path)
shutil.rmtree(repo_config.output_folder)
- def __setup_prerequisite_files(
+ def __setup_postprocessing_prerequisite_files(
self,
combination: int,
library_type: str = "GAPIC_AUTO",
@@ -273,7 +277,7 @@ def __setup_prerequisite_files(
config = self.__get_a_gen_config(combination, library_type=library_type)
proto_path = "google/cloud/baremetalsolution/v2"
transport = "grpc"
- util.generate_prerequisite_files(
+ util.generate_postprocessing_prerequisite_files(
config=config,
library=library,
proto_path=proto_path,
@@ -319,7 +323,9 @@ def __get_a_gen_config(
)
@staticmethod
- def __remove_prerequisite_files(path: str, is_monorepo: bool = True) -> None:
+ def __remove_postprocessing_prerequisite_files(
+ path: str, is_monorepo: bool = True
+ ) -> None:
os.remove(f"{path}/.repo-metadata.json")
os.remove(f"{path}/owlbot.py")
if is_monorepo:
diff --git a/library_generation/test/utils/commit_message_formatter_unit_tests.py b/library_generation/test/utils/commit_message_formatter_unit_tests.py
index 0148214dfb..16e3fffdfc 100644
--- a/library_generation/test/utils/commit_message_formatter_unit_tests.py
+++ b/library_generation/test/utils/commit_message_formatter_unit_tests.py
@@ -14,13 +14,24 @@
import unittest
from unittest.mock import patch
+from library_generation.model.config_change import (
+ ConfigChange,
+ ChangeType,
+ LibraryChange,
+)
+from library_generation.model.generation_config import GenerationConfig
from library_generation.utils.commit_message_formatter import (
format_commit_message,
commit_link,
+ format_repo_level_change,
)
-from library_generation.utils.commit_message_formatter import wrap_nested_commit
+from library_generation.utils.commit_message_formatter import wrap_googleapis_commit
from library_generation.utils.commit_message_formatter import wrap_override_commit
+gen_config = GenerationConfig(
+ gapic_generator_version="1.2.3", googleapis_commitish="123abc", libraries=[]
+)
+
class CommitMessageFormatterTest(unittest.TestCase):
def test_format_commit_message_should_add_library_name_for_conventional_commit(
@@ -130,7 +141,7 @@ def test_wrap_nested_commit_success(self):
"Source Link: [googleapis/googleapis@1234567](https://github.com/googleapis/googleapis/commit/1234567abcdefg)",
"END_NESTED_COMMIT",
],
- wrap_nested_commit(commit, messages),
+ wrap_googleapis_commit(commit, messages),
)
def test_wrap_override_commit_success(self):
@@ -153,3 +164,36 @@ def test_commit_link_success(self):
"[googleapis/googleapis@1234567](https://github.com/googleapis/googleapis/commit/1234567abcdefg)",
commit_link(commit),
)
+
+ def test_format_repo_level_change_success(self):
+ config_change = ConfigChange(
+ change_to_libraries={
+ ChangeType.REPO_LEVEL_CHANGE: [
+ LibraryChange(
+ changed_param="gapic_generator_version", current_value="1.2.3"
+ ),
+ LibraryChange(
+ changed_param="libraries_bom_version", current_value="2.3.4"
+ ),
+ LibraryChange(
+ changed_param="protoc_version", current_value="3.4.5"
+ ),
+ ]
+ },
+ baseline_config=gen_config,
+ current_config=gen_config,
+ )
+ self.assertEqual(
+ [
+ "BEGIN_NESTED_COMMIT",
+ "fix(deps): update the Java code generator (gapic-generator-java) to 1.2.3",
+ "END_NESTED_COMMIT",
+ "BEGIN_NESTED_COMMIT",
+ "chore: update the libraries_bom version to 2.3.4",
+ "END_NESTED_COMMIT",
+ "BEGIN_NESTED_COMMIT",
+ "chore: update repo-level parameter protoc_version to 3.4.5",
+ "END_NESTED_COMMIT",
+ ],
+ format_repo_level_change(config_change),
+ )
diff --git a/library_generation/utils/commit_message_formatter.py b/library_generation/utils/commit_message_formatter.py
index 85bfbc8036..5b75db51a0 100644
--- a/library_generation/utils/commit_message_formatter.py
+++ b/library_generation/utils/commit_message_formatter.py
@@ -12,12 +12,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import re
-from typing import List
-from typing import Dict
from git import Commit
+from library_generation.model.config_change import ConfigChange, ChangeType
+from library_generation.model.generation_config import (
+ GAPIC_GENERATOR_VERSION,
+ LIBRARIES_BOM_VERSION,
+)
-def format_commit_message(commits: Dict[Commit, str], is_monorepo: bool) -> List[str]:
+PARAM_TO_COMMIT_MESSAGE = {
+ GAPIC_GENERATOR_VERSION: "fix(deps): update the Java code generator (gapic-generator-java) to",
+ LIBRARIES_BOM_VERSION: "chore: update the libraries_bom version to",
+}
+
+
+def format_commit_message(commits: dict[Commit, str], is_monorepo: bool) -> list[str]:
"""
Format commit messages. Add library_name to conventional commit messages if
is_monorepo is True; otherwise no op.
@@ -47,11 +56,29 @@ def format_commit_message(commits: Dict[Commit, str], is_monorepo: bool) -> List
messages.append(formatted_message)
else:
messages.append(message_line)
- all_commits.extend(wrap_nested_commit(commit, messages))
+ all_commits.extend(wrap_googleapis_commit(commit, messages))
return all_commits
-def wrap_nested_commit(commit: Commit, messages: List[str]) -> List[str]:
+def format_repo_level_change(config_change: ConfigChange) -> list[str]:
+ """
+ Format commit messages regarding repo-level changes.
+
+ :param config_change:
+ :return: commit messages regarding repo-level changes.
+ """
+ messages = []
+ for repo_level_change in config_change.change_to_libraries.get(
+ ChangeType.REPO_LEVEL_CHANGE, []
+ ):
+ message = f"chore: update repo-level parameter {repo_level_change.changed_param} to {repo_level_change.current_value}"
+ if repo_level_change.changed_param in PARAM_TO_COMMIT_MESSAGE:
+ message = f"{PARAM_TO_COMMIT_MESSAGE.get(repo_level_change.changed_param)} {repo_level_change.current_value}"
+ messages.extend(__wrap_nested_commit([message]))
+ return messages
+
+
+def wrap_googleapis_commit(commit: Commit, messages: list[str]) -> list[str]:
"""
Wrap message between `BEGIN_NESTED_COMMIT` and `BEGIN_NESTED_COMMIT`.
@@ -59,14 +86,11 @@ def wrap_nested_commit(commit: Commit, messages: List[str]) -> List[str]:
:param messages: a (multi-line) commit message, one line per item.
:return: wrapped messages.
"""
- result = ["BEGIN_NESTED_COMMIT"]
- result.extend(messages)
- result.append(f"Source Link: {commit_link(commit)}")
- result.append("END_NESTED_COMMIT")
- return result
+ messages.append(f"Source Link: {commit_link(commit)}")
+ return __wrap_nested_commit(messages)
-def wrap_override_commit(messages: List[str]) -> List[str]:
+def wrap_override_commit(messages: list[str]) -> list[str]:
"""
Wrap message between `BEGIN_COMMIT_OVERRIDE` and `END_COMMIT_OVERRIDE`.
@@ -88,3 +112,16 @@ def commit_link(commit: Commit) -> str:
"""
short_sha = commit.hexsha[:7]
return f"[googleapis/googleapis@{short_sha}](https://github.com/googleapis/googleapis/commit/{commit.hexsha})"
+
+
+def __wrap_nested_commit(messages: list[str]) -> list[str]:
+ """
+ Wrap message between `BEGIN_NESTED_COMMIT` and `BEGIN_NESTED_COMMIT`.
+
+ :param messages: a (multi-line) commit message, one line per item.
+ :return: wrapped messages.
+ """
+ result = ["BEGIN_NESTED_COMMIT"]
+ result.extend(messages)
+ result.append("END_NESTED_COMMIT")
+ return result
diff --git a/library_generation/utils/utilities.py b/library_generation/utils/utilities.py
index f21c35bf0e..0490ad9e2a 100755
--- a/library_generation/utils/utilities.py
+++ b/library_generation/utils/utilities.py
@@ -183,7 +183,7 @@ def pull_api_definition(
)
-def generate_prerequisite_files(
+def generate_postprocessing_prerequisite_files(
config: GenerationConfig,
library: LibraryConfig,
proto_path: str,
@@ -192,14 +192,13 @@ def generate_prerequisite_files(
language: str = "java",
) -> None:
"""
- Generate prerequisite files for a library.
-
- Note that the version, if any, in the proto_path will be removed.
+ Generates the postprocessing prerequisite files for a library.
:param config: a GenerationConfig object representing a parsed configuration
yaml
:param library: the library configuration
- :param proto_path: the proto path
+ :param proto_path: the path from the root of googleapis to the location of the service
+ protos. If the path contains a version, it will be removed
:param transport: transport supported by the library
:param library_path: the path to which the generated file goes
:param language: programming language of the library
@@ -275,6 +274,10 @@ def generate_prerequisite_files(
repo_metadata["rpc_documentation"] = library.rpc_documentation
if library.extra_versioned_modules:
repo_metadata["extra_versioned_modules"] = library.extra_versioned_modules
+ if library.recommended_package:
+ repo_metadata["recommended_package"] = library.recommended_package
+ if library.min_java_version:
+ repo_metadata["min_java_version"] = library.min_java_version
# generate .repo-meta.json
json_file = ".repo-metadata.json"
diff --git a/sdk-platform-java-config/pom.xml b/sdk-platform-java-config/pom.xml
index aa4a2fabb9..cfa568e7ff 100644
--- a/sdk-platform-java-config/pom.xml
+++ b/sdk-platform-java-config/pom.xml
@@ -4,7 +4,7 @@
com.google.cloud
sdk-platform-java-config
pom
- 3.31.0
+ 3.32.0
SDK Platform For Java Configurations
Shared build configuration for Google Cloud Java libraries.
@@ -13,10 +13,10 @@
com.google.cloud
google-cloud-shared-config
- 1.8.0
+ 1.8.1
- 3.31.0
+ 3.32.0
\ No newline at end of file
diff --git a/showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelMetrics.java b/showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelMetrics.java
index c2ecff034d..55b07a851b 100644
--- a/showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelMetrics.java
+++ b/showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelMetrics.java
@@ -35,6 +35,7 @@
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.core.ApiFuture;
import com.google.api.gax.core.NoCredentialsProvider;
+import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
import com.google.api.gax.retrying.RetrySettings;
import com.google.api.gax.rpc.InvalidArgumentException;
import com.google.api.gax.rpc.StatusCode.Code;
@@ -69,7 +70,9 @@
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.data.PointData;
import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader;
+import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -100,7 +103,7 @@ class ITOtelMetrics {
private static final String OPERATION_COUNT = SERVICE_NAME + "/operation_count";
private static final String ATTEMPT_LATENCY = SERVICE_NAME + "/attempt_latency";
private static final String OPERATION_LATENCY = SERVICE_NAME + "/operation_latency";
- private static final int NUM_METRICS = 4;
+ private static final int NUM_DEFAULT_METRICS = 4;
private static final int NUM_COLLECTION_FLUSH_ATTEMPTS = 10;
private InMemoryMetricReader inMemoryMetricReader;
private EchoClient grpcClient;
@@ -272,16 +275,22 @@ private void verifyStatusAttribute(
}
}
+ /** Uses the default InMemoryMetricReader configured for showcase tests. */
+ private List getMetricDataList() throws InterruptedException {
+ return getMetricDataList(inMemoryMetricReader);
+ }
+
/**
- * Attempts to retrieve the metrics from the InMemoryMetricsReader. Sleep every second for at most
- * 10s to try and retrieve all the metrics available. If it is unable to retrieve all the metrics,
- * fail the test.
+ * Attempts to retrieve the metrics from a custom InMemoryMetricsReader. Sleep every second for at
+ * most 10s to try and retrieve all the metrics available. If it is unable to retrieve all the
+ * metrics, fail the test.
*/
- private List getMetricDataList() throws InterruptedException {
+ private List getMetricDataList(InMemoryMetricReader metricReader)
+ throws InterruptedException {
for (int i = 0; i < NUM_COLLECTION_FLUSH_ATTEMPTS; i++) {
Thread.sleep(1000L);
- List metricData = new ArrayList<>(inMemoryMetricReader.collectAllMetrics());
- if (metricData.size() == NUM_METRICS) {
+ List metricData = new ArrayList<>(metricReader.collectAllMetrics());
+ if (metricData.size() == NUM_DEFAULT_METRICS) {
return metricData;
}
}
@@ -296,19 +305,19 @@ void testGrpc_operationSucceeded_recordsMetrics() throws InterruptedException {
EchoRequest.newBuilder().setContent("test_grpc_operation_succeeded").build();
grpcClient.echo(echoRequest);
- List metricDataList = getMetricDataList();
- verifyPointDataSum(metricDataList, attemptCount);
+ List actualMetricDataList = getMetricDataList();
+ verifyPointDataSum(actualMetricDataList, attemptCount);
- Map attributeMapping =
+ Map expectedAttributes =
ImmutableMap.of(
- MetricsTracer.METHOD_NAME_ATTRIBUTE,
+ MetricsTracer.METHOD_ATTRIBUTE,
"Echo.Echo",
MetricsTracer.LANGUAGE_ATTRIBUTE,
MetricsTracer.DEFAULT_LANGUAGE);
- verifyDefaultMetricsAttributes(metricDataList, attributeMapping);
+ verifyDefaultMetricsAttributes(actualMetricDataList, expectedAttributes);
List statusCountList = ImmutableList.of(new StatusCount(Code.OK));
- verifyStatusAttribute(metricDataList, statusCountList);
+ verifyStatusAttribute(actualMetricDataList, statusCountList);
}
@Disabled("https://github.com/googleapis/sdk-platform-java/issues/2503")
@@ -319,19 +328,19 @@ void testHttpJson_operationSucceeded_recordsMetrics() throws InterruptedExceptio
EchoRequest.newBuilder().setContent("test_http_operation_succeeded").build();
httpClient.echo(echoRequest);
- List metricDataList = getMetricDataList();
- verifyPointDataSum(metricDataList, attemptCount);
+ List actualMetricDataList = getMetricDataList();
+ verifyPointDataSum(actualMetricDataList, attemptCount);
- Map attributeMapping =
+ Map expectedAttributes =
ImmutableMap.of(
- MetricsTracer.METHOD_NAME_ATTRIBUTE,
+ MetricsTracer.METHOD_ATTRIBUTE,
"google.showcase.v1beta1.Echo/Echo",
MetricsTracer.LANGUAGE_ATTRIBUTE,
MetricsTracer.DEFAULT_LANGUAGE);
- verifyDefaultMetricsAttributes(metricDataList, attributeMapping);
+ verifyDefaultMetricsAttributes(actualMetricDataList, expectedAttributes);
List statusCountList = ImmutableList.of(new StatusCount(Code.OK));
- verifyStatusAttribute(metricDataList, statusCountList);
+ verifyStatusAttribute(actualMetricDataList, statusCountList);
}
@Test
@@ -349,19 +358,19 @@ void testGrpc_operationCancelled_recordsMetrics() throws Exception {
Thread.sleep(1000);
blockResponseApiFuture.cancel(true);
- List metricDataList = getMetricDataList();
- verifyPointDataSum(metricDataList, attemptCount);
+ List actualMetricDataList = getMetricDataList();
+ verifyPointDataSum(actualMetricDataList, attemptCount);
- Map attributeMapping =
+ Map expectedAttributes =
ImmutableMap.of(
- MetricsTracer.METHOD_NAME_ATTRIBUTE,
+ MetricsTracer.METHOD_ATTRIBUTE,
"Echo.Block",
MetricsTracer.LANGUAGE_ATTRIBUTE,
MetricsTracer.DEFAULT_LANGUAGE);
- verifyDefaultMetricsAttributes(metricDataList, attributeMapping);
+ verifyDefaultMetricsAttributes(actualMetricDataList, expectedAttributes);
List statusCountList = ImmutableList.of(new StatusCount(Code.CANCELLED));
- verifyStatusAttribute(metricDataList, statusCountList);
+ verifyStatusAttribute(actualMetricDataList, statusCountList);
}
@Disabled("https://github.com/googleapis/sdk-platform-java/issues/2503")
@@ -377,19 +386,19 @@ void testHttpJson_operationCancelled_recordsMetrics() throws Exception {
Thread.sleep(1000);
blockResponseApiFuture.cancel(true);
- List metricDataList = getMetricDataList();
- verifyPointDataSum(metricDataList, attemptCount);
+ List actualMetricDataList = getMetricDataList();
+ verifyPointDataSum(actualMetricDataList, attemptCount);
- Map attributeMapping =
+ Map expectedAttributes =
ImmutableMap.of(
- MetricsTracer.METHOD_NAME_ATTRIBUTE,
+ MetricsTracer.METHOD_ATTRIBUTE,
"google.showcase.v1beta1.Echo/Block",
MetricsTracer.LANGUAGE_ATTRIBUTE,
MetricsTracer.DEFAULT_LANGUAGE);
- verifyDefaultMetricsAttributes(metricDataList, attributeMapping);
+ verifyDefaultMetricsAttributes(actualMetricDataList, expectedAttributes);
List statusCountList = ImmutableList.of(new StatusCount(Code.CANCELLED));
- verifyStatusAttribute(metricDataList, statusCountList);
+ verifyStatusAttribute(actualMetricDataList, statusCountList);
}
@Test
@@ -406,19 +415,19 @@ void testGrpc_operationFailed_recordsMetrics() throws InterruptedException {
ApiFuture blockResponseApiFuture = blockCallable.futureCall(blockRequest);
assertThrows(ExecutionException.class, blockResponseApiFuture::get);
- List metricDataList = getMetricDataList();
- verifyPointDataSum(metricDataList, attemptCount);
+ List actualMetricDataList = getMetricDataList();
+ verifyPointDataSum(actualMetricDataList, attemptCount);
- Map attributeMapping =
+ Map expectedAttributes =
ImmutableMap.of(
- MetricsTracer.METHOD_NAME_ATTRIBUTE,
+ MetricsTracer.METHOD_ATTRIBUTE,
"Echo.Block",
MetricsTracer.LANGUAGE_ATTRIBUTE,
MetricsTracer.DEFAULT_LANGUAGE);
- verifyDefaultMetricsAttributes(metricDataList, attributeMapping);
+ verifyDefaultMetricsAttributes(actualMetricDataList, expectedAttributes);
List statusCountList = ImmutableList.of(new StatusCount(statusCode));
- verifyStatusAttribute(metricDataList, statusCountList);
+ verifyStatusAttribute(actualMetricDataList, statusCountList);
}
@Disabled("https://github.com/googleapis/sdk-platform-java/issues/2503")
@@ -436,19 +445,19 @@ void testHttpJson_operationFailed_recordsMetrics() throws InterruptedException {
ApiFuture blockResponseApiFuture = blockCallable.futureCall(blockRequest);
assertThrows(ExecutionException.class, blockResponseApiFuture::get);
- List metricDataList = getMetricDataList();
- verifyPointDataSum(metricDataList, attemptCount);
+ List actualMetricDataList = getMetricDataList();
+ verifyPointDataSum(actualMetricDataList, attemptCount);
- Map attributeMapping =
+ Map expectedAttributes =
ImmutableMap.of(
- MetricsTracer.METHOD_NAME_ATTRIBUTE,
+ MetricsTracer.METHOD_ATTRIBUTE,
"google.showcase.v1beta1.Echo/Block",
MetricsTracer.LANGUAGE_ATTRIBUTE,
MetricsTracer.DEFAULT_LANGUAGE);
- verifyDefaultMetricsAttributes(metricDataList, attributeMapping);
+ verifyDefaultMetricsAttributes(actualMetricDataList, expectedAttributes);
List statusCountList = ImmutableList.of(new StatusCount(statusCode));
- verifyStatusAttribute(metricDataList, statusCountList);
+ verifyStatusAttribute(actualMetricDataList, statusCountList);
}
@Test
@@ -499,19 +508,19 @@ void testGrpc_attemptFailedRetriesExhausted_recordsMetrics() throws Exception {
assertThrows(UnavailableException.class, () -> grpcClient.echo(echoRequest));
- List metricDataList = getMetricDataList();
- verifyPointDataSum(metricDataList, attemptCount);
+ List actualMetricDataList = getMetricDataList();
+ verifyPointDataSum(actualMetricDataList, attemptCount);
- Map attributeMapping =
+ Map expectedAttributes =
ImmutableMap.of(
- MetricsTracer.METHOD_NAME_ATTRIBUTE,
+ MetricsTracer.METHOD_ATTRIBUTE,
"Echo.Echo",
MetricsTracer.LANGUAGE_ATTRIBUTE,
MetricsTracer.DEFAULT_LANGUAGE);
- verifyDefaultMetricsAttributes(metricDataList, attributeMapping);
+ verifyDefaultMetricsAttributes(actualMetricDataList, expectedAttributes);
List statusCountList = ImmutableList.of(new StatusCount(statusCode, 3));
- verifyStatusAttribute(metricDataList, statusCountList);
+ verifyStatusAttribute(actualMetricDataList, statusCountList);
grpcClient.close();
grpcClient.awaitTermination(TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS);
@@ -567,19 +576,19 @@ void testHttpJson_attemptFailedRetriesExhausted_recordsMetrics() throws Exceptio
assertThrows(UnavailableException.class, () -> httpClient.echo(echoRequest));
- List metricDataList = getMetricDataList();
- verifyPointDataSum(metricDataList, attemptCount);
+ List actualMetricDataList = getMetricDataList();
+ verifyPointDataSum(actualMetricDataList, attemptCount);
- Map attributeMapping =
+ Map expectedAttributes =
ImmutableMap.of(
- MetricsTracer.METHOD_NAME_ATTRIBUTE,
+ MetricsTracer.METHOD_ATTRIBUTE,
"google.showcase.v1beta1.Echo/Echo",
MetricsTracer.LANGUAGE_ATTRIBUTE,
MetricsTracer.DEFAULT_LANGUAGE);
- verifyDefaultMetricsAttributes(metricDataList, attributeMapping);
+ verifyDefaultMetricsAttributes(actualMetricDataList, expectedAttributes);
List statusCountList = ImmutableList.of(new StatusCount(statusCode, 3));
- verifyStatusAttribute(metricDataList, statusCountList);
+ verifyStatusAttribute(actualMetricDataList, statusCountList);
httpClient.close();
httpClient.awaitTermination(TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS);
@@ -597,19 +606,19 @@ void testGrpc_attemptPermanentFailure_recordsMetrics() throws InterruptedExcepti
assertThrows(InvalidArgumentException.class, () -> grpcClient.block(blockRequest));
- List metricDataList = getMetricDataList();
- verifyPointDataSum(metricDataList, attemptCount);
+ List actualMetricDataList = getMetricDataList();
+ verifyPointDataSum(actualMetricDataList, attemptCount);
- Map attributeMapping =
+ Map expectedAttributes =
ImmutableMap.of(
- MetricsTracer.METHOD_NAME_ATTRIBUTE,
+ MetricsTracer.METHOD_ATTRIBUTE,
"Echo.Block",
MetricsTracer.LANGUAGE_ATTRIBUTE,
MetricsTracer.DEFAULT_LANGUAGE);
- verifyDefaultMetricsAttributes(metricDataList, attributeMapping);
+ verifyDefaultMetricsAttributes(actualMetricDataList, expectedAttributes);
List statusCountList = ImmutableList.of(new StatusCount(statusCode));
- verifyStatusAttribute(metricDataList, statusCountList);
+ verifyStatusAttribute(actualMetricDataList, statusCountList);
}
@Disabled("https://github.com/googleapis/sdk-platform-java/issues/2503")
@@ -625,19 +634,19 @@ void testHttpJson_attemptPermanentFailure_recordsMetrics() throws InterruptedExc
assertThrows(InvalidArgumentException.class, () -> httpClient.block(blockRequest));
- List metricDataList = getMetricDataList();
- verifyPointDataSum(metricDataList, attemptCount);
+ List actualMetricDataList = getMetricDataList();
+ verifyPointDataSum(actualMetricDataList, attemptCount);
- Map attributeMapping =
+ Map expectedAttributes =
ImmutableMap.of(
- MetricsTracer.METHOD_NAME_ATTRIBUTE,
+ MetricsTracer.METHOD_ATTRIBUTE,
"google.showcase.v1beta1.Echo/Block",
MetricsTracer.LANGUAGE_ATTRIBUTE,
MetricsTracer.DEFAULT_LANGUAGE);
- verifyDefaultMetricsAttributes(metricDataList, attributeMapping);
+ verifyDefaultMetricsAttributes(actualMetricDataList, expectedAttributes);
List statusCountList = ImmutableList.of(new StatusCount(statusCode));
- verifyStatusAttribute(metricDataList, statusCountList);
+ verifyStatusAttribute(actualMetricDataList, statusCountList);
}
@Test
@@ -694,20 +703,20 @@ void testGrpc_multipleFailedAttempts_successfulOperation() throws Exception {
grpcClient.block(blockRequest);
- List metricDataList = getMetricDataList();
- verifyPointDataSum(metricDataList, attemptCount);
+ List actualMetricDataList = getMetricDataList();
+ verifyPointDataSum(actualMetricDataList, attemptCount);
- Map attributeMapping =
+ Map expectedAttributes =
ImmutableMap.of(
- MetricsTracer.METHOD_NAME_ATTRIBUTE,
+ MetricsTracer.METHOD_ATTRIBUTE,
"Echo.Block",
MetricsTracer.LANGUAGE_ATTRIBUTE,
MetricsTracer.DEFAULT_LANGUAGE);
- verifyDefaultMetricsAttributes(metricDataList, attributeMapping);
+ verifyDefaultMetricsAttributes(actualMetricDataList, expectedAttributes);
List statusCountList =
ImmutableList.of(new StatusCount(Code.DEADLINE_EXCEEDED, 2), new StatusCount(Code.OK));
- verifyStatusAttribute(metricDataList, statusCountList);
+ verifyStatusAttribute(actualMetricDataList, statusCountList);
grpcClient.close();
grpcClient.awaitTermination(TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS);
@@ -764,18 +773,86 @@ void testHttpJson_multipleFailedAttempts_successfulOperation() throws Exception
grpcClient.block(blockRequest);
- List metricDataList = getMetricDataList();
- verifyPointDataSum(metricDataList, attemptCount);
+ List actualMetricDataList = getMetricDataList();
+ verifyPointDataSum(actualMetricDataList, attemptCount);
- Map attributeMapping =
+ Map expectedAttributes =
ImmutableMap.of(
- MetricsTracer.METHOD_NAME_ATTRIBUTE,
+ MetricsTracer.METHOD_ATTRIBUTE,
"google.showcase.v1beta1.Echo/Block",
MetricsTracer.LANGUAGE_ATTRIBUTE,
MetricsTracer.DEFAULT_LANGUAGE);
- verifyDefaultMetricsAttributes(metricDataList, attributeMapping);
+ verifyDefaultMetricsAttributes(actualMetricDataList, expectedAttributes);
httpClient.close();
httpClient.awaitTermination(TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS);
}
+
+ @Test
+ void recordsCustomAttributes() throws InterruptedException, IOException {
+ InstantiatingGrpcChannelProvider channelProvider =
+ EchoSettings.defaultGrpcTransportProviderBuilder()
+ .setChannelConfigurator(ManagedChannelBuilder::usePlaintext)
+ .setAttemptDirectPathXds()
+ .build();
+
+ // Add custom attributes to be added as client level attributes
+ Map customAttributes = new HashMap<>();
+ String directpathEnabled = "directpath_enabled";
+ customAttributes.put(directpathEnabled, String.valueOf(channelProvider.canUseDirectPath()));
+ String directpathXdsEnabled = "directpathxds_enabled";
+ customAttributes.put(
+ directpathXdsEnabled, String.valueOf(channelProvider.isDirectPathXdsEnabled()));
+ String randomAttributeKey1 = "testing";
+ String randomAttributeValue1 = "showcase";
+ String randomAttributeKey2 = "hello";
+ String randomAttributeValue2 = "world";
+ customAttributes.put(randomAttributeKey1, randomAttributeValue1);
+ customAttributes.put(randomAttributeKey2, randomAttributeValue2);
+
+ InMemoryMetricReader inMemoryMetricReader = InMemoryMetricReader.create();
+ OpenTelemetryMetricsRecorder otelMetricsRecorder =
+ createOtelMetricsRecorder(inMemoryMetricReader);
+ MetricsTracerFactory metricsTracerFactory =
+ new MetricsTracerFactory(otelMetricsRecorder, customAttributes);
+
+ EchoSettings grpcEchoSettings =
+ EchoSettings.newBuilder()
+ .setCredentialsProvider(NoCredentialsProvider.create())
+ .setTransportChannelProvider(channelProvider)
+ .setEndpoint(TestClientInitializer.DEFAULT_GRPC_ENDPOINT)
+ .build();
+
+ EchoStubSettings echoStubSettings =
+ (EchoStubSettings)
+ grpcEchoSettings
+ .getStubSettings()
+ .toBuilder()
+ .setTracerFactory(metricsTracerFactory)
+ .build();
+ EchoStub stub = echoStubSettings.createStub();
+ EchoClient grpcClient = EchoClient.create(stub);
+
+ EchoRequest echoRequest = EchoRequest.newBuilder().setContent("content").build();
+ grpcClient.echo(echoRequest);
+
+ List actualMetricDataList = getMetricDataList(inMemoryMetricReader);
+ Map expectedAttributes =
+ ImmutableMap.of(
+ MetricsTracer.METHOD_ATTRIBUTE,
+ "Echo.Echo",
+ MetricsTracer.LANGUAGE_ATTRIBUTE,
+ MetricsTracer.DEFAULT_LANGUAGE,
+ directpathEnabled,
+ "false",
+ directpathXdsEnabled,
+ "true",
+ randomAttributeKey1,
+ randomAttributeValue1,
+ randomAttributeKey2,
+ randomAttributeValue2);
+ verifyDefaultMetricsAttributes(actualMetricDataList, expectedAttributes);
+
+ inMemoryMetricReader.close();
+ }
}
diff --git a/showcase/pom.xml b/showcase/pom.xml
index 841aa4db61..59d8bcecc2 100644
--- a/showcase/pom.xml
+++ b/showcase/pom.xml
@@ -15,7 +15,7 @@
com.google.cloud
google-cloud-shared-config
- 1.8.0
+ 1.8.1
@@ -34,7 +34,7 @@
com.google.cloud
google-cloud-shared-dependencies
- 3.31.0
+ 3.32.0
pom
import
@@ -108,7 +108,7 @@
org.apache.maven.plugins
maven-surefire-plugin
- 3.2.5
+ 3.3.0
sponge_log
${skipUnitTests}
diff --git a/versions.txt b/versions.txt
index 16eede494a..3612dbf52c 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,19 +1,19 @@
# Format:
# module:released-version:current-version
-gapic-generator-java:2.41.0:2.41.0
-api-common:2.32.0:2.32.0
-gax:2.49.0:2.49.0
-gax-grpc:2.49.0:2.49.0
-gax-httpjson:0.134.0:0.134.0
-proto-google-common-protos:2.40.0:2.40.0
-grpc-google-common-protos:2.40.0:2.40.0
-proto-google-iam-v1:1.35.0:1.35.0
-grpc-google-iam-v1:1.35.0:1.35.0
-proto-google-iam-v2beta:1.35.0:1.35.0
-grpc-google-iam-v2beta:1.35.0:1.35.0
-google-iam-policy:1.35.0:1.35.0
-proto-google-iam-v2:1.35.0:1.35.0
-grpc-google-iam-v2:1.35.0:1.35.0
-google-cloud-core:2.39.0:2.39.0
-google-cloud-shared-dependencies:3.31.0:3.31.0
+gapic-generator-java:2.42.0:2.42.0
+api-common:2.33.0:2.33.0
+gax:2.50.0:2.50.0
+gax-grpc:2.50.0:2.50.0
+gax-httpjson:0.135.0:0.135.0
+proto-google-common-protos:2.41.0:2.41.0
+grpc-google-common-protos:2.41.0:2.41.0
+proto-google-iam-v1:1.36.0:1.36.0
+grpc-google-iam-v1:1.36.0:1.36.0
+proto-google-iam-v2beta:1.36.0:1.36.0
+grpc-google-iam-v2beta:1.36.0:1.36.0
+google-iam-policy:1.36.0:1.36.0
+proto-google-iam-v2:1.36.0:1.36.0
+grpc-google-iam-v2:1.36.0:1.36.0
+google-cloud-core:2.40.0:2.40.0
+google-cloud-shared-dependencies:3.32.0:3.32.0