From ba3c080e5e51e68c397839c5f9c144596c739d0c Mon Sep 17 00:00:00 2001 From: Diego Marquez Date: Thu, 12 Feb 2026 12:08:55 -0500 Subject: [PATCH 1/6] feat(obs): generate gapic.properties file with repo property --- .../generator/gapic/model/GapicContext.java | 7 +++++- .../generator/gapic/protoparser/Parser.java | 2 ++ .../protoparser/PluginArgumentParser.java | 5 ++++ .../generator/gapic/protowriter/Writer.java | 17 +++++++++++++ .../protoparser/PluginArgumentParserTest.java | 20 ++++++++++++++++ .../gapic/protowriter/WriterTest.java | 24 +++++++++++++++++++ 6 files changed, 74 insertions(+), 1 deletion(-) diff --git a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/GapicContext.java b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/GapicContext.java index 780890c664..a6e86c5698 100644 --- a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/GapicContext.java +++ b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/GapicContext.java @@ -95,11 +95,14 @@ static GapicMetadata defaultGapicMetadata() { public abstract Transport transport(); + public abstract Optional repo(); + public static Builder builder() { return new AutoValue_GapicContext.Builder() .setMixinServices(Collections.emptyList()) .setGapicMetadataEnabled(false) - .setRestNumericEnumsEnabled(false); + .setRestNumericEnumsEnabled(false) + .setRepo(Optional.empty()); } @AutoValue.Builder @@ -130,6 +133,8 @@ public Builder setHelperResourceNames(Set helperResourceNames) { public abstract Builder setTransport(Transport transport); + public abstract Builder setRepo(Optional repo); + abstract ImmutableMap resourceNames(); abstract ImmutableMap helperResourceNames(); diff --git a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java index 0ff6a71039..43ef63a63c 100644 --- a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java +++ b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java @@ -150,6 +150,7 @@ public static GapicContext parse(CodeGeneratorRequest request) { Optional languageSettingsOpt = GapicLanguageSettingsParser.parse(gapicYamlConfigPathOpt); Optional transportOpt = PluginArgumentParser.parseTransport(request); + Optional repoOpt = PluginArgumentParser.parseRepo(request); boolean willGenerateMetadata = PluginArgumentParser.hasMetadataFlag(request); boolean willGenerateNumericEnum = PluginArgumentParser.hasNumericEnumFlag(request); @@ -253,6 +254,7 @@ public static GapicContext parse(CodeGeneratorRequest request) { .setServiceYamlProto(serviceYamlProtoOpt.orElse(null)) .setTransport(transport) .setRestNumericEnumsEnabled(willGenerateNumericEnum) + .setRepo(repoOpt) .build(); } diff --git a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protoparser/PluginArgumentParser.java b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protoparser/PluginArgumentParser.java index f56e0621a9..487aeb440e 100644 --- a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protoparser/PluginArgumentParser.java +++ b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protoparser/PluginArgumentParser.java @@ -32,6 +32,7 @@ public class PluginArgumentParser { @VisibleForTesting static final String KEY_NUMERIC_ENUM = "rest-numeric-enums"; @VisibleForTesting static final String KEY_SERVICE_YAML_CONFIG = "api-service-config"; @VisibleForTesting static final String KEY_TRANSPORT = "transport"; + @VisibleForTesting static final String KEY_REPO = "repo"; private static final String JSON_FILE_ENDING = "grpc_service_config.json"; private static final String GAPIC_YAML_FILE_ENDING = "gapic.yaml"; @@ -53,6 +54,10 @@ static Optional parseTransport(CodeGeneratorRequest request) { return parseConfigArgument(request.getParameter(), KEY_TRANSPORT); } + static Optional parseRepo(CodeGeneratorRequest request) { + return parseConfigArgument(request.getParameter(), KEY_REPO); + } + static boolean hasMetadataFlag(CodeGeneratorRequest request) { return hasFlag(request.getParameter(), KEY_METADATA); } diff --git a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protowriter/Writer.java b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protowriter/Writer.java index 79c9cbf349..c24c8d935a 100644 --- a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protowriter/Writer.java +++ b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protowriter/Writer.java @@ -71,6 +71,7 @@ protected static CodeGeneratorResponse write( writeMetadataFile(context, writePackageInfo(gapicPackageInfo, codeWriter, jos), jos); writeReflectConfigFile(gapicPackageInfo.packageInfo().pakkage(), reflectConfigInfo, jos); + writeGapicPropertiesFile(context, jos); jos.finish(); jos.flush(); @@ -212,6 +213,22 @@ private static void writeMetadataFile(GapicContext context, String path, JarOutp } } + @VisibleForTesting + static void writeGapicPropertiesFile(GapicContext context, JarOutputStream jos) { + context + .repo() + .ifPresent( + repo -> { + JarEntry jarEntry = new JarEntry("src/main/resources/gapic.properties"); + try { + jos.putNextEntry(jarEntry); + jos.write(String.format("repo=%s\n", repo).getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + throw new GapicWriterException("Could not write repo file", e); + } + }); + } + private static String getPath(String pakkage, String className) { String path = pakkage.replaceAll("\\.", "/"); if (className.startsWith("Mock") || className.endsWith("Test")) { diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protoparser/PluginArgumentParserTest.java b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protoparser/PluginArgumentParserTest.java index 83e75f87f5..ab5fac84f9 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protoparser/PluginArgumentParserTest.java +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protoparser/PluginArgumentParserTest.java @@ -16,6 +16,7 @@ import static com.google.api.generator.gapic.protoparser.PluginArgumentParser.KEY_METADATA; import static com.google.api.generator.gapic.protoparser.PluginArgumentParser.KEY_NUMERIC_ENUM; +import static com.google.api.generator.gapic.protoparser.PluginArgumentParser.KEY_REPO; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -269,6 +270,21 @@ void hasFlag_flagFound() { assertTrue(PluginArgumentParser.hasFlag(rawArgument, KEY_METADATA)); } + @Test + void parseRepo_onlyOnePresent() { + String repo = "googleapis/sdk-platform-java"; + CodeGeneratorRequest request = + CodeGeneratorRequest.newBuilder().setParameter(createRepo(repo)).build(); + assertEquals(repo, PluginArgumentParser.parseRepo(request).get()); + } + + @Test + void parseRepo_noneFound() { + CodeGeneratorRequest request = + CodeGeneratorRequest.newBuilder().setParameter("metadata").build(); + assertFalse(PluginArgumentParser.parseRepo(request).isPresent()); + } + private static String createGrpcServiceConfig(String path) { return String.format("%s=%s", PluginArgumentParser.KEY_GRPC_SERVICE_CONFIG, path); } @@ -280,4 +296,8 @@ private static String createGapicConfig(String path) { private static String createServiceConfig(String path) { return String.format("%s=%s", PluginArgumentParser.KEY_SERVICE_YAML_CONFIG, path); } + + private static String createRepo(String repo) { + return String.format("%s=%s", KEY_REPO, repo); + } } diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protowriter/WriterTest.java b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protowriter/WriterTest.java index c366d2085e..9081c56b1f 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protowriter/WriterTest.java +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protowriter/WriterTest.java @@ -16,6 +16,7 @@ import com.google.gson.Gson; import com.google.protobuf.ByteString; import com.google.protobuf.compiler.PluginProtos.CodeGeneratorResponse; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; @@ -25,6 +26,7 @@ import java.util.Collections; import java.util.Enumeration; import java.util.List; +import java.util.Optional; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarOutputStream; @@ -144,4 +146,26 @@ void productionWrite_emptyGapicContext_succeeds() throws IOException { "temp-codegen.srcjar"); assertNull(result); } + + @Test + void writeRepoFile_isWritten() throws IOException { + String repo = "googleapis/sdk-platform-java"; + GapicContext context = GapicContext.EMPTY.toBuilder().setRepo(Optional.of(repo)).build(); + Writer.writeGapicPropertiesFile(context, jarOutputStream); + + closeJarOutputStream(); + + try (JarFile jarFile = new JarFile(file)) { + Enumeration entries = jarFile.entries(); + assertThat(entries.hasMoreElements()).isTrue(); + JarEntry entry = entries.nextElement(); + assertThat(entries.hasMoreElements()).isFalse(); + assertEquals("src/main/resources/gapic.properties", entry.getName()); + try (BufferedReader reader = + new BufferedReader(new InputStreamReader(jarFile.getInputStream(entry)))) { + String line = reader.readLine(); + assertEquals("repo=" + repo, line); + } + } + } } From caead0d7fe29bd895e8d901fa8ffd0f3b39ec68d Mon Sep 17 00:00:00 2001 From: Diego Marquez Date: Thu, 12 Feb 2026 12:46:23 -0500 Subject: [PATCH 2/6] feat: implement repo handling in gax --- .../api/gax/tracing/ApiTracerContext.java | 42 ++++++++- .../api/gax/tracing/AppCentricTracer.java | 3 +- .../gax/tracing/AppCentricTracerFactory.java | 3 + .../api/gax/tracing/ApiTracerContextTest.java | 92 +++++++++++++++++++ .../showcase/v1beta1/it/ITOtelTracing.java | 11 +++ 5 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 gax-java/gax/src/test/java/com/google/api/gax/tracing/ApiTracerContextTest.java diff --git a/gax-java/gax/src/main/java/com/google/api/gax/tracing/ApiTracerContext.java b/gax-java/gax/src/main/java/com/google/api/gax/tracing/ApiTracerContext.java index 1c92bd8db3..b35385f286 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/tracing/ApiTracerContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/tracing/ApiTracerContext.java @@ -32,6 +32,12 @@ import com.google.api.core.InternalApi; import com.google.auto.value.AutoValue; +import com.google.common.annotations.VisibleForTesting; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.annotation.Nullable; /** @@ -43,18 +49,52 @@ @InternalApi @AutoValue public abstract class ApiTracerContext { + private static final Logger LOGGER = Logger.getLogger(ApiTracerContext.class.getName()); + private static final String GAPIC_PROPERTIES_FILE = "/gapic.properties"; + private static final String REPO_KEY = "repo"; @Nullable public abstract String getServerAddress(); + @Nullable + public abstract String getRepo(); + public static Builder newBuilder() { - return new AutoValue_ApiTracerContext.Builder(); + return newBuilder(ApiTracerContext.class.getResourceAsStream(GAPIC_PROPERTIES_FILE)); + } + + @VisibleForTesting + static Builder newBuilder(@Nullable InputStream inputStream) { + Builder builder = new AutoValue_ApiTracerContext.Builder(); + loadRepoFromProperties(builder, inputStream); + return builder; + } + + private static void loadRepoFromProperties(Builder builder, @Nullable InputStream is) { + if (is == null) { + return; + } + try { + Properties properties = new Properties(); + properties.load(is); + builder.setRepo(properties.getProperty(REPO_KEY)); + } catch (IOException e) { + LOGGER.log(Level.WARNING, "Could not load gapic.properties", e); + } finally { + try { + is.close(); + } catch (IOException e) { + LOGGER.log(Level.WARNING, "Could not close gapic.properties stream", e); + } + } } @AutoValue.Builder public abstract static class Builder { public abstract Builder setServerAddress(String serverAddress); + public abstract Builder setRepo(String repo); + public abstract ApiTracerContext build(); } } diff --git a/gax-java/gax/src/main/java/com/google/api/gax/tracing/AppCentricTracer.java b/gax-java/gax/src/main/java/com/google/api/gax/tracing/AppCentricTracer.java index c885e526e0..247ceefea0 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/tracing/AppCentricTracer.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/tracing/AppCentricTracer.java @@ -44,7 +44,8 @@ @InternalApi public class AppCentricTracer implements ApiTracer { public static final String SERVER_ADDRESS_ATTRIBUTE = "server.address"; - public static final String LANGUAGE_ATTRIBUTE = "gcp.client.language"; + public static final String REPO_ATTRIBUTE = "gcp.client.language"; + public static final String LANGUAGE_ATTRIBUTE = "gcp.client.repo"; public static final String DEFAULT_LANGUAGE = "Java"; diff --git a/gax-java/gax/src/main/java/com/google/api/gax/tracing/AppCentricTracerFactory.java b/gax-java/gax/src/main/java/com/google/api/gax/tracing/AppCentricTracerFactory.java index c2f4261383..b59638715b 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/tracing/AppCentricTracerFactory.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/tracing/AppCentricTracerFactory.java @@ -101,6 +101,9 @@ public ApiTracerFactory withContext(ApiTracerContext context) { newAttemptAttributes.put( AppCentricTracer.SERVER_ADDRESS_ATTRIBUTE, context.getServerAddress()); } + if (context.getRepo() != null) { + newAttemptAttributes.put(AppCentricTracer.REPO_ATTRIBUTE, context.getRepo()); + } return new AppCentricTracerFactory(traceRecorder, operationAttributes, newAttemptAttributes); } } diff --git a/gax-java/gax/src/test/java/com/google/api/gax/tracing/ApiTracerContextTest.java b/gax-java/gax/src/test/java/com/google/api/gax/tracing/ApiTracerContextTest.java new file mode 100644 index 0000000000..8d704643cb --- /dev/null +++ b/gax-java/gax/src/test/java/com/google/api/gax/tracing/ApiTracerContextTest.java @@ -0,0 +1,92 @@ +/* + * Copyright 2026 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.api.gax.tracing; + +import static com.google.common.truth.Truth.assertThat; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class ApiTracerContextTest { + + @Test + void testNewBuilderWithNoPropertiesFile() { + ApiTracerContext context = + ApiTracerContext.newBuilder(null).setServerAddress("test-address").build(); + + assertThat(context.getServerAddress()).isEqualTo("test-address"); + assertThat(context.getRepo()).isNull(); + } + + @Test + void testNewBuilderWithPropertiesFile() { + String propertiesContent = "repo=test-repo"; + InputStream inputStream = + new ByteArrayInputStream(propertiesContent.getBytes(StandardCharsets.UTF_8)); + + ApiTracerContext context = + ApiTracerContext.newBuilder(inputStream).setServerAddress("test-address").build(); + + assertThat(context.getServerAddress()).isEqualTo("test-address"); + assertThat(context.getRepo()).isEqualTo("test-repo"); + } + + @Test + void testNewBuilderWithPropertiesFileAndNoRepoKey() { + String propertiesContent = "somekey=somevalue"; + InputStream inputStream = + new ByteArrayInputStream(propertiesContent.getBytes(StandardCharsets.UTF_8)); + + ApiTracerContext context = + ApiTracerContext.newBuilder(inputStream).setServerAddress("test-address").build(); + + assertThat(context.getServerAddress()).isEqualTo("test-address"); + assertThat(context.getRepo()).isNull(); + } + + @Test + void testNewBuilderWithPropertiesFileLoadingError() throws IOException { + InputStream mockInputStream = Mockito.mock(InputStream.class); + Mockito.doThrow(new IOException("Test IO Exception")) + .when(mockInputStream) + .read(Mockito.any(byte[].class)); + + ApiTracerContext context = + ApiTracerContext.newBuilder(mockInputStream).setServerAddress("test-address").build(); + + assertThat(context.getServerAddress()).isEqualTo("test-address"); + assertThat(context.getRepo()).isNull(); + } +} diff --git a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelTracing.java b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelTracing.java index cddf0c5372..cbed57cc74 100644 --- a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelTracing.java +++ b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelTracing.java @@ -54,6 +54,7 @@ class ITOtelTracing { private static final String SHOWCASE_SERVER_ADDRESS = "localhost"; + private static final String SHOWCASE_REPO = "googleapis/sdk-platform-java"; private InMemorySpanExporter spanExporter; private OpenTelemetrySdk openTelemetrySdk; @@ -137,6 +138,11 @@ void testTracing_successfulEcho_grpc() throws Exception { .getAttributes() .get(AttributeKey.stringKey(AppCentricTracer.SERVER_ADDRESS_ATTRIBUTE))) .isEqualTo(SHOWCASE_SERVER_ADDRESS); + assertThat( + attemptSpan + .getAttributes() + .get(AttributeKey.stringKey(AppCentricTracer.REPO_ATTRIBUTE))) + .isEqualTo(SHOWCASE_REPO); } } @@ -176,6 +182,11 @@ void testTracing_successfulEcho_httpjson() throws Exception { .getAttributes() .get(AttributeKey.stringKey(AppCentricTracer.SERVER_ADDRESS_ATTRIBUTE))) .isEqualTo(SHOWCASE_SERVER_ADDRESS); + assertThat( + attemptSpan + .getAttributes() + .get(AttributeKey.stringKey(AppCentricTracer.REPO_ATTRIBUTE))) + .isEqualTo(SHOWCASE_REPO); } } } From 58f72d2595199907098a14892acd0130eaed4069 Mon Sep 17 00:00:00 2001 From: Diego Marquez Date: Thu, 12 Feb 2026 12:51:51 -0500 Subject: [PATCH 3/6] test: add tests for repo property --- .../tracing/AppCentricTracerFactoryTest.java | 6 +++-- .../api/gax/tracing/AppCentricTracerTest.java | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/gax-java/gax/src/test/java/com/google/api/gax/tracing/AppCentricTracerFactoryTest.java b/gax-java/gax/src/test/java/com/google/api/gax/tracing/AppCentricTracerFactoryTest.java index c3826d533d..90c1af41d6 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/tracing/AppCentricTracerFactoryTest.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/tracing/AppCentricTracerFactoryTest.java @@ -89,7 +89,7 @@ void testWithContext_addsInferredAttributes() { when(recorder.createSpan(anyString(), anyMap())).thenReturn(operationHandle); ApiTracerContext context = - ApiTracerContext.newBuilder().setServerAddress("example.com").build(); + ApiTracerContext.newBuilder().setServerAddress("example.com").setRepo("my-repo").build(); AppCentricTracerFactory factory = new AppCentricTracerFactory(recorder); ApiTracerFactory factoryWithContext = factory.withContext(context); @@ -107,6 +107,7 @@ void testWithContext_addsInferredAttributes() { Map attemptAttributes = attributesCaptor.getValue(); assertThat(attemptAttributes) .containsEntry(AppCentricTracer.SERVER_ADDRESS_ATTRIBUTE, "example.com"); + assertThat(attemptAttributes).containsEntry(AppCentricTracer.REPO_ATTRIBUTE, "my-repo"); } @Test @@ -115,7 +116,7 @@ void testWithContext_noEndpointContext_doesNotAddAttributes() { TraceRecorder.TraceSpan operationHandle = mock(TraceRecorder.TraceSpan.class); when(recorder.createSpan(anyString(), anyMap())).thenReturn(operationHandle); - ApiTracerContext context = ApiTracerContext.newBuilder().build(); + ApiTracerContext context = ApiTracerContext.newBuilder(null).build(); AppCentricTracerFactory factory = new AppCentricTracerFactory(recorder); ApiTracerFactory factoryWithContext = factory.withContext(context); @@ -132,5 +133,6 @@ void testWithContext_noEndpointContext_doesNotAddAttributes() { Map attemptAttributes = attributesCaptor.getValue(); assertThat(attemptAttributes).doesNotContainKey(AppCentricTracer.SERVER_ADDRESS_ATTRIBUTE); + assertThat(attemptAttributes).doesNotContainKey(AppCentricTracer.REPO_ATTRIBUTE); } } diff --git a/gax-java/gax/src/test/java/com/google/api/gax/tracing/AppCentricTracerTest.java b/gax-java/gax/src/test/java/com/google/api/gax/tracing/AppCentricTracerTest.java index 702f16a50b..63be3be8c8 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/tracing/AppCentricTracerTest.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/tracing/AppCentricTracerTest.java @@ -29,15 +29,18 @@ */ package com.google.api.gax.tracing; +import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.HashMap; +import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -73,4 +76,28 @@ void testAttemptLifecycle_startsAndEndsAttemptSpan() { verify(attemptHandle).end(); } + + @Test + void testAttemptStarted_includesRepoAttribute() { + Map attemptAttributes = new HashMap<>(); + attemptAttributes.put(AppCentricTracer.REPO_ATTRIBUTE, "test-repo"); + + tracer = + new AppCentricTracer( + recorder, OPERATION_SPAN_NAME, ATTEMPT_SPAN_NAME, new HashMap<>(), attemptAttributes); + + when(recorder.createSpan(eq(ATTEMPT_SPAN_NAME), anyMap(), eq(operationHandle))) + .thenReturn(attemptHandle); + + tracer.attemptStarted(new Object(), 1); + + ArgumentCaptor> attributesCaptor = ArgumentCaptor.forClass(Map.class); + verify(recorder) + .createSpan(eq(ATTEMPT_SPAN_NAME), attributesCaptor.capture(), eq(operationHandle)); + + assertThat(attributesCaptor.getValue()) + .containsEntry(AppCentricTracer.REPO_ATTRIBUTE, "test-repo"); + assertThat(attributesCaptor.getValue()) + .containsEntry(AppCentricTracer.LANGUAGE_ATTRIBUTE, AppCentricTracer.DEFAULT_LANGUAGE); + } } From 5a5d9d6e36f136792b897ca329ddc1d8f36313fa Mon Sep 17 00:00:00 2001 From: Diego Marquez Date: Thu, 12 Feb 2026 12:52:02 -0500 Subject: [PATCH 4/6] chore: speed up image building --- .cloudbuild/library_generation/library_generation.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cloudbuild/library_generation/library_generation.Dockerfile b/.cloudbuild/library_generation/library_generation.Dockerfile index f0ec060357..eb9d944738 100644 --- a/.cloudbuild/library_generation/library_generation.Dockerfile +++ b/.cloudbuild/library_generation/library_generation.Dockerfile @@ -30,7 +30,7 @@ RUN cat /java-formatter-version RUN V=$(cat /java-formatter-version) && curl -o "/google-java-format.jar" "https://maven-central.storage-download.googleapis.com/maven2/com/google/googlejavaformat/google-java-format/${V}/google-java-format-${V}-all-deps.jar" # Compile and install packages -RUN mvn install -B -ntp -DskipTests -Dclirr.skip -Dcheckstyle.skip +RUN mvn install -B -ntp -T 1.5C -DskipTests -Dcheckstyle.skip -Dclirr.skip -Denforcer.skip -Dfmt.skip RUN cp "/root/.m2/repository/com/google/api/gapic-generator-java/${DOCKER_GAPIC_GENERATOR_VERSION}/gapic-generator-java-${DOCKER_GAPIC_GENERATOR_VERSION}.jar" \ "./gapic-generator-java.jar" From 015aa887cff0028dad42ab27f8bb9092c6a71ec3 Mon Sep 17 00:00:00 2001 From: Diego Marquez Date: Thu, 12 Feb 2026 13:01:46 -0500 Subject: [PATCH 5/6] build: introduce repo property to generation config --- .../generate_composed_library.py | 6 +++++ .../library_generation/generate_library.sh | 10 +++++++- .../tests/generate_library_unit_tests.sh | 15 ++++++----- .../tests/utilities_unit_tests.py | 18 +++++++++++++ .../library_generation/utils/utilities.py | 25 ++++++++++++++----- .../library_generation/utils/utilities.sh | 3 ++- 6 files changed, 63 insertions(+), 14 deletions(-) diff --git a/hermetic_build/library_generation/generate_composed_library.py b/hermetic_build/library_generation/generate_composed_library.py index ea595a3f98..653df39c09 100755 --- a/hermetic_build/library_generation/generate_composed_library.py +++ b/hermetic_build/library_generation/generate_composed_library.py @@ -84,6 +84,8 @@ def generate_composed_library( gapic=gapic, gapic_inputs=gapic_inputs, temp_destination_path=temp_destination_path, + generation_config=config, + library=library, ) print("arguments: ") print(effective_arguments) @@ -124,6 +126,8 @@ def __construct_effective_arg( gapic: GapicConfig, gapic_inputs: GapicInputs, temp_destination_path: str, + generation_config: LibraryConfig, + library: LibraryConfig, ) -> List[str]: """ Construct arguments consist attributes of a GAPIC library which used in @@ -153,6 +157,8 @@ def __construct_effective_arg( gapic_inputs.service_yaml, "--include_samples", gapic_inputs.include_samples, + "--repo", + util.get_library_repository(generation_config, library), ] arguments += ["--destination_path", temp_destination_path] diff --git a/hermetic_build/library_generation/generate_library.sh b/hermetic_build/library_generation/generate_library.sh index 2625021ea6..579e329d1a 100755 --- a/hermetic_build/library_generation/generate_library.sh +++ b/hermetic_build/library_generation/generate_library.sh @@ -50,6 +50,10 @@ case $key in os_architecture="$2" shift ;; + --repo) + repo="$2" + shift + ;; *) echo "Invalid option: [$1]" exit 1 @@ -99,6 +103,10 @@ if [ -z "${os_architecture}" ]; then os_architecture=$(detect_os_architecture) fi +if [ -z "${repo}" ]; then + repo=$(repo) +fi + temp_destination_path="${output_folder}/temp_preprocessed-$RANDOM" mkdir -p "${output_folder}/${destination_path}" if [ -d "${temp_destination_path}" ]; then @@ -179,7 +187,7 @@ if [[ "${proto_only}" == "false" ]]; then "$protoc_path"/protoc --experimental_allow_proto3_optional \ "--plugin=protoc-gen-java_gapic=${script_dir}/gapic-generator-java-wrapper" \ "--java_gapic_out=metadata:${temp_destination_path}/java_gapic_srcjar_raw.srcjar.zip" \ - "--java_gapic_opt=$(get_gapic_opts "${transport}" "${rest_numeric_enums}" "${gapic_yaml}" "${service_config}" "${service_yaml}")" \ + "--java_gapic_opt=$(get_gapic_opts "${transport}" "${rest_numeric_enums}" "${gapic_yaml}" "${service_config}" "${service_yaml}" "${repo}")" \ ${proto_files} ${gapic_additional_protos} unzip -o -q "${temp_destination_path}/java_gapic_srcjar_raw.srcjar.zip" -d "${temp_destination_path}" diff --git a/hermetic_build/library_generation/tests/generate_library_unit_tests.sh b/hermetic_build/library_generation/tests/generate_library_unit_tests.sh index 68eb9ba40e..1093fffe0b 100755 --- a/hermetic_build/library_generation/tests/generate_library_unit_tests.sh +++ b/hermetic_build/library_generation/tests/generate_library_unit_tests.sh @@ -27,10 +27,11 @@ get_gapic_opts_with_rest_test() { local proto_path="${script_dir}/resources/gapic_options" local transport="grpc" local rest_numeric_enums="true" + local repo="googleapis/google-cloud-java" local gapic_opts - gapic_opts="$(get_gapic_opts "${transport}" "${rest_numeric_enums}" "" "" "")" + gapic_opts="$(get_gapic_opts "${transport}" "${rest_numeric_enums}" "" "" "" "${repo}")" assertEquals \ - "transport=grpc,rest-numeric-enums,grpc-service-config=${proto_path}/example_grpc_service_config.json,gapic-config=${proto_path}/example_gapic.yaml,api-service-config=${proto_path}/example.yaml" \ + "transport=grpc,rest-numeric-enums,grpc-service-config=${proto_path}/example_grpc_service_config.json,gapic-config=${proto_path}/example_gapic.yaml,api-service-config=${proto_path}/example.yaml,repo=${repo}" \ "${gapic_opts}" } @@ -38,10 +39,11 @@ get_gapic_opts_without_rest_test() { local proto_path="${script_dir}/resources/gapic_options" local transport="grpc" local rest_numeric_enums="false" + local repo="googleapis/google-cloud-java" local gapic_opts - gapic_opts="$(get_gapic_opts "${transport}" "${rest_numeric_enums}" "" "" "")" + gapic_opts="$(get_gapic_opts "${transport}" "${rest_numeric_enums}" "" "" "" "${repo}")" assertEquals \ - "transport=grpc,,grpc-service-config=${proto_path}/example_grpc_service_config.json,gapic-config=${proto_path}/example_gapic.yaml,api-service-config=${proto_path}/example.yaml" \ + "transport=grpc,,grpc-service-config=${proto_path}/example_grpc_service_config.json,gapic-config=${proto_path}/example_gapic.yaml,api-service-config=${proto_path}/example.yaml,repo=${repo}" \ "$gapic_opts" } @@ -49,10 +51,11 @@ get_gapic_opts_with_non_default_test() { local proto_path="${script_dir}/resources/gapic_options" local transport="grpc" local rest_numeric_enums="false" + local repo="googleapis/google-cloud-java" local gapic_opts - gapic_opts="$(get_gapic_opts "${transport}" "${rest_numeric_enums}" "${proto_path}/example_gapic.yaml" "${proto_path}/example_grpc_service_config.json" "${proto_path}/example.yaml")" + gapic_opts="$(get_gapic_opts "${transport}" "${rest_numeric_enums}" "${proto_path}/example_gapic.yaml" "${proto_path}/example_grpc_service_config.json" "${proto_path}/example.yaml" "${repo}")" assertEquals \ - "transport=grpc,,grpc-service-config=${proto_path}/example_grpc_service_config.json,gapic-config=${proto_path}/example_gapic.yaml,api-service-config=${proto_path}/example.yaml" \ + "transport=grpc,,grpc-service-config=${proto_path}/example_grpc_service_config.json,gapic-config=${proto_path}/example_gapic.yaml,api-service-config=${proto_path}/example.yaml,repo=${repo}" \ "$gapic_opts" } diff --git a/hermetic_build/library_generation/tests/utilities_unit_tests.py b/hermetic_build/library_generation/tests/utilities_unit_tests.py index a6796b706d..d5a70054b1 100644 --- a/hermetic_build/library_generation/tests/utilities_unit_tests.py +++ b/hermetic_build/library_generation/tests/utilities_unit_tests.py @@ -178,6 +178,24 @@ def test_eprint_valid_input_succeeds(self): # print() appends a `\n` each time it's called self.assertEqual(test_input + "\n", result) + def test_get_library_repository_with_common_protos_returns_sdk_platform_java(self): + config = self.__get_a_gen_config(3) + library = common_protos + result = util.get_library_repository(config, library) + self.assertEqual("googleapis/sdk-platform-java", result) + + def test_get_library_repository_with_monorepo_returns_google_cloud_java(self): + config = self.__get_a_gen_config(2) + library = library_1 + result = util.get_library_repository(config, library) + self.assertEqual("googleapis/google-cloud-java", result) + + def test_get_library_repository_with_split_repo_returns_library_repo(self): + config = self.__get_a_gen_config(1) + library = library_1 + result = util.get_library_repository(config, library) + self.assertEqual("googleapis/java-bare-metal-solution", result) + def test_generate_postprocessing_prerequisite_files_non_monorepo_success(self): library_path = self.__setup_postprocessing_prerequisite_files( combination=1, library_type="GAPIC_COMBO" diff --git a/hermetic_build/library_generation/utils/utilities.py b/hermetic_build/library_generation/utils/utilities.py index ec5c03d069..d1d44e21bf 100755 --- a/hermetic_build/library_generation/utils/utilities.py +++ b/hermetic_build/library_generation/utils/utilities.py @@ -170,6 +170,24 @@ def prepare_repo( ) +def get_library_repository( + config: GenerationConfig, library: LibraryConfig, language: str = "java" +): + """ + Obtains the repository identifier (e.g. googleapis/java-bigtable) depending on + whether it's a monorepo (google-cloud-java or sdk-platform-java if has common-protos) or not. + + :return: string representing the repository + """ + if config.contains_common_protos(): + repo = SDK_PLATFORM_JAVA + elif config.is_monorepo(): + repo = "googleapis/google-cloud-java" + else: + repo = f"googleapis/{language}-{library.get_library_name()}" + return repo + + def generate_postprocessing_prerequisite_files( config: GenerationConfig, library: LibraryConfig, @@ -191,14 +209,9 @@ def generate_postprocessing_prerequisite_files( :param language: programming language of the library :return: None """ + repo = get_library_repository(config, library) library_name = library.get_library_name() artifact_id = library.get_artifact_id() - if config.contains_common_protos(): - repo = SDK_PLATFORM_JAVA - elif config.is_monorepo(): - repo = "googleapis/google-cloud-java" - else: - repo = f"googleapis/{language}-{library_name}" api_id = ( library.api_id if library.api_id else f"{library.api_shortname}.googleapis.com" ) diff --git a/hermetic_build/library_generation/utils/utilities.sh b/hermetic_build/library_generation/utils/utilities.sh index 863834f508..55e89098a7 100755 --- a/hermetic_build/library_generation/utils/utilities.sh +++ b/hermetic_build/library_generation/utils/utilities.sh @@ -70,6 +70,7 @@ get_gapic_opts() { local gapic_yaml=$3 local service_config=$4 local service_yaml=$5 + local repo=$6 if [ "${rest_numeric_enums}" == "true" ]; then rest_numeric_enums="rest-numeric-enums" else @@ -88,7 +89,7 @@ get_gapic_opts() { if [[ "${service_yaml}" == "" ]]; then service_yaml=$(find "${proto_path}" -maxdepth 1 -type f \( -name "*.yaml" ! -name "*gapic*.yaml" \)) fi - echo "transport=${transport},${rest_numeric_enums},grpc-service-config=${service_config},gapic-config=${gapic_yaml},api-service-config=${service_yaml}" + echo "transport=${transport},${rest_numeric_enums},grpc-service-config=${service_config},gapic-config=${gapic_yaml},api-service-config=${service_yaml},repo=${repo}" } remove_grpc_version() { From 0907e9393f690d646c50e8e20a24cfd0d2d2d7f4 Mon Sep 17 00:00:00 2001 From: Diego Marquez Date: Thu, 12 Feb 2026 13:10:42 -0500 Subject: [PATCH 6/6] chore: update showcase module --- java-showcase/gapic-showcase/src/main/resources/gapic.properties | 1 + 1 file changed, 1 insertion(+) create mode 100644 java-showcase/gapic-showcase/src/main/resources/gapic.properties diff --git a/java-showcase/gapic-showcase/src/main/resources/gapic.properties b/java-showcase/gapic-showcase/src/main/resources/gapic.properties new file mode 100644 index 0000000000..ac1d20a460 --- /dev/null +++ b/java-showcase/gapic-showcase/src/main/resources/gapic.properties @@ -0,0 +1 @@ +repo=googleapis/sdk-platform-java