diff --git a/.cloudbuild/library_generation/library_generation.Dockerfile b/.cloudbuild/library_generation/library_generation.Dockerfile index 09d23a106b..f6ef6f1609 100644 --- a/.cloudbuild/library_generation/library_generation.Dockerfile +++ b/.cloudbuild/library_generation/library_generation.Dockerfile @@ -15,26 +15,68 @@ # build from the root of this repo: FROM gcr.io/cloud-devrel-public-resources/python -# install tools +ARG SYNTHTOOL_COMMITTISH=63cc541da2c45fcfca2136c43e638da1fbae174d +ARG OWLBOT_CLI_COMMITTISH=ac84fa5c423a0069bbce3d2d869c9730c8fdf550 +ENV HOME=/home + +# install OS tools RUN apt-get update && apt-get install -y \ unzip openjdk-17-jdk rsync maven jq \ && apt-get clean -COPY library_generation /src - +# use python 3.11 (the base image has several python versions; here we define the default one) RUN rm $(which python3) RUN ln -s $(which python3.11) /usr/local/bin/python RUN ln -s $(which python3.11) /usr/local/bin/python3 RUN python -m pip install --upgrade pip -RUN cd /src && python -m pip install -r requirements.txt -RUN cd /src && python -m pip install . -# set dummy git credentials for empty commit used in postprocessing -RUN git config --global user.email "cloud-java-bot@google.com" -RUN git config --global user.name "Cloud Java Bot" +# copy source code +COPY library_generation /src -WORKDIR /workspace -RUN chmod 750 /workspace -RUN chmod 750 /src/generate_repo.py +# install scripts as a python package +WORKDIR /src +RUN python -m pip install -r requirements.txt +RUN python -m pip install . + +# install synthtool +WORKDIR /tools +RUN git clone https://github.com/googleapis/synthtool +WORKDIR /tools/synthtool +RUN git checkout "${SYNTHTOOL_COMMITTISH}" +RUN python3 -m pip install --no-deps -e . +RUN python3 -m pip install -r requirements.in -CMD [ "/src/generate_repo.py" ] +# Install nvm with node and npm +ENV NODE_VERSION 20.12.0 +WORKDIR /home +RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash +RUN chmod o+rx /home/.nvm +ENV NODE_PATH=/home/.nvm/versions/node/v${NODE_VERSION}/bin +ENV PATH=${PATH}:${NODE_PATH} +RUN node --version +RUN npm --version + +# install the owl-bot CLI +WORKDIR /tools +RUN git clone https://github.com/googleapis/repo-automation-bots +WORKDIR /tools/repo-automation-bots/packages/owl-bot +RUN git checkout "${OWLBOT_CLI_COMMITTISH}" +RUN npm i && npm run compile && npm link +RUN owl-bot copy-code --version +RUN chmod -R o+rx ${NODE_PATH} +RUN ln -sf ${NODE_PATH}/* /usr/local/bin + +# allow users to access the script folders +RUN chmod -R o+rx /src + +# set dummy git credentials for the empty commit used in postprocessing +# we use system so all users using the container will use this configuration +RUN git config --system user.email "cloud-java-bot@google.com" +RUN git config --system user.name "Cloud Java Bot" + +# allow read-write for /home and execution for binaries in /home/.nvm +RUN chmod -R a+rw /home +RUN chmod -R a+rx /home/.nvm + +WORKDIR /workspace +ENTRYPOINT [ "python", "/src/cli/entry_point.py", "generate" ] diff --git a/.github/workflows/anaylze_dependency.yaml b/.github/workflows/analyze_dependency.yaml similarity index 98% rename from .github/workflows/anaylze_dependency.yaml rename to .github/workflows/analyze_dependency.yaml index 1030e469d1..22b350d53c 100644 --- a/.github/workflows/anaylze_dependency.yaml +++ b/.github/workflows/analyze_dependency.yaml @@ -25,7 +25,7 @@ jobs: - uses: actions/setup-java@v4 with: distribution: temurin - java-version: 11 + java-version: 17 cache: maven - name: Set up Maven uses: stCarolas/setup-maven@v4.5 diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml index 355a651f55..12e239ae8c 100644 --- a/.github/workflows/nightly.yaml +++ b/.github/workflows/nightly.yaml @@ -23,7 +23,7 @@ jobs: distribution: temurin cache: maven - run: mvn -version - - name: Unit Tests + - name: Install run: mvn install --errors --batch-mode --no-transfer-progress -Dcheckstyle.skip -T 1C - name: Create issue if previous step fails if: ${{ failure() }} diff --git a/.github/workflows/verify_library_generation.yaml b/.github/workflows/verify_library_generation.yaml index c51f8ed7b0..8feec8a9d6 100644 --- a/.github/workflows/verify_library_generation.yaml +++ b/.github/workflows/verify_library_generation.yaml @@ -3,14 +3,38 @@ on: branches: - main pull_request: - paths: - - library_generation/** workflow_dispatch: name: verify_library_generation jobs: - integration_tests: + should-run-library-generation-tests: runs-on: ubuntu-22.04 + outputs: + should_run: ${{ steps.get_changed_directories.outputs.should_run }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: get changed directories in the pull request + id: get_changed_directories + shell: bash + run: | + set -ex + git checkout "${base_ref}" + git checkout "${head_ref}" + changed_directories="$(git diff --name-only ${base_ref} ${head_ref})" + if [[ ${changed_directories} =~ "library_generation/" ]]; then + echo "should_run=true" >> $GITHUB_OUTPUT + else + echo "should_run=false" >> $GITHUB_OUTPUT + fi + env: + base_ref: ${{ github.event.pull_request.base.ref }} + head_ref: ${{ github.event.pull_request.head.ref }} + library-generation-integration-tests: + runs-on: ubuntu-22.04 + needs: should-run-library-generation-tests + if: needs.should-run-library-generation-tests.outputs.should_run == 'true' steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 @@ -41,12 +65,14 @@ jobs: run: | set -x python -m unittest library_generation/test/integration_tests.py - unit_tests: + library-generation-unit-tests: + runs-on: ${{ matrix.os }} + needs: should-run-library-generation-tests + if: needs.should-run-library-generation-tests.outputs.should_run == 'true' strategy: matrix: java: [ 8 ] os: [ ubuntu-22.04, macos-12 ] - runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - name: install utils (macos) @@ -88,8 +114,10 @@ jobs: run: | set -x python -m unittest discover -s library_generation/test/ -p "*unit_tests.py" - lint-shell: + library-generation-lint-shell: runs-on: ubuntu-22.04 + needs: should-run-library-generation-tests + if: needs.should-run-library-generation-tests.outputs.should_run == 'true' steps: - uses: actions/checkout@v4 - name: Run ShellCheck @@ -98,8 +126,10 @@ jobs: scandir: 'library_generation' format: tty severity: error - lint-python: + library-generation-lint-python: runs-on: ubuntu-22.04 + needs: should-run-library-generation-tests + if: needs.should-run-library-generation-tests.outputs.should_run == 'true' steps: - uses: actions/checkout@v4 - name: install python dependencies diff --git a/gapic-generator-java/pom.xml b/gapic-generator-java/pom.xml index 923191445c..5b1145d0bd 100644 --- a/gapic-generator-java/pom.xml +++ b/gapic-generator-java/pom.xml @@ -351,7 +351,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.5.2 + 3.5.3 package diff --git a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/Composer.java b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/Composer.java index e92fd9b0c4..f2ffa56016 100644 --- a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/Composer.java +++ b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/Composer.java @@ -207,7 +207,7 @@ static List prepareExecutableSamples(List clazzes) { sample -> samples.add( addRegionTagAndHeaderToSample( - sample, gapicClass.apiShortName(), gapicClass.apiVersion()))); + sample, gapicClass.apiShortName(), gapicClass.packageVersion()))); clazzesWithSamples.add(gapicClass.withSamples(samples)); }); return clazzesWithSamples; diff --git a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java index 5f8456aa97..e8bd6fe081 100644 --- a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java +++ b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java @@ -173,7 +173,7 @@ public GapicClass generate(GapicContext context, Service service) { updateGapicMetadata(context, service, className, grpcRpcsToJavaMethodNames); return GapicClass.create(kind, classDef, SampleComposerUtil.handleDuplicateSamples(samples)) .withApiShortName(service.apiShortName()) - .withApiVersion(service.apiVersion()); + .withPackageVersion(service.packageVersion()); } private static List createClassAnnotations(Service service, TypeStore typeStore) { diff --git a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceSettingsClassComposer.java b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceSettingsClassComposer.java index c83bd54deb..60e3fcd38a 100644 --- a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceSettingsClassComposer.java +++ b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceSettingsClassComposer.java @@ -128,7 +128,7 @@ public GapicClass generate(GapicContext context, Service service) { .build(); return GapicClass.create(kind, classDef, SampleComposerUtil.handleDuplicateSamples(samples)) .withApiShortName(service.apiShortName()) - .withApiVersion(service.apiVersion()); + .withPackageVersion(service.packageVersion()); } private static List createClassHeaderComments( diff --git a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubSettingsClassComposer.java b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubSettingsClassComposer.java index f8c00131be..c13bc5f3f1 100644 --- a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubSettingsClassComposer.java +++ b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubSettingsClassComposer.java @@ -204,7 +204,7 @@ public GapicClass generate(GapicContext context, Service service) { return GapicClass.create( GapicClass.Kind.STUB, classDef, SampleComposerUtil.handleDuplicateSamples(samples)) .withApiShortName(service.apiShortName()) - .withApiVersion(service.apiVersion()); + .withPackageVersion(service.packageVersion()); } protected MethodDefinition createDefaultCredentialsProviderBuilderMethod() { @@ -370,6 +370,16 @@ protected MethodDefinition createApiClientHeaderProviderBuilderMethod( .setReturnType(returnType) .build(); + if (service.hasApiVersion()) { + + returnExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(returnExpr) + .setMethodName("setApiVersionToken") + .setArguments(ValueExpr.withValue(StringObjectValue.withValue(service.apiVersion()))) + .setReturnType(returnType) + .build(); + } return MethodDefinition.builder() .setScope(ScopeNode.PUBLIC) .setIsStatic(true) diff --git a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/GapicClass.java b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/GapicClass.java index 11d6598e7e..1fd06a8dfe 100644 --- a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/GapicClass.java +++ b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/GapicClass.java @@ -43,7 +43,7 @@ public enum Kind { public abstract String apiShortName(); // Only used for generating the region tag for samples; therefore only used in select Composers. - public abstract String apiVersion(); + public abstract String packageVersion(); /** * Create a GapicClass with minimal information. This is intended to be used for GapicClasses that @@ -76,7 +76,7 @@ static Builder builder() { return new AutoValue_GapicClass.Builder() .setSamples(Collections.emptyList()) .setApiShortName("") - .setApiVersion(""); + .setPackageVersion(""); } abstract Builder toBuilder(); @@ -89,8 +89,8 @@ public final GapicClass withApiShortName(String apiShortName) { return toBuilder().setApiShortName(apiShortName).build(); } - public final GapicClass withApiVersion(String apiVersion) { - return toBuilder().setApiVersion(apiVersion).build(); + public final GapicClass withPackageVersion(String packageVersion) { + return toBuilder().setPackageVersion(packageVersion).build(); } @AutoValue.Builder @@ -103,7 +103,7 @@ abstract static class Builder { abstract Builder setApiShortName(String apiShortName); - abstract Builder setApiVersion(String apiVersion); + abstract Builder setPackageVersion(String packageVersion); abstract GapicClass build(); } diff --git a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/Service.java b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/Service.java index b89d42b4d2..656bf6bbd3 100644 --- a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/Service.java +++ b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/Service.java @@ -27,6 +27,9 @@ public abstract class Service { public abstract String name(); + @Nullable + public abstract String apiVersion(); + public abstract String defaultHost(); public abstract ImmutableList oauthScopes(); @@ -52,6 +55,10 @@ public boolean hasDescription() { return !Strings.isNullOrEmpty(description()); } + public boolean hasApiVersion() { + return !Strings.isNullOrEmpty(apiVersion()); + } + public String hostServiceName() { // Host Service Name is guaranteed to exist and be non-null and non-empty // Parser will fail if the default host is not supplied @@ -65,9 +72,9 @@ public String apiShortName() { return ""; } - public String apiVersion() { + public String packageVersion() { if (!Strings.isNullOrEmpty(protoPakkage())) { - return parseApiVersion(protoPakkage()); + return parsePackageVersion(protoPakkage()); } return ""; } @@ -158,6 +165,8 @@ public abstract static class Builder { public abstract Builder setOverriddenName(String overriddenName); + public abstract Builder setApiVersion(String apiVersion); + public abstract Builder setDefaultHost(String defaultHost); public abstract Builder setOauthScopes(List oauthScopes); @@ -177,17 +186,17 @@ public abstract static class Builder { public abstract Service build(); } - private static String parseApiVersion(String protoPackage) { - // parse protoPackage for apiVersion + private static String parsePackageVersion(String protoPackage) { + // parse protoPackage for packageVersion String[] pakkage = protoPackage.split("\\."); - String apiVersion; + String packageVersion; // e.g. v1, v2, v1beta1 if (pakkage[pakkage.length - 1].matches("v[0-9].*")) { - apiVersion = pakkage[pakkage.length - 1]; + packageVersion = pakkage[pakkage.length - 1]; } else { - apiVersion = ""; + packageVersion = ""; } - return apiVersion; + return packageVersion; } // Parse the service name from the default host configured in the protos 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 e960ad3f6d..c7d0b95a3d 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 @@ -470,6 +470,11 @@ public static List parseService( } } + if (serviceOptions.hasExtension(ClientProto.apiVersion)) { + String apiVersion = serviceOptions.getExtension(ClientProto.apiVersion); + serviceBuilder.setApiVersion(apiVersion); + } + String serviceName = s.getName(); String overriddenServiceName = serviceName; String pakkage = TypeParser.getPackage(fileDescriptor); diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/ComposerTest.java b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/ComposerTest.java index bc99864bdd..66ad0584be 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/ComposerTest.java +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/ComposerTest.java @@ -45,7 +45,7 @@ public class ComposerTest { GrpcServiceCallableFactoryClassComposer.instance() .generate(context, echoProtoService) .withApiShortName(echoProtoService.apiShortName()) - .withApiVersion(echoProtoService.apiVersion())); + .withPackageVersion(echoProtoService.packageVersion())); private final Sample sample = Sample.builder() .setRegionTag( @@ -160,7 +160,7 @@ private List getTestClassListFromService(Service testService) { .generate(context, testService) .withSamples(ListofSamples) .withApiShortName(testService.apiShortName()) - .withApiVersion(testService.apiVersion()); + .withPackageVersion(testService.packageVersion()); List testClassList = Arrays.asList(new GapicClass[] {testClass}); return testClassList; } diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceClientClassComposerTest.java b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceClientClassComposerTest.java index 8da1e5015c..151ccb578d 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceClientClassComposerTest.java +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceClientClassComposerTest.java @@ -72,7 +72,7 @@ public static Collection data() { public String apiShortNameExpected; @Parameterized.Parameter(3) - public String apiVersionExpected; + public String packageVersionExpected; @Test public void generateServiceClientClasses() { @@ -83,6 +83,6 @@ public void generateServiceClientClasses() { Assert.assertGoldenSamples( this.getClass(), name, clazz.classDefinition().packageString(), clazz.samples()); Assert.assertCodeEquals(clazz.apiShortName(), apiShortNameExpected); - Assert.assertCodeEquals(clazz.apiVersion(), apiVersionExpected); + Assert.assertCodeEquals(clazz.packageVersion(), packageVersionExpected); } } diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceSettingsClassComposerTest.java b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceSettingsClassComposerTest.java index 9a9f4fb2e1..7a955fecd3 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceSettingsClassComposerTest.java +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceSettingsClassComposerTest.java @@ -55,7 +55,7 @@ public static Collection data() { public String apiShortNameExpected; @Parameterized.Parameter(3) - public String apiVersionExpected; + public String packageVersionExpected; @Test public void generateServiceSettingsClasses() { @@ -69,6 +69,6 @@ public void generateServiceSettingsClasses() { clazz.classDefinition().packageString(), clazz.samples()); Assert.assertCodeEquals(clazz.apiShortName(), apiShortNameExpected); - Assert.assertCodeEquals(clazz.apiVersion(), apiVersionExpected); + Assert.assertCodeEquals(clazz.packageVersion(), packageVersionExpected); } } diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceStubClassComposerTest.java b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceStubClassComposerTest.java index 387dba166f..8984c3550c 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceStubClassComposerTest.java +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceStubClassComposerTest.java @@ -45,7 +45,7 @@ public static Collection data() { public String apiShortNameExpected; @Parameterized.Parameter(3) - public String apiVersionExpected; + public String packageVersionExpected; @Test public void generateServiceStubClasses() { @@ -55,6 +55,6 @@ public void generateServiceStubClasses() { Assert.assertGoldenClass(this.getClass(), clazz, name + ".golden"); Assert.assertEmptySamples(clazz.samples()); Assert.assertCodeEquals(clazz.apiShortName(), apiShortNameExpected); - Assert.assertCodeEquals(clazz.apiVersion(), apiVersionExpected); + Assert.assertCodeEquals(clazz.packageVersion(), packageVersionExpected); } } diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceStubSettingsClassComposerTest.java b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceStubSettingsClassComposerTest.java index d552342d67..bfce68a45a 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceStubSettingsClassComposerTest.java +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceStubSettingsClassComposerTest.java @@ -54,6 +54,12 @@ public static Collection data() { GrpcTestProtoLoader.instance().parseDeprecatedService(), "localhost:7469", "v1" + }, + { + "ApiVersionTestingStubSettings", + GrpcTestProtoLoader.instance().parseApiVersionTesting(), + "localhost:7469", + "v1" } }); } @@ -67,7 +73,7 @@ public static Collection data() { public String apiShortNameExpected; @Parameterized.Parameter(3) - public String apiVersionExpected; + public String packageVersionExpected; @Test public void generateServiceStubSettingsClasses() { @@ -81,6 +87,6 @@ public void generateServiceStubSettingsClasses() { clazz.classDefinition().packageString(), clazz.samples()); Assert.assertCodeEquals(clazz.apiShortName(), apiShortNameExpected); - Assert.assertCodeEquals(clazz.apiVersion(), apiVersionExpected); + Assert.assertCodeEquals(clazz.packageVersion(), packageVersionExpected); } } diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/ApiVersionTestingStubSettings.golden b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/ApiVersionTestingStubSettings.golden new file mode 100644 index 0000000000..c67187cf5e --- /dev/null +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/ApiVersionTestingStubSettings.golden @@ -0,0 +1,248 @@ +package com.google.api.version.test.stub; + +import com.google.api.core.ApiFunction; +import com.google.api.gax.core.GaxProperties; +import com.google.api.gax.core.GoogleCredentialsProvider; +import com.google.api.gax.core.InstantiatingExecutorProvider; +import com.google.api.gax.grpc.GaxGrpcProperties; +import com.google.api.gax.grpc.GrpcTransportChannel; +import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider; +import com.google.api.gax.retrying.RetrySettings; +import com.google.api.gax.rpc.ApiClientHeaderProvider; +import com.google.api.gax.rpc.ClientContext; +import com.google.api.gax.rpc.StatusCode; +import com.google.api.gax.rpc.StubSettings; +import com.google.api.gax.rpc.TransportChannelProvider; +import com.google.api.gax.rpc.UnaryCallSettings; +import com.google.api.version.test.EchoRequest; +import com.google.api.version.test.EchoResponse; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import java.io.IOException; +import java.util.List; +import javax.annotation.Generated; + +// AUTO-GENERATED DOCUMENTATION AND CLASS. +/** + * Settings class to configure an instance of {@link EchoWithVersionStub}. + * + *

The default instance has everything set to sensible defaults: + * + *

    + *
  • The default service address (localhost) and default port (7469) are used. + *
  • Credentials are acquired automatically through Application Default Credentials. + *
  • Retries are configured for idempotent methods but not for non-idempotent methods. + *
+ * + *

The builder of this class is recursive, so contained classes are themselves builders. When + * build() is called, the tree of builders is called to create the complete settings object. + * + *

For example, to set the total timeout of echoWithVersionMethod to 30 seconds: + * + *

{@code
+ * // This snippet has been automatically generated and should be regarded as a code template only.
+ * // It will require modifications to work:
+ * // - It may require correct/in-range values for request initialization.
+ * // - It may require specifying regional endpoints when creating the service client as shown in
+ * // https://cloud.google.com/java/docs/setup#configure_endpoints_for_the_client_library
+ * EchoWithVersionStubSettings.Builder echoWithVersionSettingsBuilder =
+ *     EchoWithVersionStubSettings.newBuilder();
+ * echoWithVersionSettingsBuilder
+ *     .echoWithVersionMethodSettings()
+ *     .setRetrySettings(
+ *         echoWithVersionSettingsBuilder
+ *             .echoWithVersionMethodSettings()
+ *             .getRetrySettings()
+ *             .toBuilder()
+ *             .setTotalTimeout(Duration.ofSeconds(30))
+ *             .build());
+ * EchoWithVersionStubSettings echoWithVersionSettings = echoWithVersionSettingsBuilder.build();
+ * }
+ */ +@Generated("by gapic-generator-java") +public class EchoWithVersionStubSettings extends StubSettings { + /** The default scopes of the service. */ + private static final ImmutableList DEFAULT_SERVICE_SCOPES = + ImmutableList.builder().add("https://www.googleapis.com/auth/cloud-platform").build(); + + private final UnaryCallSettings echoWithVersionMethodSettings; + + /** Returns the object with the settings used for calls to echoWithVersionMethod. */ + public UnaryCallSettings echoWithVersionMethodSettings() { + return echoWithVersionMethodSettings; + } + + public EchoWithVersionStub createStub() throws IOException { + if (getTransportChannelProvider() + .getTransportName() + .equals(GrpcTransportChannel.getGrpcTransportName())) { + return GrpcEchoWithVersionStub.create(this); + } + throw new UnsupportedOperationException( + String.format( + "Transport not supported: %s", getTransportChannelProvider().getTransportName())); + } + + /** Returns a builder for the default ExecutorProvider for this service. */ + public static InstantiatingExecutorProvider.Builder defaultExecutorProviderBuilder() { + return InstantiatingExecutorProvider.newBuilder(); + } + + /** Returns the default service endpoint. */ + public static String getDefaultEndpoint() { + return "localhost:7469"; + } + + /** Returns the default mTLS service endpoint. */ + public static String getDefaultMtlsEndpoint() { + return "localhost:7469"; + } + + /** Returns the default service scopes. */ + public static List getDefaultServiceScopes() { + return DEFAULT_SERVICE_SCOPES; + } + + /** Returns a builder for the default credentials for this service. */ + public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); + } + + /** Returns a builder for the default ChannelProvider for this service. */ + public static InstantiatingGrpcChannelProvider.Builder defaultGrpcTransportProviderBuilder() { + return InstantiatingGrpcChannelProvider.newBuilder() + .setMaxInboundMessageSize(Integer.MAX_VALUE); + } + + public static TransportChannelProvider defaultTransportChannelProvider() { + return defaultGrpcTransportProviderBuilder().build(); + } + + public static ApiClientHeaderProvider.Builder defaultApiClientHeaderProviderBuilder() { + return ApiClientHeaderProvider.newBuilder() + .setGeneratedLibToken( + "gapic", GaxProperties.getLibraryVersion(EchoWithVersionStubSettings.class)) + .setTransportToken(GaxGrpcProperties.getGrpcTokenName(), GaxGrpcProperties.getGrpcVersion()) + .setApiVersionToken("fake_version"); + } + + /** Returns a new builder for this class. */ + public static Builder newBuilder() { + return Builder.createDefault(); + } + + /** Returns a new builder for this class. */ + public static Builder newBuilder(ClientContext clientContext) { + return new Builder(clientContext); + } + + /** Returns a builder containing all the values of this settings class. */ + public Builder toBuilder() { + return new Builder(this); + } + + protected EchoWithVersionStubSettings(Builder settingsBuilder) throws IOException { + super(settingsBuilder); + + echoWithVersionMethodSettings = settingsBuilder.echoWithVersionMethodSettings().build(); + } + + /** Builder for EchoWithVersionStubSettings. */ + public static class Builder extends StubSettings.Builder { + private final ImmutableList> unaryMethodSettingsBuilders; + private final UnaryCallSettings.Builder + echoWithVersionMethodSettings; + private static final ImmutableMap> + RETRYABLE_CODE_DEFINITIONS; + + static { + ImmutableMap.Builder> definitions = + ImmutableMap.builder(); + definitions.put("no_retry_codes", ImmutableSet.copyOf(Lists.newArrayList())); + RETRYABLE_CODE_DEFINITIONS = definitions.build(); + } + + private static final ImmutableMap RETRY_PARAM_DEFINITIONS; + + static { + ImmutableMap.Builder definitions = ImmutableMap.builder(); + RetrySettings settings = null; + settings = RetrySettings.newBuilder().setRpcTimeoutMultiplier(1.0).build(); + definitions.put("no_retry_params", settings); + RETRY_PARAM_DEFINITIONS = definitions.build(); + } + + protected Builder() { + this(((ClientContext) null)); + } + + protected Builder(ClientContext clientContext) { + super(clientContext); + + echoWithVersionMethodSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + + unaryMethodSettingsBuilders = + ImmutableList.>of(echoWithVersionMethodSettings); + initDefaults(this); + } + + protected Builder(EchoWithVersionStubSettings settings) { + super(settings); + + echoWithVersionMethodSettings = settings.echoWithVersionMethodSettings.toBuilder(); + + unaryMethodSettingsBuilders = + ImmutableList.>of(echoWithVersionMethodSettings); + } + + private static Builder createDefault() { + Builder builder = new Builder(((ClientContext) null)); + + builder.setTransportChannelProvider(defaultTransportChannelProvider()); + builder.setCredentialsProvider(defaultCredentialsProviderBuilder().build()); + builder.setInternalHeaderProvider(defaultApiClientHeaderProviderBuilder().build()); + builder.setMtlsEndpoint(getDefaultMtlsEndpoint()); + builder.setSwitchToMtlsEndpointAllowed(true); + + return initDefaults(builder); + } + + private static Builder initDefaults(Builder builder) { + builder + .echoWithVersionMethodSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_params")); + + return builder; + } + + /** + * Applies the given settings updater function to all of the unary API methods in this service. + * + *

Note: This method does not support applying settings to streaming methods. + */ + public Builder applyToAllUnaryMethods( + ApiFunction, Void> settingsUpdater) { + super.applyToAllUnaryMethods(unaryMethodSettingsBuilders, settingsUpdater); + return this; + } + + public ImmutableList> unaryMethodSettingsBuilders() { + return unaryMethodSettingsBuilders; + } + + /** Returns the builder for the settings used for calls to echoWithVersionMethod. */ + public UnaryCallSettings.Builder echoWithVersionMethodSettings() { + return echoWithVersionMethodSettings; + } + + @Override + public EchoWithVersionStubSettings build() throws IOException { + return new EchoWithVersionStubSettings(this); + } + } +} diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/samples/servicesettings/stub/SyncEchoWithVersionMethod.golden b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/samples/servicesettings/stub/SyncEchoWithVersionMethod.golden new file mode 100644 index 0000000000..fc298b28dc --- /dev/null +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/samples/servicesettings/stub/SyncEchoWithVersionMethod.golden @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package com.google.api.version.test.stub.samples; + +// [START goldensample_generated_EchoWithVersionStubSettings_EchoWithVersionMethod_sync] +import com.google.api.version.test.stub.EchoWithVersionStubSettings; +import java.time.Duration; + +public class SyncEchoWithVersionMethod { + + public static void main(String[] args) throws Exception { + syncEchoWithVersionMethod(); + } + + public static void syncEchoWithVersionMethod() throws Exception { + // This snippet has been automatically generated and should be regarded as a code template only. + // It will require modifications to work: + // - It may require correct/in-range values for request initialization. + // - It may require specifying regional endpoints when creating the service client as shown in + // https://cloud.google.com/java/docs/setup#configure_endpoints_for_the_client_library + EchoWithVersionStubSettings.Builder echoWithVersionSettingsBuilder = + EchoWithVersionStubSettings.newBuilder(); + echoWithVersionSettingsBuilder + .echoWithVersionMethodSettings() + .setRetrySettings( + echoWithVersionSettingsBuilder + .echoWithVersionMethodSettings() + .getRetrySettings() + .toBuilder() + .setTotalTimeout(Duration.ofSeconds(30)) + .build()); + EchoWithVersionStubSettings echoWithVersionSettings = echoWithVersionSettingsBuilder.build(); + } +} +// [END goldensample_generated_EchoWithVersionStubSettings_EchoWithVersionMethod_sync] diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpcrest/ServiceStubSettingsClassComposerTest.java b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpcrest/ServiceStubSettingsClassComposerTest.java index 388fa54648..c9439d525f 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpcrest/ServiceStubSettingsClassComposerTest.java +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpcrest/ServiceStubSettingsClassComposerTest.java @@ -23,37 +23,38 @@ import com.google.api.generator.test.protoloader.GrpcRestTestProtoLoader; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collection; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +@RunWith(Parameterized.class) public class ServiceStubSettingsClassComposerTest { + @Parameterized.Parameters + public static Collection data() { + return Arrays.asList( + new Object[][] { + {"EchoStubSettings.golden", GrpcRestTestProtoLoader.instance().parseShowcaseEcho()}, + {"WickedStubSettings.golden", GrpcRestTestProtoLoader.instance().parseShowcaseWicked()} + }); + } + + @Parameterized.Parameter public String goldenFileName; + + @Parameterized.Parameter(1) + public GapicContext context; + @Test public void generateServiceClasses() { - GapicContext context = GrpcRestTestProtoLoader.instance().parseShowcaseEcho(); Service echoProtoService = context.services().get(0); GapicClass clazz = ServiceStubSettingsClassComposer.instance().generate(context, echoProtoService); JavaWriterVisitor visitor = new JavaWriterVisitor(); clazz.classDefinition().accept(visitor); - GoldenFileWriter.saveCodegenToFile(this.getClass(), "EchoStubSettings.golden", visitor.write()); - Path goldenFilePath = - Paths.get(GoldenFileWriter.getGoldenDir(this.getClass()), "EchoStubSettings.golden"); - Assert.assertCodeEquals(goldenFilePath, visitor.write()); - } - - @Test - public void generateServiceClassesWicked() { - GapicContext context = GrpcRestTestProtoLoader.instance().parseShowcaseWicked(); - Service wickedProtoService = context.services().get(0); - GapicClass clazz = - ServiceStubSettingsClassComposer.instance().generate(context, wickedProtoService); - - JavaWriterVisitor visitor = new JavaWriterVisitor(); - clazz.classDefinition().accept(visitor); - GoldenFileWriter.saveCodegenToFile( - this.getClass(), "WickedStubSettings.golden", visitor.write()); - Path goldenFilePath = - Paths.get(GoldenFileWriter.getGoldenDir(this.getClass()), "WickedStubSettings.golden"); + GoldenFileWriter.saveCodegenToFile(this.getClass(), goldenFileName, visitor.write()); + Path goldenFilePath = Paths.get(GoldenFileWriter.getGoldenDir(this.getClass()), goldenFileName); Assert.assertCodeEquals(goldenFilePath, visitor.write()); } } diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpcrest/goldens/EchoStubSettings.golden b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpcrest/goldens/EchoStubSettings.golden index fefa7643ba..565f38a483 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpcrest/goldens/EchoStubSettings.golden +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpcrest/goldens/EchoStubSettings.golden @@ -348,8 +348,8 @@ public class EchoStubSettings extends StubSettings { public static ApiClientHeaderProvider.Builder defaultGrpcApiClientHeaderProviderBuilder() { return ApiClientHeaderProvider.newBuilder() .setGeneratedLibToken("gapic", GaxProperties.getLibraryVersion(EchoStubSettings.class)) - .setTransportToken( - GaxGrpcProperties.getGrpcTokenName(), GaxGrpcProperties.getGrpcVersion()); + .setTransportToken(GaxGrpcProperties.getGrpcTokenName(), GaxGrpcProperties.getGrpcVersion()) + .setApiVersionToken("foo_version_for_tests"); } public static ApiClientHeaderProvider.Builder defaultHttpJsonApiClientHeaderProviderBuilder() { @@ -357,7 +357,8 @@ public class EchoStubSettings extends StubSettings { .setGeneratedLibToken("gapic", GaxProperties.getLibraryVersion(EchoStubSettings.class)) .setTransportToken( GaxHttpJsonProperties.getHttpJsonTokenName(), - GaxHttpJsonProperties.getHttpJsonVersion()); + GaxHttpJsonProperties.getHttpJsonVersion()) + .setApiVersionToken("foo_version_for_tests"); } public static ApiClientHeaderProvider.Builder defaultApiClientHeaderProviderBuilder() { diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/rest/ServiceStubSettingsClassComposerTest.java b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/rest/ServiceStubSettingsClassComposerTest.java index 1869a893fe..d2ac3b813a 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/rest/ServiceStubSettingsClassComposerTest.java +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/rest/ServiceStubSettingsClassComposerTest.java @@ -23,22 +23,41 @@ import com.google.api.generator.test.protoloader.RestTestProtoLoader; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collection; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +@RunWith(Parameterized.class) public class ServiceStubSettingsClassComposerTest { + + @Parameterized.Parameters + public static Collection data() { + return Arrays.asList( + new Object[][] { + {"ComplianceStubSettings.golden", RestTestProtoLoader.instance().parseCompliance()}, + { + "HttpJsonApiVersionTestingStubSettings.golden", + RestTestProtoLoader.instance().parseApiVersionTesting() + } + }); + } + + @Parameterized.Parameter public String goldenFileName; + + @Parameterized.Parameter(1) + public GapicContext context; + @Test public void generateServiceClasses() { - GapicContext context = RestTestProtoLoader.instance().parseCompliance(); - Service echoProtoService = context.services().get(0); - GapicClass clazz = - ServiceStubSettingsClassComposer.instance().generate(context, echoProtoService); + Service protoService = context.services().get(0); + GapicClass clazz = ServiceStubSettingsClassComposer.instance().generate(context, protoService); JavaWriterVisitor visitor = new JavaWriterVisitor(); clazz.classDefinition().accept(visitor); - GoldenFileWriter.saveCodegenToFile( - this.getClass(), "ComplianceStubSettings.golden", visitor.write()); - Path goldenFilePath = - Paths.get(GoldenFileWriter.getGoldenDir(this.getClass()), "ComplianceStubSettings.golden"); + GoldenFileWriter.saveCodegenToFile(this.getClass(), goldenFileName, visitor.write()); + Path goldenFilePath = Paths.get(GoldenFileWriter.getGoldenDir(this.getClass()), goldenFileName); Assert.assertCodeEquals(goldenFilePath, visitor.write()); } } diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonApiVersionTestingStubSettings.golden b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonApiVersionTestingStubSettings.golden new file mode 100644 index 0000000000..219800efd4 --- /dev/null +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonApiVersionTestingStubSettings.golden @@ -0,0 +1,250 @@ +package com.google.api.version.test.stub; + +import com.google.api.core.ApiFunction; +import com.google.api.gax.core.GaxProperties; +import com.google.api.gax.core.GoogleCredentialsProvider; +import com.google.api.gax.core.InstantiatingExecutorProvider; +import com.google.api.gax.httpjson.GaxHttpJsonProperties; +import com.google.api.gax.httpjson.HttpJsonTransportChannel; +import com.google.api.gax.httpjson.InstantiatingHttpJsonChannelProvider; +import com.google.api.gax.retrying.RetrySettings; +import com.google.api.gax.rpc.ApiClientHeaderProvider; +import com.google.api.gax.rpc.ClientContext; +import com.google.api.gax.rpc.StatusCode; +import com.google.api.gax.rpc.StubSettings; +import com.google.api.gax.rpc.TransportChannelProvider; +import com.google.api.gax.rpc.UnaryCallSettings; +import com.google.api.version.test.EchoRequest; +import com.google.api.version.test.EchoResponse; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import java.io.IOException; +import java.util.List; +import javax.annotation.Generated; + +// AUTO-GENERATED DOCUMENTATION AND CLASS. +/** + * Settings class to configure an instance of {@link EchoWithVersionStub}. + * + *

The default instance has everything set to sensible defaults: + * + *

    + *
  • The default service address (localhost) and default port (7469) are used. + *
  • Credentials are acquired automatically through Application Default Credentials. + *
  • Retries are configured for idempotent methods but not for non-idempotent methods. + *
+ * + *

The builder of this class is recursive, so contained classes are themselves builders. When + * build() is called, the tree of builders is called to create the complete settings object. + * + *

For example, to set the total timeout of echoWithVersionMethod to 30 seconds: + * + *

{@code
+ * // This snippet has been automatically generated and should be regarded as a code template only.
+ * // It will require modifications to work:
+ * // - It may require correct/in-range values for request initialization.
+ * // - It may require specifying regional endpoints when creating the service client as shown in
+ * // https://cloud.google.com/java/docs/setup#configure_endpoints_for_the_client_library
+ * EchoWithVersionStubSettings.Builder echoWithVersionSettingsBuilder =
+ *     EchoWithVersionStubSettings.newBuilder();
+ * echoWithVersionSettingsBuilder
+ *     .echoWithVersionMethodSettings()
+ *     .setRetrySettings(
+ *         echoWithVersionSettingsBuilder
+ *             .echoWithVersionMethodSettings()
+ *             .getRetrySettings()
+ *             .toBuilder()
+ *             .setTotalTimeout(Duration.ofSeconds(30))
+ *             .build());
+ * EchoWithVersionStubSettings echoWithVersionSettings = echoWithVersionSettingsBuilder.build();
+ * }
+ */ +@Generated("by gapic-generator-java") +public class EchoWithVersionStubSettings extends StubSettings { + /** The default scopes of the service. */ + private static final ImmutableList DEFAULT_SERVICE_SCOPES = + ImmutableList.builder().add("https://www.googleapis.com/auth/cloud-platform").build(); + + private final UnaryCallSettings echoWithVersionMethodSettings; + + /** Returns the object with the settings used for calls to echoWithVersionMethod. */ + public UnaryCallSettings echoWithVersionMethodSettings() { + return echoWithVersionMethodSettings; + } + + public EchoWithVersionStub createStub() throws IOException { + if (getTransportChannelProvider() + .getTransportName() + .equals(HttpJsonTransportChannel.getHttpJsonTransportName())) { + return HttpJsonEchoWithVersionStub.create(this); + } + throw new UnsupportedOperationException( + String.format( + "Transport not supported: %s", getTransportChannelProvider().getTransportName())); + } + + /** Returns a builder for the default ExecutorProvider for this service. */ + public static InstantiatingExecutorProvider.Builder defaultExecutorProviderBuilder() { + return InstantiatingExecutorProvider.newBuilder(); + } + + /** Returns the default service endpoint. */ + public static String getDefaultEndpoint() { + return "localhost:7469"; + } + + /** Returns the default mTLS service endpoint. */ + public static String getDefaultMtlsEndpoint() { + return "localhost:7469"; + } + + /** Returns the default service scopes. */ + public static List getDefaultServiceScopes() { + return DEFAULT_SERVICE_SCOPES; + } + + /** Returns a builder for the default credentials for this service. */ + public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); + } + + /** Returns a builder for the default ChannelProvider for this service. */ + public static InstantiatingHttpJsonChannelProvider.Builder + defaultHttpJsonTransportProviderBuilder() { + return InstantiatingHttpJsonChannelProvider.newBuilder(); + } + + public static TransportChannelProvider defaultTransportChannelProvider() { + return defaultHttpJsonTransportProviderBuilder().build(); + } + + public static ApiClientHeaderProvider.Builder defaultApiClientHeaderProviderBuilder() { + return ApiClientHeaderProvider.newBuilder() + .setGeneratedLibToken( + "gapic", GaxProperties.getLibraryVersion(EchoWithVersionStubSettings.class)) + .setTransportToken( + GaxHttpJsonProperties.getHttpJsonTokenName(), + GaxHttpJsonProperties.getHttpJsonVersion()) + .setApiVersionToken("fake_version"); + } + + /** Returns a new builder for this class. */ + public static Builder newBuilder() { + return Builder.createDefault(); + } + + /** Returns a new builder for this class. */ + public static Builder newBuilder(ClientContext clientContext) { + return new Builder(clientContext); + } + + /** Returns a builder containing all the values of this settings class. */ + public Builder toBuilder() { + return new Builder(this); + } + + protected EchoWithVersionStubSettings(Builder settingsBuilder) throws IOException { + super(settingsBuilder); + + echoWithVersionMethodSettings = settingsBuilder.echoWithVersionMethodSettings().build(); + } + + /** Builder for EchoWithVersionStubSettings. */ + public static class Builder extends StubSettings.Builder { + private final ImmutableList> unaryMethodSettingsBuilders; + private final UnaryCallSettings.Builder + echoWithVersionMethodSettings; + private static final ImmutableMap> + RETRYABLE_CODE_DEFINITIONS; + + static { + ImmutableMap.Builder> definitions = + ImmutableMap.builder(); + definitions.put("no_retry_codes", ImmutableSet.copyOf(Lists.newArrayList())); + RETRYABLE_CODE_DEFINITIONS = definitions.build(); + } + + private static final ImmutableMap RETRY_PARAM_DEFINITIONS; + + static { + ImmutableMap.Builder definitions = ImmutableMap.builder(); + RetrySettings settings = null; + settings = RetrySettings.newBuilder().setRpcTimeoutMultiplier(1.0).build(); + definitions.put("no_retry_params", settings); + RETRY_PARAM_DEFINITIONS = definitions.build(); + } + + protected Builder() { + this(((ClientContext) null)); + } + + protected Builder(ClientContext clientContext) { + super(clientContext); + + echoWithVersionMethodSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + + unaryMethodSettingsBuilders = + ImmutableList.>of(echoWithVersionMethodSettings); + initDefaults(this); + } + + protected Builder(EchoWithVersionStubSettings settings) { + super(settings); + + echoWithVersionMethodSettings = settings.echoWithVersionMethodSettings.toBuilder(); + + unaryMethodSettingsBuilders = + ImmutableList.>of(echoWithVersionMethodSettings); + } + + private static Builder createDefault() { + Builder builder = new Builder(((ClientContext) null)); + + builder.setTransportChannelProvider(defaultTransportChannelProvider()); + builder.setCredentialsProvider(defaultCredentialsProviderBuilder().build()); + builder.setInternalHeaderProvider(defaultApiClientHeaderProviderBuilder().build()); + builder.setMtlsEndpoint(getDefaultMtlsEndpoint()); + builder.setSwitchToMtlsEndpointAllowed(true); + + return initDefaults(builder); + } + + private static Builder initDefaults(Builder builder) { + builder + .echoWithVersionMethodSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_params")); + + return builder; + } + + /** + * Applies the given settings updater function to all of the unary API methods in this service. + * + *

Note: This method does not support applying settings to streaming methods. + */ + public Builder applyToAllUnaryMethods( + ApiFunction, Void> settingsUpdater) { + super.applyToAllUnaryMethods(unaryMethodSettingsBuilders, settingsUpdater); + return this; + } + + public ImmutableList> unaryMethodSettingsBuilders() { + return unaryMethodSettingsBuilders; + } + + /** Returns the builder for the settings used for calls to echoWithVersionMethod. */ + public UnaryCallSettings.Builder echoWithVersionMethodSettings() { + return echoWithVersionMethodSettings; + } + + @Override + public EchoWithVersionStubSettings build() throws IOException { + return new EchoWithVersionStubSettings(this); + } + } +} diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonEchoStubSettings.golden b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonEchoStubSettings.golden new file mode 100644 index 0000000000..0c788d7ebd --- /dev/null +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonEchoStubSettings.golden @@ -0,0 +1,635 @@ +package com.google.showcase.v1beta1.stub; + +import static com.google.showcase.v1beta1.EchoClient.PagedExpandPagedResponse; +import static com.google.showcase.v1beta1.EchoClient.SimplePagedExpandPagedResponse; + +import com.google.api.core.ApiFunction; +import com.google.api.core.ApiFuture; +import com.google.api.core.BetaApi; +import com.google.api.gax.core.GaxProperties; +import com.google.api.gax.core.GoogleCredentialsProvider; +import com.google.api.gax.core.InstantiatingExecutorProvider; +import com.google.api.gax.httpjson.GaxHttpJsonProperties; +import com.google.api.gax.httpjson.HttpJsonTransportChannel; +import com.google.api.gax.httpjson.InstantiatingHttpJsonChannelProvider; +import com.google.api.gax.httpjson.ProtoOperationTransformers; +import com.google.api.gax.longrunning.OperationSnapshot; +import com.google.api.gax.longrunning.OperationTimedPollAlgorithm; +import com.google.api.gax.retrying.RetrySettings; +import com.google.api.gax.rpc.ApiCallContext; +import com.google.api.gax.rpc.ApiClientHeaderProvider; +import com.google.api.gax.rpc.ClientContext; +import com.google.api.gax.rpc.OperationCallSettings; +import com.google.api.gax.rpc.PageContext; +import com.google.api.gax.rpc.PagedCallSettings; +import com.google.api.gax.rpc.PagedListDescriptor; +import com.google.api.gax.rpc.PagedListResponseFactory; +import com.google.api.gax.rpc.ServerStreamingCallSettings; +import com.google.api.gax.rpc.StatusCode; +import com.google.api.gax.rpc.StreamingCallSettings; +import com.google.api.gax.rpc.StubSettings; +import com.google.api.gax.rpc.TransportChannelProvider; +import com.google.api.gax.rpc.UnaryCallSettings; +import com.google.api.gax.rpc.UnaryCallable; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.longrunning.Operation; +import com.google.showcase.v1beta1.BlockRequest; +import com.google.showcase.v1beta1.BlockResponse; +import com.google.showcase.v1beta1.EchoRequest; +import com.google.showcase.v1beta1.EchoResponse; +import com.google.showcase.v1beta1.ExpandRequest; +import com.google.showcase.v1beta1.Object; +import com.google.showcase.v1beta1.PagedExpandRequest; +import com.google.showcase.v1beta1.PagedExpandResponse; +import com.google.showcase.v1beta1.WaitMetadata; +import com.google.showcase.v1beta1.WaitRequest; +import com.google.showcase.v1beta1.WaitResponse; +import java.io.IOException; +import java.util.List; +import javax.annotation.Generated; +import org.threeten.bp.Duration; + +// AUTO-GENERATED DOCUMENTATION AND CLASS. +/** + * Settings class to configure an instance of {@link EchoStub}. + * + *

The default instance has everything set to sensible defaults: + * + *

    + *
  • The default service address (localhost) and default port (7469) are used. + *
  • Credentials are acquired automatically through Application Default Credentials. + *
  • Retries are configured for idempotent methods but not for non-idempotent methods. + *
+ * + *

The builder of this class is recursive, so contained classes are themselves builders. When + * build() is called, the tree of builders is called to create the complete settings object. + * + *

For example, to set the total timeout of echo to 30 seconds: + * + *

{@code
+ * // This snippet has been automatically generated and should be regarded as a code template only.
+ * // It will require modifications to work:
+ * // - It may require correct/in-range values for request initialization.
+ * // - It may require specifying regional endpoints when creating the service client as shown in
+ * // https://cloud.google.com/java/docs/setup#configure_endpoints_for_the_client_library
+ * EchoStubSettings.Builder echoSettingsBuilder = EchoStubSettings.newBuilder();
+ * echoSettingsBuilder
+ *     .echoSettings()
+ *     .setRetrySettings(
+ *         echoSettingsBuilder
+ *             .echoSettings()
+ *             .getRetrySettings()
+ *             .toBuilder()
+ *             .setTotalTimeout(Duration.ofSeconds(30))
+ *             .build());
+ * EchoStubSettings echoSettings = echoSettingsBuilder.build();
+ * }
+ */ +@BetaApi +@Generated("by gapic-generator-java") +public class EchoStubSettings extends StubSettings { + /** The default scopes of the service. */ + private static final ImmutableList DEFAULT_SERVICE_SCOPES = + ImmutableList.builder().add("https://www.googleapis.com/auth/cloud-platform").build(); + + private final UnaryCallSettings echoSettings; + private final ServerStreamingCallSettings expandSettings; + private final StreamingCallSettings collectSettings; + private final StreamingCallSettings chatSettings; + private final StreamingCallSettings chatAgainSettings; + private final PagedCallSettings + pagedExpandSettings; + private final PagedCallSettings< + PagedExpandRequest, PagedExpandResponse, SimplePagedExpandPagedResponse> + simplePagedExpandSettings; + private final UnaryCallSettings waitSettings; + private final OperationCallSettings + waitOperationSettings; + private final UnaryCallSettings blockSettings; + private final UnaryCallSettings collideNameSettings; + + private static final PagedListDescriptor + PAGED_EXPAND_PAGE_STR_DESC = + new PagedListDescriptor() { + @Override + public String emptyToken() { + return ""; + } + + @Override + public PagedExpandRequest injectToken(PagedExpandRequest payload, String token) { + return PagedExpandRequest.newBuilder(payload).setPageToken(token).build(); + } + + @Override + public PagedExpandRequest injectPageSize(PagedExpandRequest payload, int pageSize) { + return PagedExpandRequest.newBuilder(payload).setPageSize(pageSize).build(); + } + + @Override + public Integer extractPageSize(PagedExpandRequest payload) { + return payload.getPageSize(); + } + + @Override + public String extractNextToken(PagedExpandResponse payload) { + return payload.getNextPageToken(); + } + + @Override + public Iterable extractResources(PagedExpandResponse payload) { + return payload.getResponsesList() == null + ? ImmutableList.of() + : payload.getResponsesList(); + } + }; + + private static final PagedListDescriptor + SIMPLE_PAGED_EXPAND_PAGE_STR_DESC = + new PagedListDescriptor() { + @Override + public String emptyToken() { + return ""; + } + + @Override + public PagedExpandRequest injectToken(PagedExpandRequest payload, String token) { + return PagedExpandRequest.newBuilder(payload).setPageToken(token).build(); + } + + @Override + public PagedExpandRequest injectPageSize(PagedExpandRequest payload, int pageSize) { + return PagedExpandRequest.newBuilder(payload).setPageSize(pageSize).build(); + } + + @Override + public Integer extractPageSize(PagedExpandRequest payload) { + return payload.getPageSize(); + } + + @Override + public String extractNextToken(PagedExpandResponse payload) { + return payload.getNextPageToken(); + } + + @Override + public Iterable extractResources(PagedExpandResponse payload) { + return payload.getResponsesList() == null + ? ImmutableList.of() + : payload.getResponsesList(); + } + }; + + private static final PagedListResponseFactory< + PagedExpandRequest, PagedExpandResponse, PagedExpandPagedResponse> + PAGED_EXPAND_PAGE_STR_FACT = + new PagedListResponseFactory< + PagedExpandRequest, PagedExpandResponse, PagedExpandPagedResponse>() { + @Override + public ApiFuture getFuturePagedResponse( + UnaryCallable callable, + PagedExpandRequest request, + ApiCallContext context, + ApiFuture futureResponse) { + PageContext pageContext = + PageContext.create(callable, PAGED_EXPAND_PAGE_STR_DESC, request, context); + return PagedExpandPagedResponse.createAsync(pageContext, futureResponse); + } + }; + + private static final PagedListResponseFactory< + PagedExpandRequest, PagedExpandResponse, SimplePagedExpandPagedResponse> + SIMPLE_PAGED_EXPAND_PAGE_STR_FACT = + new PagedListResponseFactory< + PagedExpandRequest, PagedExpandResponse, SimplePagedExpandPagedResponse>() { + @Override + public ApiFuture getFuturePagedResponse( + UnaryCallable callable, + PagedExpandRequest request, + ApiCallContext context, + ApiFuture futureResponse) { + PageContext pageContext = + PageContext.create(callable, SIMPLE_PAGED_EXPAND_PAGE_STR_DESC, request, context); + return SimplePagedExpandPagedResponse.createAsync(pageContext, futureResponse); + } + }; + + /** Returns the object with the settings used for calls to echo. */ + public UnaryCallSettings echoSettings() { + return echoSettings; + } + + /** Returns the object with the settings used for calls to expand. */ + public ServerStreamingCallSettings expandSettings() { + return expandSettings; + } + + /** Returns the object with the settings used for calls to collect. */ + public StreamingCallSettings collectSettings() { + return collectSettings; + } + + /** Returns the object with the settings used for calls to chat. */ + public StreamingCallSettings chatSettings() { + return chatSettings; + } + + /** Returns the object with the settings used for calls to chatAgain. */ + public StreamingCallSettings chatAgainSettings() { + return chatAgainSettings; + } + + /** Returns the object with the settings used for calls to pagedExpand. */ + public PagedCallSettings + pagedExpandSettings() { + return pagedExpandSettings; + } + + /** Returns the object with the settings used for calls to simplePagedExpand. */ + public PagedCallSettings + simplePagedExpandSettings() { + return simplePagedExpandSettings; + } + + /** Returns the object with the settings used for calls to wait. */ + public UnaryCallSettings waitSettings() { + return waitSettings; + } + + /** Returns the object with the settings used for calls to wait. */ + public OperationCallSettings waitOperationSettings() { + return waitOperationSettings; + } + + /** Returns the object with the settings used for calls to block. */ + public UnaryCallSettings blockSettings() { + return blockSettings; + } + + /** Returns the object with the settings used for calls to collideName. */ + public UnaryCallSettings collideNameSettings() { + return collideNameSettings; + } + + public EchoStub createStub() throws IOException { + if (getTransportChannelProvider() + .getTransportName() + .equals(HttpJsonTransportChannel.getHttpJsonTransportName())) { + return HttpJsonEchoStub.create(this); + } + throw new UnsupportedOperationException( + String.format( + "Transport not supported: %s", getTransportChannelProvider().getTransportName())); + } + + /** Returns a builder for the default ExecutorProvider for this service. */ + public static InstantiatingExecutorProvider.Builder defaultExecutorProviderBuilder() { + return InstantiatingExecutorProvider.newBuilder(); + } + + /** Returns the default service endpoint. */ + public static String getDefaultEndpoint() { + return "localhost:7469"; + } + + /** Returns the default mTLS service endpoint. */ + public static String getDefaultMtlsEndpoint() { + return "localhost:7469"; + } + + /** Returns the default service scopes. */ + public static List getDefaultServiceScopes() { + return DEFAULT_SERVICE_SCOPES; + } + + /** Returns a builder for the default credentials for this service. */ + public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); + } + + /** Returns a builder for the default ChannelProvider for this service. */ + public static InstantiatingHttpJsonChannelProvider.Builder + defaultHttpJsonTransportProviderBuilder() { + return InstantiatingHttpJsonChannelProvider.newBuilder(); + } + + public static TransportChannelProvider defaultTransportChannelProvider() { + return defaultHttpJsonTransportProviderBuilder().build(); + } + + public static ApiClientHeaderProvider.Builder defaultApiClientHeaderProviderBuilder() { + return ApiClientHeaderProvider.newBuilder() + .setGeneratedLibToken("gapic", GaxProperties.getLibraryVersion(EchoStubSettings.class)) + .setTransportToken( + GaxHttpJsonProperties.getHttpJsonTokenName(), + GaxHttpJsonProperties.getHttpJsonVersion()); + } + + /** Returns a new builder for this class. */ + public static Builder newBuilder() { + return Builder.createDefault(); + } + + /** Returns a new builder for this class. */ + public static Builder newBuilder(ClientContext clientContext) { + return new Builder(clientContext); + } + + /** Returns a builder containing all the values of this settings class. */ + public Builder toBuilder() { + return new Builder(this); + } + + protected EchoStubSettings(Builder settingsBuilder) throws IOException { + super(settingsBuilder); + + echoSettings = settingsBuilder.echoSettings().build(); + expandSettings = settingsBuilder.expandSettings().build(); + collectSettings = settingsBuilder.collectSettings().build(); + chatSettings = settingsBuilder.chatSettings().build(); + chatAgainSettings = settingsBuilder.chatAgainSettings().build(); + pagedExpandSettings = settingsBuilder.pagedExpandSettings().build(); + simplePagedExpandSettings = settingsBuilder.simplePagedExpandSettings().build(); + waitSettings = settingsBuilder.waitSettings().build(); + waitOperationSettings = settingsBuilder.waitOperationSettings().build(); + blockSettings = settingsBuilder.blockSettings().build(); + collideNameSettings = settingsBuilder.collideNameSettings().build(); + } + + /** Builder for EchoStubSettings. */ + public static class Builder extends StubSettings.Builder { + private final ImmutableList> unaryMethodSettingsBuilders; + private final UnaryCallSettings.Builder echoSettings; + private final ServerStreamingCallSettings.Builder expandSettings; + private final StreamingCallSettings.Builder collectSettings; + private final StreamingCallSettings.Builder chatSettings; + private final StreamingCallSettings.Builder chatAgainSettings; + private final PagedCallSettings.Builder< + PagedExpandRequest, PagedExpandResponse, PagedExpandPagedResponse> + pagedExpandSettings; + private final PagedCallSettings.Builder< + PagedExpandRequest, PagedExpandResponse, SimplePagedExpandPagedResponse> + simplePagedExpandSettings; + private final UnaryCallSettings.Builder waitSettings; + private final OperationCallSettings.Builder + waitOperationSettings; + private final UnaryCallSettings.Builder blockSettings; + private final UnaryCallSettings.Builder collideNameSettings; + private static final ImmutableMap> + RETRYABLE_CODE_DEFINITIONS; + + static { + ImmutableMap.Builder> definitions = + ImmutableMap.builder(); + definitions.put( + "retry_policy_1_codes", + ImmutableSet.copyOf( + Lists.newArrayList( + StatusCode.Code.UNAVAILABLE, StatusCode.Code.UNKNOWN))); + definitions.put( + "no_retry_0_codes", ImmutableSet.copyOf(Lists.newArrayList())); + RETRYABLE_CODE_DEFINITIONS = definitions.build(); + } + + private static final ImmutableMap RETRY_PARAM_DEFINITIONS; + + static { + ImmutableMap.Builder definitions = ImmutableMap.builder(); + RetrySettings settings = null; + settings = + RetrySettings.newBuilder() + .setInitialRetryDelay(Duration.ofMillis(100L)) + .setRetryDelayMultiplier(2.0) + .setMaxRetryDelay(Duration.ofMillis(3000L)) + .setInitialRpcTimeout(Duration.ofMillis(10000L)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeout(Duration.ofMillis(10000L)) + .setTotalTimeout(Duration.ofMillis(10000L)) + .build(); + definitions.put("retry_policy_1_params", settings); + settings = + RetrySettings.newBuilder() + .setInitialRpcTimeout(Duration.ofMillis(5000L)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeout(Duration.ofMillis(5000L)) + .setTotalTimeout(Duration.ofMillis(5000L)) + .build(); + definitions.put("no_retry_0_params", settings); + RETRY_PARAM_DEFINITIONS = definitions.build(); + } + + protected Builder() { + this(((ClientContext) null)); + } + + protected Builder(ClientContext clientContext) { + super(clientContext); + + echoSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + expandSettings = ServerStreamingCallSettings.newBuilder(); + collectSettings = StreamingCallSettings.newBuilder(); + chatSettings = StreamingCallSettings.newBuilder(); + chatAgainSettings = StreamingCallSettings.newBuilder(); + pagedExpandSettings = PagedCallSettings.newBuilder(PAGED_EXPAND_PAGE_STR_FACT); + simplePagedExpandSettings = PagedCallSettings.newBuilder(SIMPLE_PAGED_EXPAND_PAGE_STR_FACT); + waitSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + waitOperationSettings = OperationCallSettings.newBuilder(); + blockSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + collideNameSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + + unaryMethodSettingsBuilders = + ImmutableList.>of( + echoSettings, + pagedExpandSettings, + simplePagedExpandSettings, + waitSettings, + blockSettings, + collideNameSettings); + initDefaults(this); + } + + protected Builder(EchoStubSettings settings) { + super(settings); + + echoSettings = settings.echoSettings.toBuilder(); + expandSettings = settings.expandSettings.toBuilder(); + collectSettings = settings.collectSettings.toBuilder(); + chatSettings = settings.chatSettings.toBuilder(); + chatAgainSettings = settings.chatAgainSettings.toBuilder(); + pagedExpandSettings = settings.pagedExpandSettings.toBuilder(); + simplePagedExpandSettings = settings.simplePagedExpandSettings.toBuilder(); + waitSettings = settings.waitSettings.toBuilder(); + waitOperationSettings = settings.waitOperationSettings.toBuilder(); + blockSettings = settings.blockSettings.toBuilder(); + collideNameSettings = settings.collideNameSettings.toBuilder(); + + unaryMethodSettingsBuilders = + ImmutableList.>of( + echoSettings, + pagedExpandSettings, + simplePagedExpandSettings, + waitSettings, + blockSettings, + collideNameSettings); + } + + private static Builder createDefault() { + Builder builder = new Builder(((ClientContext) null)); + + builder.setTransportChannelProvider(defaultTransportChannelProvider()); + builder.setCredentialsProvider(defaultCredentialsProviderBuilder().build()); + builder.setInternalHeaderProvider(defaultApiClientHeaderProviderBuilder().build()); + builder.setMtlsEndpoint(getDefaultMtlsEndpoint()); + builder.setSwitchToMtlsEndpointAllowed(true); + + return initDefaults(builder); + } + + private static Builder initDefaults(Builder builder) { + builder + .echoSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); + + builder + .expandSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); + + builder + .pagedExpandSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); + + builder + .simplePagedExpandSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params")); + + builder + .waitSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params")); + + builder + .blockSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params")); + + builder + .collideNameSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params")); + + builder + .waitOperationSettings() + .setInitialCallSettings( + UnaryCallSettings.newUnaryCallSettingsBuilder() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params")) + .build()) + .setResponseTransformer( + ProtoOperationTransformers.ResponseTransformer.create(WaitResponse.class)) + .setMetadataTransformer( + ProtoOperationTransformers.MetadataTransformer.create(WaitMetadata.class)) + .setPollingAlgorithm( + OperationTimedPollAlgorithm.create( + RetrySettings.newBuilder() + .setInitialRetryDelay(Duration.ofMillis(5000L)) + .setRetryDelayMultiplier(1.5) + .setMaxRetryDelay(Duration.ofMillis(45000L)) + .setInitialRpcTimeout(Duration.ZERO) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeout(Duration.ZERO) + .setTotalTimeout(Duration.ofMillis(300000L)) + .build())); + + return builder; + } + + /** + * Applies the given settings updater function to all of the unary API methods in this service. + * + *

Note: This method does not support applying settings to streaming methods. + */ + public Builder applyToAllUnaryMethods( + ApiFunction, Void> settingsUpdater) { + super.applyToAllUnaryMethods(unaryMethodSettingsBuilders, settingsUpdater); + return this; + } + + public ImmutableList> unaryMethodSettingsBuilders() { + return unaryMethodSettingsBuilders; + } + + /** Returns the builder for the settings used for calls to echo. */ + public UnaryCallSettings.Builder echoSettings() { + return echoSettings; + } + + /** Returns the builder for the settings used for calls to expand. */ + public ServerStreamingCallSettings.Builder expandSettings() { + return expandSettings; + } + + /** Returns the builder for the settings used for calls to collect. */ + public StreamingCallSettings.Builder collectSettings() { + return collectSettings; + } + + /** Returns the builder for the settings used for calls to chat. */ + public StreamingCallSettings.Builder chatSettings() { + return chatSettings; + } + + /** Returns the builder for the settings used for calls to chatAgain. */ + public StreamingCallSettings.Builder chatAgainSettings() { + return chatAgainSettings; + } + + /** Returns the builder for the settings used for calls to pagedExpand. */ + public PagedCallSettings.Builder< + PagedExpandRequest, PagedExpandResponse, PagedExpandPagedResponse> + pagedExpandSettings() { + return pagedExpandSettings; + } + + /** Returns the builder for the settings used for calls to simplePagedExpand. */ + public PagedCallSettings.Builder< + PagedExpandRequest, PagedExpandResponse, SimplePagedExpandPagedResponse> + simplePagedExpandSettings() { + return simplePagedExpandSettings; + } + + /** Returns the builder for the settings used for calls to wait. */ + public UnaryCallSettings.Builder waitSettings() { + return waitSettings; + } + + /** Returns the builder for the settings used for calls to wait. */ + public OperationCallSettings.Builder + waitOperationSettings() { + return waitOperationSettings; + } + + /** Returns the builder for the settings used for calls to block. */ + public UnaryCallSettings.Builder blockSettings() { + return blockSettings; + } + + /** Returns the builder for the settings used for calls to collideName. */ + public UnaryCallSettings.Builder collideNameSettings() { + return collideNameSettings; + } + + @Override + public EchoStubSettings build() throws IOException { + return new EchoStubSettings(this); + } + } +} diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/model/ServiceTest.java b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/model/ServiceTest.java index 82a3a7f2b9..10b82ec585 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/model/ServiceTest.java +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/model/ServiceTest.java @@ -16,24 +16,20 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import com.google.api.generator.engine.ast.TypeNode; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import java.util.Arrays; +import org.junit.Before; import org.junit.Test; public class ServiceTest { private static final String SHOWCASE_PACKAGE_NAME = "com.google.showcase.v1beta1"; - private static final Service.Builder testServiceBuilder = - Service.builder() - .setName("Echo") - .setDefaultHost("localhost:7469") - .setOauthScopes(Arrays.asList("https://www.googleapis.com/auth/cloud-platform")) - .setPakkage(SHOWCASE_PACKAGE_NAME) - .setProtoPakkage(SHOWCASE_PACKAGE_NAME) - .setOriginalJavaPackage(SHOWCASE_PACKAGE_NAME) - .setOverriddenName("Echo"); + private Service.Builder testServiceBuilder; private static final Method.Builder testMethodBuilder = Method.builder() @@ -50,6 +46,19 @@ public class ServiceTest { .setIsAsteriskBody(false) .setHttpVerb(HttpBindings.HttpVerb.GET); + @Before + public void init() { + testServiceBuilder = + Service.builder() + .setName("Echo") + .setDefaultHost("localhost:7469") + .setOauthScopes(Arrays.asList("https://www.googleapis.com/auth/cloud-platform")) + .setPakkage(SHOWCASE_PACKAGE_NAME) + .setProtoPakkage(SHOWCASE_PACKAGE_NAME) + .setOriginalJavaPackage(SHOWCASE_PACKAGE_NAME) + .setOverriddenName("Echo"); + } + @Test public void apiShortName_shouldReturnApiShortNameIfHostContainsRegionalEndpoint() { String defaultHost = "us-east1-pubsub.googleapis.com"; @@ -79,17 +88,40 @@ public void apiShortName_shouldReturnHostIfNoPeriods() { } @Test - public void apiVersion_shouldReturnVersionIfMatch() { + public void packageVersion_shouldReturnVersionIfMatch() { String protoPackage = "com.google.showcase.v1"; Service testService = testServiceBuilder.setProtoPakkage(protoPackage).build(); - assertEquals("v1", testService.apiVersion()); + assertEquals("v1", testService.packageVersion()); } @Test - public void apiVersion_shouldReturnEmptyIfNoMatch() { + public void packageVersion_shouldReturnEmptyIfNoMatch() { String protoPackage = "com.google.showcase"; Service testService = testServiceBuilder.setProtoPakkage(protoPackage).build(); + assertEquals("", testService.packageVersion()); + } + + @Test + public void apiVersion_shouldReturnApiVersion() { + String apiVersion = "v1_20230601"; + Service testService = testServiceBuilder.setApiVersion(apiVersion).build(); + assertTrue(testService.hasApiVersion()); + assertEquals(apiVersion, testService.apiVersion()); + } + + @Test + public void apiVersion_shouldReturnNoApiVersionWhenNull() { + Service testService = testServiceBuilder.build(); + assertNull(testService.apiVersion()); + assertFalse(testService.hasApiVersion()); + } + + @Test + public void apiVersion_shouldReturnNoApiVersionWhenEmpty() { + String apiVersion = ""; + Service testService = testServiceBuilder.setApiVersion(apiVersion).build(); assertEquals("", testService.apiVersion()); + assertFalse(testService.hasApiVersion()); } @Test diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java index b4379fdf66..f06c464055 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; @@ -35,6 +36,7 @@ import com.google.api.generator.gapic.model.ResourceName; import com.google.api.generator.gapic.model.ResourceReference; import com.google.api.generator.gapic.model.Transport; +import com.google.api.version.test.ApiVersionTestingOuterClass; import com.google.auto.populate.field.AutoPopulateFieldTestingOuterClass; import com.google.bookshop.v1beta1.BookshopProto; import com.google.common.collect.ImmutableList; @@ -607,6 +609,76 @@ public void parseNestedProtoTypeName() { "google.ads.googleads.v3.resources.MutateJob.MutateJobMetadata")); } + @Test + public void parseServiceApiVersionTest() { + FileDescriptor apiVersionFileDescriptor = ApiVersionTestingOuterClass.getDescriptor(); + Map messageTypes = Parser.parseMessages(apiVersionFileDescriptor); + Map resourceNames = Parser.parseResourceNames(apiVersionFileDescriptor); + List services = + Parser.parseService( + apiVersionFileDescriptor, + messageTypes, + resourceNames, + Optional.empty(), + new HashSet<>()); + com.google.api.generator.gapic.model.Service parsedEchoService = services.get(0); + + assertEquals("EchoWithVersion", parsedEchoService.overriddenName()); + assertTrue(parsedEchoService.hasApiVersion()); + assertEquals("fake_version", parsedEchoService.apiVersion()); + } + + @Test + public void parseServiceWithoutApiVersionTest() { + FileDescriptor apiVersionFileDescriptor = ApiVersionTestingOuterClass.getDescriptor(); + Map messageTypes = Parser.parseMessages(apiVersionFileDescriptor); + Map resourceNames = Parser.parseResourceNames(apiVersionFileDescriptor); + List services = + Parser.parseService( + apiVersionFileDescriptor, + messageTypes, + resourceNames, + Optional.empty(), + new HashSet<>()); + com.google.api.generator.gapic.model.Service parsedEchoWithoutVersionService = services.get(1); + + assertNull(parsedEchoWithoutVersionService.apiVersion()); + assertFalse(parsedEchoWithoutVersionService.hasApiVersion()); + assertEquals("EchoWithoutVersion", parsedEchoWithoutVersionService.overriddenName()); + } + + @Test + public void parseServiceWithEmptyApiVersionTest() { + FileDescriptor apiVersionFileDescriptor = ApiVersionTestingOuterClass.getDescriptor(); + Map messageTypes = Parser.parseMessages(apiVersionFileDescriptor); + Map resourceNames = Parser.parseResourceNames(apiVersionFileDescriptor); + List services = + Parser.parseService( + apiVersionFileDescriptor, + messageTypes, + resourceNames, + Optional.empty(), + new HashSet<>()); + com.google.api.generator.gapic.model.Service parsedEchoWithEmptyVersionService = + services.get(2); + + assertEquals("EchoWithEmptyVersion", parsedEchoWithEmptyVersionService.overriddenName()); + assertEquals("", parsedEchoWithEmptyVersionService.apiVersion()); + assertFalse(parsedEchoWithEmptyVersionService.hasApiVersion()); + } + + @Test + public void testServiceWithoutApiVersionParsed() { + FileDescriptor bookshopFileDescriptor = BookshopProto.getDescriptor(); + Map messageTypes = Parser.parseMessages(bookshopFileDescriptor); + Map resourceNames = Parser.parseResourceNames(bookshopFileDescriptor); + List services = + Parser.parseService( + bookshopFileDescriptor, messageTypes, resourceNames, Optional.empty(), new HashSet<>()); + com.google.api.generator.gapic.model.Service parsedBookshopService = services.get(0); + assertNull(parsedBookshopService.apiVersion()); + } + private void assertMethodArgumentEquals( String name, TypeNode type, List nestedFields, MethodArgument argument) { assertEquals(name, argument.name()); diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/test/protoloader/RestTestProtoLoader.java b/gapic-generator-java/src/test/java/com/google/api/generator/test/protoloader/RestTestProtoLoader.java index 20d64c7b3a..63938fcaad 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/test/protoloader/RestTestProtoLoader.java +++ b/gapic-generator-java/src/test/java/com/google/api/generator/test/protoloader/RestTestProtoLoader.java @@ -15,6 +15,7 @@ package com.google.api.generator.test.protoloader; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; import com.google.api.generator.gapic.model.GapicContext; import com.google.api.generator.gapic.model.GapicServiceConfig; @@ -25,6 +26,7 @@ import com.google.api.generator.gapic.protoparser.Parser; import com.google.api.generator.gapic.protoparser.ServiceConfigParser; import com.google.api.generator.gapic.protoparser.ServiceYamlParser; +import com.google.api.version.test.ApiVersionTestingOuterClass; import com.google.longrunning.OperationsProto; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Descriptors.ServiceDescriptor; @@ -121,4 +123,37 @@ public GapicContext parseEcho() { .setRestNumericEnumsEnabled(true) .build(); } + + public GapicContext parseApiVersionTesting() { + FileDescriptor testingFileDescriptor = ApiVersionTestingOuterClass.getDescriptor(); + ServiceDescriptor testingService = testingFileDescriptor.getServices().get(0); + assertEquals(testingService.getName(), "EchoWithVersion"); + + Map messageTypes = Parser.parseMessages(testingFileDescriptor); + Map resourceNames = Parser.parseResourceNames(testingFileDescriptor); + Set outputResourceNames = new HashSet<>(); + List services = + Parser.parseService( + testingFileDescriptor, + messageTypes, + resourceNames, + Optional.empty(), + outputResourceNames); + + String jsonFilename = "showcase_grpc_service_config.json"; + Path jsonPath = Paths.get(getTestFilesDirectory(), jsonFilename); + Optional configOpt = ServiceConfigParser.parse(jsonPath.toString()); + assertThat(configOpt.isPresent()).isTrue(); + GapicServiceConfig config = configOpt.get(); + + return GapicContext.builder() + .setMessages(messageTypes) + .setResourceNames(resourceNames) + .setServices(services) + .setServiceConfig(config) + .setHelperResourceNames(outputResourceNames) + .setTransport(getTransport()) + .setRestNumericEnumsEnabled(true) + .build(); + } } diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/test/protoloader/TestProtoLoader.java b/gapic-generator-java/src/test/java/com/google/api/generator/test/protoloader/TestProtoLoader.java index d5e62ddf70..db9efd06ca 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/test/protoloader/TestProtoLoader.java +++ b/gapic-generator-java/src/test/java/com/google/api/generator/test/protoloader/TestProtoLoader.java @@ -28,6 +28,7 @@ import com.google.api.generator.gapic.protoparser.Parser; import com.google.api.generator.gapic.protoparser.ServiceConfigParser; import com.google.api.generator.gapic.protoparser.ServiceYamlParser; +import com.google.api.version.test.ApiVersionTestingOuterClass; import com.google.auto.populate.field.AutoPopulateFieldTestingOuterClass; import com.google.bookshop.v1beta1.BookshopProto; import com.google.explicit.dynamic.routing.header.ExplicitDynamicRoutingHeaderTestingOuterClass; @@ -293,6 +294,37 @@ public GapicContext parseExplicitDynamicRoutingHeaderTesting() { .build(); } + public GapicContext parseApiVersionTesting() { + FileDescriptor testingFileDescriptor = ApiVersionTestingOuterClass.getDescriptor(); + ServiceDescriptor testingService = testingFileDescriptor.getServices().get(0); + assertEquals(testingService.getName(), "EchoWithVersion"); + + Map messageTypes = Parser.parseMessages(testingFileDescriptor); + Map resourceNames = Parser.parseResourceNames(testingFileDescriptor); + Set outputResourceNames = new HashSet<>(); + List services = + Parser.parseService( + testingFileDescriptor, + messageTypes, + resourceNames, + Optional.empty(), + outputResourceNames); + String jsonFilename = "showcase_grpc_service_config.json"; + Path jsonPath = Paths.get(testFilesDirectory, jsonFilename); + Optional configOpt = ServiceConfigParser.parse(jsonPath.toString()); + assertTrue(configOpt.isPresent()); + GapicServiceConfig config = configOpt.get(); + + return GapicContext.builder() + .setMessages(messageTypes) + .setResourceNames(resourceNames) + .setServices(services) + .setServiceConfig(config) + .setHelperResourceNames(outputResourceNames) + .setTransport(transport) + .build(); + } + public GapicContext parseAutoPopulateFieldTesting() { FileDescriptor autopopulationFileDescriptor = AutoPopulateFieldTestingOuterClass.getDescriptor(); diff --git a/gapic-generator-java/src/test/proto/api_version_testing.proto b/gapic-generator-java/src/test/proto/api_version_testing.proto new file mode 100644 index 0000000000..f815a7633e --- /dev/null +++ b/gapic-generator-java/src/test/proto/api_version_testing.proto @@ -0,0 +1,264 @@ +// 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. + +syntax = "proto3"; + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; +import "google/api/field_info.proto"; +import "google/api/resource.proto"; +import "google/longrunning/operations.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "google/rpc/status.proto"; + +package google.api.version.test.v1; + +option java_package = "com.google.api.version.test"; +option java_multiple_files = true; +option java_outer_classname = "ApiVersionTestingOuterClass"; + +option (google.api.resource_definition) = { + type: "showcase.googleapis.com/AnythingGoes" + pattern: "*" +}; +// This proto is used to test scenarios related to api_version feature. +// api_version is set on service level, so this proto includes various services +// to test different scenarios. + +// This service is used to test when api_version string is provided. +service EchoWithVersion { + // This service is meant to only run locally on the port 7469 (keypad digits + // for "show"). + option (google.api.default_host) = "localhost:7469"; + option (google.api.api_version) = "fake_version"; + option (google.api.oauth_scopes) = + "https://www.googleapis.com/auth/cloud-platform"; + + // This method simply echos the request. This method is showcases unary rpcs. + rpc EchoWithVersionMethod(EchoRequest) returns (EchoResponse) { + option (google.api.http) = { + post: "/v1beta1/echo:echo" + body: "*" + }; + option (google.api.method_signature) = "content"; + option (google.api.method_signature) = "error"; + option (google.api.method_signature) = "content,severity"; + option (google.api.method_signature) = "name"; + option (google.api.method_signature) = "parent"; + option (google.api.method_signature) = ""; + } +} + +// This service is used to test when api_version is not provided. +service EchoWithoutVersion { + // This service is meant to only run locally on the port 7469 (keypad digits + // for "show"). + option (google.api.default_host) = "localhost:7469"; + option (google.api.oauth_scopes) = + "https://www.googleapis.com/auth/cloud-platform"; + + // This method simply echos the request. This method is showcases unary rpcs. + rpc Echo(EchoRequest) returns (EchoResponse) { + option (google.api.http) = { + post: "/v1beta1/echo:echo" + body: "*" + }; + option (google.api.method_signature) = "content"; + option (google.api.method_signature) = "error"; + option (google.api.method_signature) = "content,severity"; + option (google.api.method_signature) = "name"; + option (google.api.method_signature) = "parent"; + option (google.api.method_signature) = ""; + } +} + +// This service is to test api_version is empty. +service EchoWithEmptyVersion { + // This service is meant to only run locally on the port 7469 (keypad digits + // for "show"). + option (google.api.default_host) = "localhost:7469"; + option (google.api.api_version) = ""; + option (google.api.oauth_scopes) = + "https://www.googleapis.com/auth/cloud-platform"; + + // This method simply echos the request. This method is showcases unary rpcs. + rpc Echo(EchoRequest) returns (EchoResponse) { + option (google.api.http) = { + post: "/v1beta1/echo:echo" + body: "*" + }; + option (google.api.method_signature) = "content"; + option (google.api.method_signature) = "error"; + option (google.api.method_signature) = "content,severity"; + option (google.api.method_signature) = "name"; + option (google.api.method_signature) = "parent"; + option (google.api.method_signature) = ""; + } +} + +// A severity enum used to test enum capabilities in GAPIC surfaces +enum Severity { + UNNECESSARY = 0; + NECESSARY = 1; + URGENT = 2; + CRITICAL = 3; +} + +message Foobar { + option (google.api.resource) = { + type: "showcase.googleapis.com/Foobar" + pattern: "projects/{project}/foobars/{foobar}" + pattern: "projects/{project}/chocolate/variants/{variant}/foobars/{foobar}" + pattern: "foobars/{foobar}" + pattern: "bar_foos/{bar_foo}/foobars/{foobar}" + pattern: "*" + }; + + string name = 1; + string info = 2; +} + +// The request message used for the Echo, Collect and Chat methods. +// If content or opt are set in this message then the request will succeed. +// If status is set in this message +// then the status will be returned as an error. +message EchoRequest { + string name = 5 [ + (google.api.resource_reference).type = "showcase.googleapis.com/Foobar", + (google.api.field_behavior) = REQUIRED + ]; + + string parent = 6 [ + (google.api.resource_reference).child_type = + "showcase.googleapis.com/AnythingGoes", + (google.api.field_behavior) = REQUIRED + ]; + + oneof response { + // The content to be echoed by the server. + string content = 1; + + // The error to be thrown by the server. + google.rpc.Status error = 2; + } + + // The severity to be echoed by the server. + Severity severity = 3; + + Foobar foobar = 4; +} + +// The response message for the Echo methods. +message EchoResponse { + // The content specified in the request. + string content = 1; + + // The severity specified in the request. + Severity severity = 2; +} + +// Tests name collisions with java.lang.Object. +message Object { + // The content specified in the request. + string content = 1; +} + +// The request message for the Expand method. +message ExpandRequest { + // The content that will be split into words and returned on the stream. + string content = 1; + + // The error that is thrown after all words are sent on the stream. + google.rpc.Status error = 2; + + string info = 3; + +} + +// The request for the PagedExpand method. +message PagedExpandRequest { + // The string to expand. + string content = 1 [(google.api.field_behavior) = REQUIRED]; + + // The amount of words to returned in each page. + int32 page_size = 2; + + // The position of the page to be returned. + string page_token = 3; +} + +// The response for the PagedExpand method. +message PagedExpandResponse { + // The words that were expanded. + repeated EchoResponse responses = 1; + + // The next page token. + string next_page_token = 2; +} + +// The request for Wait method. +message WaitRequest { + oneof end { + // The time that this operation will complete. + google.protobuf.Timestamp end_time = 1; + + // The duration of this operation. + google.protobuf.Duration ttl = 4; + } + + oneof response { + // The error that will be returned by the server. If this code is specified + // to be the OK rpc code, an empty response will be returned. + google.rpc.Status error = 2; + + // The response to be returned on operation completion. + WaitResponse success = 3; + } +} + +// The result of the Wait operation. +message WaitResponse { + // This content of the result. + string content = 1; +} + +// The metadata for Wait operation. +message WaitMetadata { + // The time that this operation will complete. + google.protobuf.Timestamp end_time = 1; +} + +// The request for Block method. +message BlockRequest { + // The amount of time to block before returning a response. + google.protobuf.Duration response_delay = 1; + + oneof response { + // The error that will be returned by the server. If this code is specified + // to be the OK rpc code, an empty response will be returned. + google.rpc.Status error = 2; + + // The response to be returned that will signify successful method call. + BlockResponse success = 3; + } +} + +// The response for Block method. +message BlockResponse { + // This content can contain anything, the server will not depend on a value + // here. + string content = 1; +} diff --git a/gapic-generator-java/src/test/proto/echo_grpcrest.proto b/gapic-generator-java/src/test/proto/echo_grpcrest.proto index fbab0c2553..ea4a9392f3 100644 --- a/gapic-generator-java/src/test/proto/echo_grpcrest.proto +++ b/gapic-generator-java/src/test/proto/echo_grpcrest.proto @@ -47,6 +47,7 @@ service Echo { option (google.api.default_host) = "localhost:7469"; option (google.api.oauth_scopes) = "https://www.googleapis.com/auth/cloud-platform"; + option (google.api.api_version) = "foo_version_for_tests"; // This method simply echos the request. This method is showcases unary rpcs. rpc Echo(EchoRequest) returns (EchoResponse) { diff --git a/gax-java/dependencies.properties b/gax-java/dependencies.properties index 6519fdfe96..e76c827179 100644 --- a/gax-java/dependencies.properties +++ b/gax-java/dependencies.properties @@ -83,5 +83,5 @@ maven.org_mockito_mockito_core=org.mockito:mockito-core:2.28.2 maven.org_hamcrest_hamcrest_core=org.hamcrest:hamcrest-core:1.3 maven.com_google_truth_truth=com.google.truth:truth:1.4.2 maven.com_googlecode_java_diff_utils_diffutils=com.googlecode.java-diff-utils:diffutils:1.3.0 -maven.net_bytebuddy_byte_buddy=net.bytebuddy:byte-buddy:1.14.13 +maven.net_bytebuddy_byte_buddy=net.bytebuddy:byte-buddy:1.14.14 maven.org_objenesis_objenesis=org.objenesis:objenesis:2.6 diff --git a/gax-java/gax/src/main/java/com/google/api/gax/core/InstantiatingExecutorProvider.java b/gax-java/gax/src/main/java/com/google/api/gax/core/InstantiatingExecutorProvider.java index 1faee91a4a..25c8213f02 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/core/InstantiatingExecutorProvider.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/core/InstantiatingExecutorProvider.java @@ -34,6 +34,8 @@ import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; /** * InstantiatingChannelProvider is an ExecutorProvider which constructs a new @@ -41,6 +43,9 @@ */ @AutoValue public abstract class InstantiatingExecutorProvider implements ExecutorProvider { + private static final Logger LOGGER = + Logger.getLogger(InstantiatingExecutorProvider.class.getName()); + // Thread factory to use to create our worker threads private static final ThreadFactory DEFAULT_THREAD_FACTORY = new ThreadFactory() { @@ -95,6 +100,8 @@ public static Builder newBuilder() { public static Builder newIOBuilder() { int numCpus = Runtime.getRuntime().availableProcessors(); int numThreads = IO_THREAD_MULTIPLIER * Math.max(MIN_THREAD_AMOUNT, numCpus); + LOGGER.log( + Level.CONFIG, String.format("Thread Pool for requests has Core Pool Size: %d", numThreads)); return new AutoValue_InstantiatingExecutorProvider.Builder() .setExecutorThreadCount(numThreads) diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ApiClientHeaderProvider.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ApiClientHeaderProvider.java index 34d00d0f3a..ae27404335 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ApiClientHeaderProvider.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ApiClientHeaderProvider.java @@ -42,6 +42,8 @@ public class ApiClientHeaderProvider implements HeaderProvider, Serializable { private static final long serialVersionUID = -8876627296793342119L; static final String QUOTA_PROJECT_ID_HEADER_KEY = "x-goog-user-project"; + static final String API_VERSION_HEADER_KEY = "x-goog-api-version"; + private final Map headers; protected ApiClientHeaderProvider(Builder builder) { @@ -68,6 +70,9 @@ protected ApiClientHeaderProvider(Builder builder) { headersBuilder.put(QUOTA_PROJECT_ID_HEADER_KEY, builder.getQuotaProjectIdToken()); } + if (builder.getApiVersionToken() != null) { + headersBuilder.put(API_VERSION_HEADER_KEY, builder.getApiVersionToken()); + } this.headers = headersBuilder.build(); } @@ -109,6 +114,8 @@ public static class Builder { private String resourceHeaderKey; private String resourceToken; + private String apiVersionToken; + protected Builder() { // Initialize with default values apiClientHeaderKey = getDefaultApiClientHeaderKey(); @@ -121,6 +128,8 @@ protected Builder() { resourceHeaderKey = getDefaultResourceHeaderKey(); resourceToken = null; + + apiVersionToken = null; } public String getApiClientHeaderKey() { @@ -206,6 +215,15 @@ public Builder setResourceToken(String resourceToken) { return this; } + public String getApiVersionToken() { + return apiVersionToken; + } + + public Builder setApiVersionToken(String apiVersionToken) { + this.apiVersionToken = apiVersionToken; + return this; + } + private String constructToken(String name, String version) { if (version == null) { return null; diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/ApiClientHeaderProviderTest.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/ApiClientHeaderProviderTest.java index f60c3c0760..bc524cb35d 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/ApiClientHeaderProviderTest.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/ApiClientHeaderProviderTest.java @@ -138,4 +138,18 @@ public void testQuotaProjectHeader() { assertThat(provider.getHeaders().get(ApiClientHeaderProvider.QUOTA_PROJECT_ID_HEADER_KEY)) .matches(quotaProjectHeaderValue); } + + @Test + public void testApiVersionHeader() { + ApiClientHeaderProvider provider = + ApiClientHeaderProvider.newBuilder().setApiVersionToken("fake-version-string").build(); + assertThat(provider.getHeaders().size()).isEqualTo(2); + assertThat(provider.getHeaders().get(ApiClientHeaderProvider.API_VERSION_HEADER_KEY)) + .matches("fake-version-string"); + + ApiClientHeaderProvider emptyProvider = + ApiClientHeaderProvider.newBuilder().setApiVersionToken("").build(); + assertThat( + emptyProvider.getHeaders().get(ApiClientHeaderProvider.API_VERSION_HEADER_KEY).isEmpty()); + } } diff --git a/gax-java/gax_java.bzl b/gax-java/gax_java.bzl index 8276ab68bd..c9974575f4 100644 --- a/gax-java/gax_java.bzl +++ b/gax-java/gax_java.bzl @@ -26,13 +26,15 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +load("@rules_java//java:defs.bzl", "java_test") + def java_tests(name, srcs, runtime_deps, size): classNames = [] for src in srcs: # convert .java file path to fully qualified class name className = src[(src.index("/com/") + 1):-5].replace("/", ".") classNames.append(className) - native.java_test( + java_test( name = className, test_class = className, runtime_deps = runtime_deps, diff --git a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/DependencyAnalyzer.java b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/DependencyAnalyzer.java index 7b73f73e35..7423af8f11 100644 --- a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/DependencyAnalyzer.java +++ b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/DependencyAnalyzer.java @@ -6,6 +6,7 @@ import com.google.cloud.model.Advisory; import com.google.cloud.model.AdvisoryKey; import com.google.cloud.model.AnalysisResult; +import com.google.cloud.model.License; import com.google.cloud.model.ReportResult; import com.google.cloud.model.PackageInfo; import com.google.cloud.model.QueryResult; @@ -52,11 +53,13 @@ public AnalysisResult analyze(String system, String packageName, String packageV List result = new ArrayList<>(); for (VersionKey versionKey : dependencies) { QueryResult packageInfo = depsDevClient.getQueryResult(versionKey); - List licenses = new ArrayList<>(); + List licenses = new ArrayList<>(); List advisories = new ArrayList<>(); for (Result res : packageInfo.results()) { Version version = res.version(); - licenses.addAll(version.licenses()); + for (String license : version.licenses()) { + licenses.add(License.toLicense(license)); + } for (AdvisoryKey advisoryKey : version.advisoryKeys()) { advisories.add(depsDevClient.getAdvisory(advisoryKey.id())); } @@ -65,7 +68,7 @@ public AnalysisResult analyze(String system, String packageName, String packageV result.add(new PackageInfo(versionKey, licenses, advisories)); } - return AnalysisResult.of(root, result); + return AnalysisResult.of(result); } /** @@ -86,10 +89,12 @@ public AnalysisResult analyze(String system, String packageName, String packageV */ public static void main(String[] args) throws IllegalArgumentException { checkArgument(args.length == 3, - "The length of the inputs should be 3.\n" + - "The 1st input should be the package management system.\n" + - "The 2nd input should be the package name.\n" + - "The 3rd input should be the package version.\n" + """ + The length of the inputs should be 3. + The 1st input should be the package management system. + The 2nd input should be the package name. + The 3rd input should be the package version. + """ ); String system = args[0]; @@ -107,7 +112,9 @@ public static void main(String[] args) throws IllegalArgumentException { System.exit(1); } - ReportResult result = analyzeReport.generateReport(); + System.out.println("Please copy and paste the package information below to your ticket.\n"); + System.out.println(analyzeReport.toString()); + ReportResult result = analyzeReport.getAnalysisResult(); System.out.println(result); if (result.equals(ReportResult.FAIL)) { System.out.println( diff --git a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/external/DepsDevClient.java b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/external/DepsDevClient.java index fe61edccd8..a42c46a64a 100644 --- a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/external/DepsDevClient.java +++ b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/external/DepsDevClient.java @@ -6,6 +6,7 @@ import com.google.cloud.model.QueryResult; import com.google.cloud.model.Relation; import com.google.cloud.model.VersionKey; +import com.google.errorprone.annotations.RestrictedApi; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; @@ -16,10 +17,12 @@ import java.lang.reflect.Type; import java.net.URI; import java.net.URISyntaxException; +import java.net.URLEncoder; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.stream.Collectors; @@ -27,9 +30,11 @@ public class DepsDevClient { private final HttpClient client; public final Gson gson; - private final static String advisoryUrlBase = "https://api.deps.dev/v3/advisories/%s"; - private final static String queryUrlBase = "https://api.deps.dev/v3/query?versionKey.system=%s&versionKey.name=%s&versionKey.version=%s"; - private final static String dependencyUrlBase = "https://api.deps.dev/v3/systems/%s/packages/%s/versions/%s:dependencies"; + private final static String ADVISORY_URL_BASE = "https://api.deps.dev/v3/advisories/%s"; + + private final static String DEPENDENCY_URLBASE = "https://api.deps.dev/v3/systems/%s/packages/%s/versions/%s:dependencies"; + + public final static String QUERY_URL_BASE = "https://api.deps.dev/v3/query?versionKey.system=%s&versionKey.name=%s&versionKey.version=%s"; public DepsDevClient(HttpClient client) { this.client = client; @@ -76,15 +81,25 @@ public Advisory getAdvisory(String advisoryId) } private String getAdvisoryUrl(String advisoryId) { - return String.format(advisoryUrlBase, advisoryId); + return String.format(ADVISORY_URL_BASE, advisoryId); + } + + @RestrictedApi( + explanation = "This method is for internal use only.", + allowedOnPath = "test/java/com/google/cloud/external") + public String getQueryUrl(String system, String name, String version) { + return String.format(QUERY_URL_BASE, system, name, encode(version)); } - private String getQueryUrl(String system, String name, String version) { - return String.format(queryUrlBase, system, name, version); + @RestrictedApi( + explanation = "This method is for internal use only.", + allowedOnPath = "test/java/com/google/cloud/external") + public String getDependencyUrl(String system, String name, String version) { + return String.format(DEPENDENCY_URLBASE, system, name, encode(version)); } - private String getDependencyUrl(String system, String name, String version) { - return String.format(dependencyUrlBase, system, name, version); + private String encode(String str) { + return URLEncoder.encode(str, StandardCharsets.UTF_8); } private HttpResponse getResponse(String endpoint) diff --git a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/Advisory.java b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/Advisory.java index 542033dedd..dc08fda614 100644 --- a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/Advisory.java +++ b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/Advisory.java @@ -22,5 +22,9 @@ public record Advisory( double cvss3Score, String cvss3Vector) { + @Override + public String toString() { + return String.format("Advisory (id: %s, more info: [%s](%s))", advisoryKey.id(), title, url); + } } diff --git a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/AnalysisResult.java b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/AnalysisResult.java index 5ae1907bb6..006764055d 100644 --- a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/AnalysisResult.java +++ b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/AnalysisResult.java @@ -1,50 +1,40 @@ package com.google.cloud.model; -import com.google.common.collect.ImmutableSet; +import static com.google.cloud.external.DepsDevClient.QUERY_URL_BASE; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.Set; public class AnalysisResult { - private final VersionKey root; + private final List packageInfos; private final Map> advisories; - private final Map> nonCompliantLicenses; - private final ImmutableSet compliantCategories = ImmutableSet.of( - LicenseCategory.NOTICE); - - private final static Logger LOGGER = Logger.getLogger(AnalysisResult.class.getName()); + private final Map> nonCompliantLicenses; - private AnalysisResult(VersionKey root, List result) { - this.root = root; - advisories = getAdvisories(result); - nonCompliantLicenses = getNonCompliantLicenses(result); + private AnalysisResult(List result) { + this.packageInfos = result; + this.advisories = getAdvisories(result); + this.nonCompliantLicenses = getNonCompliantLicenses(result); } - public static AnalysisResult of(VersionKey root, List result) { - return new AnalysisResult(root, result); + public static AnalysisResult of(List result) { + return new AnalysisResult(result); } - public ReportResult generateReport() { - if (!advisories.isEmpty()) { - formatLog(root, advisories, "New security vulnerability found in dependencies:"); + public ReportResult getAnalysisResult() { + if (advisories.isEmpty() && nonCompliantLicenses.isEmpty()) { + return ReportResult.PASS; } - if (!nonCompliantLicenses.isEmpty()) { - formatLog(root, nonCompliantLicenses, "Non-compliant license found in dependencies:"); - } - - if (!advisories.isEmpty() || !nonCompliantLicenses.isEmpty()) { - LOGGER.log(Level.SEVERE, String.format("Found dependency risk in %s", root)); - return ReportResult.FAIL; - } + return ReportResult.FAIL; + } - LOGGER.log(Level.INFO, - String.format("%s have no known vulnerabilities and non compliant licenses", root)); - return ReportResult.PASS; + @Override + public String toString() { + return packageInfoReport(); } private Map> getAdvisories(List result) { @@ -58,13 +48,13 @@ private Map> getAdvisories(List result) return advisories; } - private Map> getNonCompliantLicenses(List result) { - Map> licenses = new HashMap<>(); + private Map> getNonCompliantLicenses(List result) { + Map> licenses = new HashMap<>(); + Set compliantCategories = LicenseCategory.compliantCategories(); result.forEach(packageInfo -> { - List nonCompliantLicenses = new ArrayList<>(); - for (String licenseStr : packageInfo.licenses()) { - License license = License.toLicense(licenseStr); + List nonCompliantLicenses = new ArrayList<>(); + for (License license : packageInfo.licenses()) { // fiter out all compliant categories, the remaining ones are non-compliant. List nonCompliantCategories = license .getCategories() @@ -72,7 +62,7 @@ private Map> getNonCompliantLicenses(List .filter(category -> !compliantCategories.contains(category)) .toList(); if (!nonCompliantCategories.isEmpty()) { - nonCompliantLicenses.add(licenseStr); + nonCompliantLicenses.add(license); } } if (!nonCompliantLicenses.isEmpty()) { @@ -82,21 +72,53 @@ private Map> getNonCompliantLicenses(List return licenses; } - private void formatLog(VersionKey root, Map> map, String message) { - LOGGER.log(Level.SEVERE, message); - map.forEach((versionKey, list) -> { - LOGGER.log(Level.SEVERE, beginSeparator(versionKey, root)); - list.forEach(item -> LOGGER.log(Level.SEVERE, item.toString())); - LOGGER.log(Level.SEVERE, endSeparator()); - }); + private String packageInfoReport() { + StringBuilder builder = new StringBuilder(); + PackageInfo root = packageInfos.get(0); + String title = String.format(""" + ## Package information of %s + %s + """, root.versionKey(), packageInfoSection(root)); + builder.append(title); + + builder.append("## Dependencies\n"); + if (packageInfos.size() == 1) { + builder.append(String.format("%s has no dependency.", root.versionKey())); + } else { + for (int i = 1; i < packageInfos.size(); i++) { + PackageInfo info = packageInfos.get(i); + String dependencyInfo = String.format(""" + ### Package information of %s + %s + """, info.versionKey(), packageInfoSection(info)); + builder.append(dependencyInfo); + } + } + builder.append("\n"); + + return builder.toString(); } - private String beginSeparator(VersionKey versionKey, VersionKey root) { - return String.format("====================== %s, dependency of %s ======================", - versionKey.toString(), root.toString()); + private String packageInfoSection(PackageInfo packageInfo) { + VersionKey versionKey = packageInfo.versionKey(); + // generate the report using Markdown format. + String packageInfoReport = """ + Licenses: %s + Vulnerabilities: %s. + Checked in [%s (%s)](%s) + """; + return String.format(packageInfoReport, + packageInfo.licenses(), + packageInfo.advisories(), + versionKey.name(), + versionKey.version(), + getQueryUrl( + versionKey.pkgManagement().toString(), + versionKey.name(), + versionKey.version())); } - private String endSeparator() { - return "==========================================================="; + private String getQueryUrl(String system, String name, String version) { + return String.format(QUERY_URL_BASE, system, name, version); } } diff --git a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/License.java b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/License.java index 1394afdd16..246cff06b1 100644 --- a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/License.java +++ b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/License.java @@ -14,17 +14,21 @@ * For more information, please refer to go/thirdpartylicenses. */ public enum License { - APACHE_2_0(Set.of(NOTICE)), - BCL(Set.of(RESTRICTED, NOTICE)), - GL2PS(Set.of(RESTRICTED, NOTICE)), - MIT(Set.of(NOTICE)), - NOT_RECOGNIZED(Set.of()); + APACHE_2_0("Apache-2.0", Set.of(NOTICE)), + BCL("BCL", Set.of(RESTRICTED, NOTICE)), + BSD_3_CLAUSE("BSD-3-Clause", Set.of(NOTICE)), + GL2PS("GL2PS", Set.of(RESTRICTED, NOTICE)), + MIT("MIT", Set.of(NOTICE)), + NOT_RECOGNIZED("Not-Recognized", Set.of()); private final static Logger LOGGER = Logger.getLogger(License.class.getName()); + private final String licenseStr; + private final Set categories; - License(Set categories) { + License(String licenseStr, Set categories) { + this.licenseStr = licenseStr; this.categories = categories; } @@ -44,4 +48,20 @@ public static License toLicense(String licenseStr) { public Set getCategories() { return ImmutableSet.copyOf(categories); } + + @Override + public String toString() { + String nonCompliantPrefix = "%s (Not Google-compliant!)"; + String compliantPrefix = "%s (Google-compliant)"; + Set compliantCategories = LicenseCategory.compliantCategories(); + if (this.categories.isEmpty()) { + return String.format(nonCompliantPrefix, this.licenseStr); + } + for (LicenseCategory category : this.categories) { + if (!compliantCategories.contains(category)) { + return String.format(nonCompliantPrefix, this.licenseStr); + } + } + return String.format(compliantPrefix, this.licenseStr); + } } diff --git a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/LicenseCategory.java b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/LicenseCategory.java index cf98a35bfa..642d51b00a 100644 --- a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/LicenseCategory.java +++ b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/LicenseCategory.java @@ -1,5 +1,8 @@ package com.google.cloud.model; +import com.google.common.collect.ImmutableSet; +import java.util.Set; + /** * The type of license associated with open-source software. *

@@ -8,5 +11,9 @@ public enum LicenseCategory { PERMISSIVE, RESTRICTED, - NOTICE + NOTICE; + + public static Set compliantCategories() { + return ImmutableSet.of(LicenseCategory.NOTICE); + } } diff --git a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/PackageInfo.java b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/PackageInfo.java index 046fcf80aa..7aa1f12768 100644 --- a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/PackageInfo.java +++ b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/PackageInfo.java @@ -9,10 +9,10 @@ */ public record PackageInfo( VersionKey versionKey, - List licenses, + List licenses, List advisories) { - public List licenses() { + public List licenses() { return ImmutableList.copyOf(licenses); } diff --git a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/VersionKey.java b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/VersionKey.java index 7a145d3677..589ae7190a 100644 --- a/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/VersionKey.java +++ b/java-shared-dependencies/dependency-analyzer/src/main/java/com/google/cloud/model/VersionKey.java @@ -20,4 +20,16 @@ public static VersionKey from(String system, String name, String version) return new VersionKey(pkg, name, version); } + @Override + public String toString() { + if (pkgManagement == PkgManagement.MAVEN) { + return String.format("%s:%s", name, version); + } + + return "VersionKey{" + + "pkgManagement=" + pkgManagement + + ", name='" + name + '\'' + + ", version='" + version + '\'' + + '}'; + } } diff --git a/java-shared-dependencies/dependency-analyzer/src/test/java/com/google/cloud/external/DepsDevClientTest.java b/java-shared-dependencies/dependency-analyzer/src/test/java/com/google/cloud/external/DepsDevClientTest.java index 9d58e339a2..4ac683d4ef 100644 --- a/java-shared-dependencies/dependency-analyzer/src/test/java/com/google/cloud/external/DepsDevClientTest.java +++ b/java-shared-dependencies/dependency-analyzer/src/test/java/com/google/cloud/external/DepsDevClientTest.java @@ -1,6 +1,7 @@ package com.google.cloud.external; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -21,19 +22,32 @@ public class DepsDevClientTest { - private HttpClient httpClient; private HttpResponse response; private DepsDevClient client; @Before public void setUp() throws IOException, InterruptedException { - httpClient = mock(HttpClient.class); + HttpClient httpClient = mock(HttpClient.class); client = new DepsDevClient(httpClient); response = mock(HttpResponse.class); when(httpClient.send(any(HttpRequest.class), any(BodyHandler.class))) .thenReturn(response); } + @Test + public void testGetQueryUrlReturnsEncodedUrl() { + assertEquals( + "https://api.deps.dev/v3/query?versionKey.system=MAVEN&versionKey.name=com.google.errorprone:javac-shaded&versionKey.version=9%2B181-r4173-1", + client.getQueryUrl("MAVEN", "com.google.errorprone:javac-shaded", "9+181-r4173-1")); + } + + @Test + public void testGetDependenciesReturnsEncodedUrl() { + assertEquals( + "https://api.deps.dev/v3/systems/MAVEN/packages/com.google.errorprone:javac-shaded/versions/9%2B181-r4173-1:dependencies", + client.getDependencyUrl("MAVEN", "com.google.errorprone:javac-shaded", "9+181-r4173-1")); + } + @Test public void testGetDirectDependenciesOnlyReturnsDirectDeps() throws IOException, InterruptedException, URISyntaxException, IllegalArgumentException { @@ -50,7 +64,8 @@ public void testGetQueryResultSucceed() throws URISyntaxException, IOException, InterruptedException, IllegalArgumentException { String responseBody = "{\"results\":[{\"version\":{\"versionKey\":{\"system\":\"MAVEN\",\"name\":\"org.apache.logging.log4j:log4j-core\",\"version\":\"2.17.0\"},\"publishedAt\":\"2021-12-18T01:58:10Z\",\"isDefault\":false,\"licenses\":[\"Apache-2.0\"],\"advisoryKeys\":[{\"id\":\"GHSA-8489-44mv-ggj8\"}],\"links\":[{\"label\":\"SOURCE_REPO\",\"url\":\"https://gitbox.apache.org/repos/asf?p=logging-log4j2.git\"},{\"label\":\"ISSUE_TRACKER\",\"url\":\"https://issues.apache.org/jira/browse/LOG4J2\"},{\"label\":\"HOMEPAGE\",\"url\":\"https://logging.apache.org/log4j/2.x/\"}],\"slsaProvenances\":[],\"registries\":[\"https://repo.maven.apache.org/maven2/\"],\"relatedProjects\":[{\"projectKey\":{\"id\":\"\"},\"relationProvenance\":\"UNVERIFIED_METADATA\",\"relationType\":\"ISSUE_TRACKER\"}]}}]}"; when(response.body()).thenReturn(responseBody); - VersionKey log4jCore = VersionKey.from("maven", "org.apache.logging.log4j:log4j-core", "2.17.0"); + VersionKey log4jCore = + VersionKey.from("maven", "org.apache.logging.log4j:log4j-core", "2.17.0"); QueryResult queryResult = client.getQueryResult(log4jCore); assertThat(queryResult.results()).hasSize(1); Version version = queryResult.results().get(0).version(); diff --git a/java-shared-dependencies/dependency-analyzer/src/test/java/com/google/cloud/model/AnalysisResultTest.java b/java-shared-dependencies/dependency-analyzer/src/test/java/com/google/cloud/model/AnalysisResultTest.java index a074bc17be..ab3bd50b0e 100644 --- a/java-shared-dependencies/dependency-analyzer/src/test/java/com/google/cloud/model/AnalysisResultTest.java +++ b/java-shared-dependencies/dependency-analyzer/src/test/java/com/google/cloud/model/AnalysisResultTest.java @@ -9,7 +9,7 @@ public class AnalysisResultTest { @Test - public void testGenerateReportWithAdvisoriesThrowsException() + public void testGenerateReportWithAdvisoriesReturnsFailure() throws IllegalArgumentException { VersionKey root = VersionKey.from("maven", "com.example:artifact", "1.2.3"); List results = List.of( @@ -26,22 +26,22 @@ public void testGenerateReportWithAdvisoriesThrowsException() )) ) ); - ReportResult result = AnalysisResult.of(root, results).generateReport(); + ReportResult result = AnalysisResult.of(results).getAnalysisResult(); assertEquals(ReportResult.FAIL, result); } @Test - public void testGenerateReportWithNonCompliantLicenseThrowsException() + public void testGenerateReportWithNonCompliantLicenseReturnsFailure() throws IllegalArgumentException { VersionKey root = VersionKey.from("maven", "com.example:artifact", "1.2.3"); List results = List.of( new PackageInfo( root, - List.of("BCL"), + List.of(License.toLicense("BCL")), List.of() ) ); - ReportResult result = AnalysisResult.of(root, results).generateReport(); + ReportResult result = AnalysisResult.of(results).getAnalysisResult(); assertEquals(ReportResult.FAIL, result); } @@ -52,11 +52,100 @@ public void testGenerateReportWithoutRiskSucceeds() List results = List.of( new PackageInfo( root, - List.of("Apache-2.0"), + List.of(License.toLicense("Apache-2.0")), List.of() ) ); - ReportResult result = AnalysisResult.of(root, results).generateReport(); + ReportResult result = AnalysisResult.of(results).getAnalysisResult(); assertEquals(ReportResult.PASS, result); } + + @Test + public void testToStringReturnsNoRiskInformation() { + VersionKey root = VersionKey.from("maven", "com.example:artifact", "1.2.3"); + List results = List.of( + new PackageInfo( + root, + List.of(License.toLicense("Apache-2.0")), + List.of() + ), + new PackageInfo( + VersionKey.from("maven", "com.example:dependency", "4.5.6"), + List.of(License.toLicense("Apache-2.0"), License.toLicense("MIT")), + List.of() + ), + new PackageInfo( + VersionKey.from("maven", "com.example:nested-dependency", "2.3.1"), + List.of(License.toLicense("Apache-2.0"), License.toLicense("MIT")), + List.of() + ) + ); + assertEquals(""" + ## Package information of com.example:artifact:1.2.3 + Licenses: [Apache-2.0 (Google-compliant)] + Vulnerabilities: []. + Checked in [com.example:artifact (1.2.3)](https://api.deps.dev/v3/query?versionKey.system=MAVEN&versionKey.name=com.example:artifact&versionKey.version=1.2.3) + + ## Dependencies + ### Package information of com.example:dependency:4.5.6 + Licenses: [Apache-2.0 (Google-compliant), MIT (Google-compliant)] + Vulnerabilities: []. + Checked in [com.example:dependency (4.5.6)](https://api.deps.dev/v3/query?versionKey.system=MAVEN&versionKey.name=com.example:dependency&versionKey.version=4.5.6) + + ### Package information of com.example:nested-dependency:2.3.1 + Licenses: [Apache-2.0 (Google-compliant), MIT (Google-compliant)] + Vulnerabilities: []. + Checked in [com.example:nested-dependency (2.3.1)](https://api.deps.dev/v3/query?versionKey.system=MAVEN&versionKey.name=com.example:nested-dependency&versionKey.version=2.3.1) + + + """, AnalysisResult.of(results).toString()); + } + + @Test + public void testToStringReturnsRiskInformation() { + VersionKey root = VersionKey.from("maven", "com.example:artifact", "1.2.3"); + List results = List.of( + new PackageInfo( + root, + List.of(License.APACHE_2_0, License.BCL), + List.of() + ), + new PackageInfo( + VersionKey.from("maven", "com.example:dependency", "4.5.6"), + List.of(License.MIT), + List.of(new Advisory( + new AdvisoryKey("GHSA-2qrg-x229-3v8q"), + "https://osv.dev/vulnerability/GHSA-2qrg-x229-3v8q", + "Deserialization of Untrusted Data in Log4j", + new String[]{"CVE-2019-17571"}, + 9.8, + "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + )) + ), + new PackageInfo( + VersionKey.from("maven", "com.example:nested-dependency", "2.3.1"), + List.of(License.MIT, License.GL2PS), + List.of() + ) + ); + assertEquals(""" + ## Package information of com.example:artifact:1.2.3 + Licenses: [Apache-2.0 (Google-compliant), BCL (Not Google-compliant!)] + Vulnerabilities: []. + Checked in [com.example:artifact (1.2.3)](https://api.deps.dev/v3/query?versionKey.system=MAVEN&versionKey.name=com.example:artifact&versionKey.version=1.2.3) + + ## Dependencies + ### Package information of com.example:dependency:4.5.6 + Licenses: [MIT (Google-compliant)] + Vulnerabilities: [Advisory (id: GHSA-2qrg-x229-3v8q, more info: [Deserialization of Untrusted Data in Log4j](https://osv.dev/vulnerability/GHSA-2qrg-x229-3v8q))]. + Checked in [com.example:dependency (4.5.6)](https://api.deps.dev/v3/query?versionKey.system=MAVEN&versionKey.name=com.example:dependency&versionKey.version=4.5.6) + + ### Package information of com.example:nested-dependency:2.3.1 + Licenses: [MIT (Google-compliant), GL2PS (Not Google-compliant!)] + Vulnerabilities: []. + Checked in [com.example:nested-dependency (2.3.1)](https://api.deps.dev/v3/query?versionKey.system=MAVEN&versionKey.name=com.example:nested-dependency&versionKey.version=2.3.1) + + + """, AnalysisResult.of(results).toString()); + } } diff --git a/java-shared-dependencies/dependency-analyzer/src/test/java/com/google/cloud/model/LicenseTest.java b/java-shared-dependencies/dependency-analyzer/src/test/java/com/google/cloud/model/LicenseTest.java index aa6ea2a45d..9973a50eb5 100644 --- a/java-shared-dependencies/dependency-analyzer/src/test/java/com/google/cloud/model/LicenseTest.java +++ b/java-shared-dependencies/dependency-analyzer/src/test/java/com/google/cloud/model/LicenseTest.java @@ -5,6 +5,7 @@ import org.junit.Test; public class LicenseTest { + @Test public void testToLicenseSucceeds() { String license = "Apache-2.0"; @@ -16,4 +17,22 @@ public void testToLicenseReturnsNonRecognizedLicense() { String license = "Non-existent-license"; assertEquals(License.NOT_RECOGNIZED, License.toLicense(license)); } + + @Test + public void testToStringOfACompliantLicense() { + String license = "Apache-2.0"; + assertEquals("Apache-2.0 (Google-compliant)", License.toLicense(license).toString()); + } + + @Test + public void testToStringOfANonCompliantLicense() { + String license = "BCL"; + assertEquals("BCL (Not Google-compliant!)", License.toLicense(license).toString()); + } + + @Test + public void testToStringOfANotRecognizedLicense() { + String license = "Non-existent-license"; + assertEquals("Not-Recognized (Not Google-compliant!)", License.toLicense(license).toString()); + } } diff --git a/library_generation/DEVELOPMENT.md b/library_generation/DEVELOPMENT.md new file mode 100644 index 0000000000..cede089ae9 --- /dev/null +++ b/library_generation/DEVELOPMENT.md @@ -0,0 +1,171 @@ +> [!IMPORTANT] +> All examples assume you are inside the `library_generation` folder + + +# Linting + +When contributing, ensure your changes to python code have a valid +format. + +``` +python -m pip install black +black . +``` + +# Running the integration tests + +The integration tests build the docker image declared in +`.cloudbuild/library_generation/library_generation.Dockerfile`, pull GAPIC +repositories, generate the libraries and compares the results with the source +code declared in a "golden branch" of the repo. + +It requires docker and python 3.x to be installed. + +``` +python -m pip install . +python -m pip install -r requirements.txt +python -m unittest test/integration_tests.py +``` + +# Running the unit tests + +The unit tests of the hermetic build scripts are contained in several scripts, +corresponding to a specific component. Every unit test script ends with +`unit_tests.py`. To avoid them specifying them +individually, we can use the following command: + +```bash +python -m unittest discover -s test/ -p "*unit_tests.py" +``` + +> [!NOTE] +> The output of this command may look erratic during the first 30 seconds. +> This is normal. After the tests are done, an "OK" message should be shown. + +# Running the scripts in your local environment + +Although the scripts are designed to be run in a Docker container, you can also +run them directly. This section explains how to run the entrypoint script +(`library_generation/cli/entry_point.py`). + +## Installing prerequisites + +In order to run the generation scripts directly, there are a few tools we +need to install beforehand. + +### Install synthtool + +It requires python 3.x to be installed. +You will need to specify a committish of the synthtool repo in order to have +your generation results matching exactly what the docker image would produce. +You can achieve this by inspecting `SYNTHTOOL_COMMITISH` in +`.cloudbuild/library_generation/library_generation.Dockerfile`. + +```bash +# obtained from .cloudbuild/library_generation/library_generation.Dockerfile +export SYNTHTOOL_COMMITTISH=6612ab8f3afcd5e292aecd647f0fa68812c9f5b5 +``` + +```bash +git clone https://github.com/googleapis/synthtool +cd synthtool +git checkout "${SYNTHTOOL_COMMITTISH}" +python -m pip install --require-hashes -r requirements.txt +python -m pip install --no-deps -e . +python -m synthtool --version +``` + +### Install the owl-bot CLI + +Requires node.js to be installed. +Check this [installation guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script) +for NVM, Node.js's version manager. + +After you install it, you can install the owl-bot CLI with the following +commands: +```bash +git clone https://github.com/googleapis/repo-automation-bots +cd repo-automation-bots/packages/owl-bot +npm i && npm run compile && npm link +owl-bot copy-code --version +``` + +The key step is `npm link`, which will make the command available in you current +shell session. + +## Running the script +The entrypoint script (`library_generation/cli/entry_point.py`) allows you to +update the target repository with the latest changes starting from the +googleapis committish declared in `generation_config.yaml`. + +### Download the repo +For example, google-cloud-java +``` +git clone https://github.com/googleapis/google-cloud-java +export path_to_repo="$(pwd)/google-cloud-java" +``` + +### Install the scripts +``` +python -m pip install . +``` + +### Run the script +``` +python cli/entry_point.py generate --repository-path="${path_to_repo}" +``` + + +# Running the scripts using the docker container image +This is convenient in order to avoid installing the dependencies manually. + +> [!IMPORTANT] +> From now, the examples assume you are in the root of your sdk-platform-java +> folder + +## Build the docker image +```bash +docker build --file .cloudbuild/library_generation/library_generation.Dockerfile --iidfile image-id . +``` + +This will create an `image-id` file at the root of the repo with the hash ID of +the image. + +## Run the docker image +The docker image will perform changes on its internal `/workspace` folder, to which you +need to map a folder on your host machine (i.e. map your downloaded repo to this +folder). + +To run the docker container on the google-cloud-java repo, you must run: +```bash +docker run -u "$(id -u)":"$(id -g)" -v/path/to/google-cloud-java:/workspace $(cat image-id) +``` + + * `-u "$(id -u)":"$(id -g)"` makes docker run the container impersonating + yourself. This avoids folder ownership changes since it runs as root by + default. + * `-v/path/to/google-cloud-java:/workspace` maps the host machine's + google-cloud-java folder to the /workspace folder. The image is configured to + perform changes in this directory + * `$(cat image-id)` obtains the image ID created in the build step + +## Debug the created containers +If you are working on changing the way the containers are created, you may want +to inspect the containers to check the setup. It would be convenient in such +case to have a text editor/viewer available. You can achieve this by modifying +the Dockerfile as follows: + +```docker +# install OS tools +RUN apt-get update && apt-get install -y \ + unzip openjdk-17-jdk rsync maven jq less vim \ + && apt-get clean +``` + +We add `less` and `vim` as text tools for further inspection. + +You can also run a shell in a new container by running: + +```bash +docker run --rm -it -u=$(id -u):$(id -g) -v/path/to/google-cloud-java:/workspace --entrypoint="bash" $(cat image-id) +``` diff --git a/library_generation/README.md b/library_generation/README.md index 50ea1afe9c..b94fe2de53 100644 --- a/library_generation/README.md +++ b/library_generation/README.md @@ -94,12 +94,10 @@ They are shared by library level parameters. | Name | Required | Notes | |:------------------------|:--------:|:---------------------------------------------| | gapic_generator_version | Yes | | -| protobuf_version | No | inferred from the generator if not specified | +| protoc_version | No | inferred from the generator if not specified | | grpc_version | No | inferred from the generator if not specified | | googleapis-commitish | Yes | | | libraries_bom_version | Yes | | -| owlbot-cli-image | Yes | | -| synthtool-commitish | Yes | | | template_excludes | Yes | | ### Library level parameters @@ -146,11 +144,9 @@ The GAPIC level parameters define how to generate a GAPIC library. ```yaml gapic_generator_version: 2.34.0 -protobuf_version: 25.2 +protoc_version: 25.2 googleapis_commitish: 1a45bf7393b52407188c82e63101db7dc9c72026 libraries_bom_version: 26.37.0 -owlbot_cli_image: sha256:623647ee79ac605858d09e60c1382a716c125fb776f69301b72de1cd35d49409 -synthtool_commitish: 6612ab8f3afcd5e292aecd647f0fa68812c9f5b5 destination_path: google-cloud-java template_excludes: - ".github/*" diff --git a/library_generation/cli/entry_point.py b/library_generation/cli/entry_point.py index ccaf631e85..960fae8693 100644 --- a/library_generation/cli/entry_point.py +++ b/library_generation/cli/entry_point.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import os +import sys import click as click from library_generation.generate_pr_description import generate_pr_descriptions @@ -142,5 +143,29 @@ def generate( ) +@main.command() +@click.option( + "--generation-config-path", + required=False, + type=str, + help=""" + Absolute or relative path to a generation_config.yaml. + Default to generation_config.yaml in the current working directory. + """, +) +def validate_generation_config(generation_config_path: str) -> None: + """ + Validate the given generation configuration. + """ + if generation_config_path is None: + generation_config_path = "generation_config.yaml" + try: + from_yaml(os.path.abspath(generation_config_path)) + print(f"{generation_config_path} is validated without any errors.") + except ValueError as err: + print(err) + sys.exit(1) + + if __name__ == "__main__": main() diff --git a/library_generation/generate_composed_library.py b/library_generation/generate_composed_library.py index 12f21dec9c..ae5b535e3e 100755 --- a/library_generation/generate_composed_library.py +++ b/library_generation/generate_composed_library.py @@ -112,8 +112,6 @@ def generate_composed_library( "", versions_file, owlbot_cli_source_folder, - config.owlbot_cli_image, - config.synthtool_commitish, str(config.is_monorepo()).lower(), config_path, ], @@ -130,7 +128,7 @@ def __construct_tooling_arg(config: GenerationConfig) -> List[str]: arguments = [] arguments += util.create_argument("gapic_generator_version", config) arguments += util.create_argument("grpc_version", config) - arguments += util.create_argument("protobuf_version", config) + arguments += util.create_argument("protoc_version", config) return arguments diff --git a/library_generation/generate_library.sh b/library_generation/generate_library.sh index a5d73ebec4..88c2052b56 100755 --- a/library_generation/generate_library.sh +++ b/library_generation/generate_library.sh @@ -20,8 +20,8 @@ case $key in export gapic_generator_version shift ;; - --protobuf_version) - protobuf_version="$2" + --protoc_version) + protoc_version="$2" shift ;; --grpc_version) @@ -82,8 +82,8 @@ if [ -z "${gapic_generator_version}" ]; then exit 1 fi -if [ -z "${protobuf_version}" ]; then - protobuf_version=$(get_protobuf_version "${gapic_generator_version}") +if [ -z "${protoc_version}" ]; then + protoc_version=$(get_protoc_version "${gapic_generator_version}") fi if [ -z "${grpc_version}" ]; then @@ -177,7 +177,7 @@ case "${proto_path}" in ;; esac # download gapic-generator-java, protobuf and grpc plugin. -download_tools "${gapic_generator_version}" "${protobuf_version}" "${grpc_version}" "${os_architecture}" +download_tools "${gapic_generator_version}" "${protoc_version}" "${grpc_version}" "${os_architecture}" ##################### Section 1 ##################### # generate grpc-*/ ##################################################### diff --git a/library_generation/model/generation_config.py b/library_generation/model/generation_config.py index 97eebe6788..bc9c5e3f20 100644 --- a/library_generation/model/generation_config.py +++ b/library_generation/model/generation_config.py @@ -12,13 +12,15 @@ # 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 yaml -from typing import List, Optional, Dict +from typing import Optional from library_generation.model.library_config import LibraryConfig from library_generation.model.gapic_config import GapicConfig +REPO_LEVEL_PARAMETER = "Repo level parameter" +LIBRARY_LEVEL_PARAMETER = "Library level parameter" +GAPIC_LEVEL_PARAMETER = "GAPIC level parameter" + class GenerationConfig: """ @@ -30,22 +32,19 @@ def __init__( gapic_generator_version: str, googleapis_commitish: str, libraries_bom_version: str, - owlbot_cli_image: str, - synthtool_commitish: str, - template_excludes: List[str], - libraries: List[LibraryConfig], + template_excludes: list[str], + libraries: list[LibraryConfig], grpc_version: Optional[str] = None, - protobuf_version: Optional[str] = None, + protoc_version: Optional[str] = None, ): self.gapic_generator_version = gapic_generator_version self.googleapis_commitish = googleapis_commitish self.libraris_bom_version = libraries_bom_version - self.owlbot_cli_image = owlbot_cli_image - self.synthtool_commitish = synthtool_commitish self.template_excludes = template_excludes self.libraries = libraries self.grpc_version = grpc_version - self.protobuf_version = protobuf_version + self.protoc_version = protoc_version + self.__validate() def get_proto_path_to_library_name(self) -> dict[str, str]: """ @@ -62,6 +61,19 @@ def get_proto_path_to_library_name(self) -> dict[str, str]: def is_monorepo(self) -> bool: return len(self.libraries) > 1 + def __validate(self) -> None: + seen_library_names = dict() + for library in self.libraries: + library_name = library.get_library_name() + if library_name in seen_library_names: + raise ValueError( + f"Both {library.name_pretty} and " + f"{seen_library_names.get(library_name)} have the same " + f"library name: {library_name}, please update one of the " + f"library to have a different library name." + ) + seen_library_names[library_name] = library.name_pretty + def from_yaml(path_to_yaml: str) -> GenerationConfig: """ @@ -72,15 +84,19 @@ def from_yaml(path_to_yaml: str) -> GenerationConfig: with open(path_to_yaml, "r") as file_stream: config = yaml.safe_load(file_stream) - libraries = __required(config, "libraries") + libraries = __required(config, "libraries", REPO_LEVEL_PARAMETER) + if not libraries: + raise ValueError(f"Library is None in {path_to_yaml}.") parsed_libraries = list() for library in libraries: gapics = __required(library, "GAPICs") parsed_gapics = list() + if not gapics: + raise ValueError(f"GAPICs is None in {library}.") for gapic in gapics: - proto_path = __required(gapic, "proto_path") + proto_path = __required(gapic, "proto_path", GAPIC_LEVEL_PARAMETER) new_gapic = GapicConfig(proto_path) parsed_gapics.append(new_gapic) @@ -114,27 +130,36 @@ def from_yaml(path_to_yaml: str) -> GenerationConfig: parsed_libraries.append(new_library) parsed_config = GenerationConfig( - gapic_generator_version=__required(config, "gapic_generator_version"), + gapic_generator_version=__required( + config, "gapic_generator_version", REPO_LEVEL_PARAMETER + ), grpc_version=__optional(config, "grpc_version", None), - protobuf_version=__optional(config, "protobuf_version", None), - googleapis_commitish=__required(config, "googleapis_commitish"), - libraries_bom_version=__required(config, "libraries_bom_version"), - owlbot_cli_image=__required(config, "owlbot_cli_image"), - synthtool_commitish=__required(config, "synthtool_commitish"), - template_excludes=__required(config, "template_excludes"), + protoc_version=__optional(config, "protoc_version", None), + googleapis_commitish=__required( + config, "googleapis_commitish", REPO_LEVEL_PARAMETER + ), + libraries_bom_version=__required( + config, "libraries_bom_version", REPO_LEVEL_PARAMETER + ), + template_excludes=__required(config, "template_excludes", REPO_LEVEL_PARAMETER), libraries=parsed_libraries, ) return parsed_config -def __required(config: Dict, key: str): +def __required(config: dict, key: str, level: str = LIBRARY_LEVEL_PARAMETER): if key not in config: - raise ValueError(f"required key {key} not found in yaml") + message = ( + f"{level}, {key}, is not found in {config} in yaml." + if level != REPO_LEVEL_PARAMETER + else f"{level}, {key}, is not found in yaml." + ) + raise ValueError(message) return config[key] -def __optional(config: Dict, key: str, default: any): +def __optional(config: dict, key: str, default: any): if key not in config: return default return config[key] diff --git a/library_generation/owlbot/bin/entrypoint.sh b/library_generation/owlbot/bin/entrypoint.sh index 37f50152ce..789737b2a5 100755 --- a/library_generation/owlbot/bin/entrypoint.sh +++ b/library_generation/owlbot/bin/entrypoint.sh @@ -70,7 +70,12 @@ echo "Fixing missing license headers..." python3 "${scripts_root}/owlbot/src/fix-license-headers.py" echo "...done" -# ensure formatting on all .java files in the repository +# Ensure formatting on all .java files in the repository. +# Here we manually set the user.home system variable. Unfortunately, Maven +# user.home inference involves the /etc/passwd file (confirmed empirically), +# instead of the presumable $HOME env var, which may not work properly +# when `docker run`ning with the -u flag because we may incur in users +# not registered in the container's /etc/passwd file echo "Reformatting source..." -mvn fmt:format -V --batch-mode --no-transfer-progress +mvn fmt:format -Duser.home="${HOME}" -V --batch-mode --no-transfer-progress echo "...done" diff --git a/library_generation/owlbot/src/fix-license-headers.py b/library_generation/owlbot/src/fix-license-headers.py index 50f9f7fce0..1c690b5d39 100644 --- a/library_generation/owlbot/src/fix-license-headers.py +++ b/library_generation/owlbot/src/fix-license-headers.py @@ -21,10 +21,10 @@ # Until the generator generates license headers on generated proto # classes, add the license headers in -for path in glob.glob("proto-google-*"): +for path in glob.glob("proto-*"): java.fix_proto_headers(root / path) # Until the generator generates license headers on generated grpc # classes, add the license headers in -for path in glob.glob("grpc-google-*"): +for path in glob.glob("grpc-*"): java.fix_grpc_headers(root / path, "unused") diff --git a/library_generation/owlbot/src/fix-poms.py b/library_generation/owlbot/src/fix-poms.py index 4bfbe05057..1de814e9ce 100644 --- a/library_generation/owlbot/src/fix-poms.py +++ b/library_generation/owlbot/src/fix-poms.py @@ -383,7 +383,7 @@ def main(versions_file, monorepo): # Missing Case 2: There's a new proto-XXX and grpc-XXX directory. It's a new # version in the proto file to a library. Both a new library and existing # library. - for path in glob.glob("proto-google-*"): + for path in glob.glob("proto-*"): if not path in existing_modules: existing_modules[path] = module.Module( group_id=__proto_group_id(group_id), @@ -422,7 +422,7 @@ def main(versions_file, monorepo): release_version=main_module.release_version, ) - for path in glob.glob("grpc-google-*"): + for path in glob.glob("grpc-*"): if not path in existing_modules: existing_modules[path] = module.Module( group_id=__proto_group_id(group_id), diff --git a/library_generation/owlbot/templates/java_library/samples/pom.xml b/library_generation/owlbot/templates/java_library/samples/pom.xml index add08dc502..e653958eb4 100644 --- a/library_generation/owlbot/templates/java_library/samples/pom.xml +++ b/library_generation/owlbot/templates/java_library/samples/pom.xml @@ -38,7 +38,7 @@ org.apache.maven.plugins maven-deploy-plugin - 3.1.1 + 3.1.2 true diff --git a/library_generation/postprocess_library.sh b/library_generation/postprocess_library.sh index 397716c843..411c93fd08 100755 --- a/library_generation/postprocess_library.sh +++ b/library_generation/postprocess_library.sh @@ -15,12 +15,9 @@ # 3 - versions_file: path to file containing versions to be applied to the poms # 4 - owlbot_cli_source_folder: alternative folder with a structure exactly like # googleapis-gen. It will be used instead of preprocessed_sources_path if -# 5 - owlbot_cli_image_sha: SHA of the image containing the OwlBot CLI -# 6 - synthtool_commitish: Commit SHA of the synthtool repo -# provided -# 7 - is_monorepo: whether this library is a monorepo, which implies slightly +# 5 - is_monorepo: whether this library is a monorepo, which implies slightly # different logic -# 8 - configuration_yaml_path: path to the configuration yaml containing library +# 6 - configuration_yaml_path: path to the configuration yaml containing library # generation information for this library set -exo pipefail scripts_root=$(dirname "$(readlink -f "$0")") @@ -29,15 +26,13 @@ postprocessing_target=$1 preprocessed_sources_path=$2 versions_file=$3 owlbot_cli_source_folder=$4 -owlbot_cli_image_sha=$5 -synthtool_commitish=$6 -is_monorepo=$7 -configuration_yaml_path=$8 +is_monorepo=$5 +configuration_yaml_path=$6 owlbot_yaml_file_name=".OwlBot-hermetic.yaml" source "${scripts_root}"/utils/utilities.sh -declare -a required_inputs=("postprocessing_target" "versions_file" "owlbot_cli_image_sha" "synthtool_commitish" "is_monorepo") +declare -a required_inputs=("postprocessing_target" "versions_file" "is_monorepo") for required_input in "${required_inputs[@]}"; do if [[ -z "${!required_input}" ]]; then echo "missing required ${required_input} argument, please specify one" @@ -84,70 +79,22 @@ else fi # Default values for running copy-code directly from host -repo_bindings="-v ${postprocessing_target}:/workspace" repo_workspace="/workspace" preprocessed_libraries_binding="${owlbot_cli_source_folder}" -# When running docker inside docker, we run into the issue of volume bindings -# being mapped from the host machine to the child container (instead of the -# parent container to child container) because we bind the `docker.sock` socket -# to the parent container (i.e. docker calls use the host's filesystem context) -# see https://serverfault.com/a/819371 -# We solve this by referencing environment variables that will be -# set to produce the correct volume mapping. -# -# The workflow is: to check if we are in a docker container (via passed env var) -# and use managed volumes (docker volume create) instead of bindings -# (-v /path:/other-path). The volume names are also received as env vars. - -if [[ -n "${RUNNING_IN_DOCKER}" ]]; then - set -u # temporarily fail on unset variables - repo_bindings="${REPO_BINDING_VOLUMES}" - set +u - library_name=$(echo "${postprocessing_target}" | rev | cut -d'/' -f1 | rev) - repo_workspace="/workspace/" - if [[ "${is_monorepo}" == "true" ]]; then - monorepo_name=$(echo "${postprocessing_target}" | rev | cut -d'/' -f2 | rev) - repo_workspace+="${monorepo_name}/" - fi - repo_workspace+="${library_name}" -fi +pushd "${postprocessing_target}" -docker run --rm \ - --user "$(id -u)":"$(id -g)" \ - ${repo_bindings} \ - -v "/tmp:/tmp" \ - -w "${repo_workspace}" \ - --env HOME=/tmp \ - gcr.io/cloud-devrel-public-resources/owlbot-cli@"${owlbot_cli_image_sha}" \ - copy-code \ +owl-bot copy-code \ --source-repo-commit-hash=none \ - --source-repo="${preprocessed_libraries_binding}" \ + --source-repo="${owlbot_cli_source_folder}" \ --config-file="${owlbot_yaml_relative_path}" + # clean the custom owlbot yaml if [[ "${is_monorepo}" == "true" ]]; then rm "${postprocessing_target}/.OwlBot.hermetic.yaml" fi -# we clone the synthtool library and manually build it -mkdir -p /tmp/synthtool -pushd /tmp/synthtool - -if [ ! -d "synthtool" ]; then - git clone https://github.com/googleapis/synthtool.git -fi -git config --global --add safe.directory /tmp/synthtool/synthtool -pushd "synthtool" - -git fetch --all -git reset --hard "${synthtool_commitish}" - -python3 -m pip install -e . -python3 -m pip install -r requirements.in -popd # synthtool -popd # temp dir - # run the postprocessor echo 'running owl-bot post-processor' pushd "${postprocessing_target}" diff --git a/library_generation/requirements.txt b/library_generation/requirements.txt index f2d649d744..b7636a3706 100644 --- a/library_generation/requirements.txt +++ b/library_generation/requirements.txt @@ -1,12 +1,12 @@ -absl-py==2.0.0 +absl-py==2.1.0 attr==0.3.2 attrs==23.2.0 black==24.3.0 click==8.1.7 gitdb==4.0.11 -GitPython==3.1.41 +GitPython==3.1.43 Jinja2==3.1.3 -lxml==5.0.0 +lxml==5.2.1 MarkupSafe==2.1.3 mypy-extensions==1.0.0 packaging==23.2 diff --git a/library_generation/templates/root-pom.xml.j2 b/library_generation/templates/root-pom.xml.j2 index c48e8b71ef..a713cefa2c 100644 --- a/library_generation/templates/root-pom.xml.j2 +++ b/library_generation/templates/root-pom.xml.j2 @@ -25,7 +25,7 @@ org.apache.maven.plugins maven-deploy-plugin - 3.1.1 + 3.1.2 true diff --git a/library_generation/test/cli/entry_point_unit_tests.py b/library_generation/test/cli/entry_point_unit_tests.py index ae168e9671..ace2794684 100644 --- a/library_generation/test/cli/entry_point_unit_tests.py +++ b/library_generation/test/cli/entry_point_unit_tests.py @@ -11,9 +11,13 @@ # 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 os import unittest from click.testing import CliRunner -from library_generation.cli.entry_point import generate +from library_generation.cli.entry_point import generate, validate_generation_config + +script_dir = os.path.dirname(os.path.realpath(__file__)) +test_resource_dir = os.path.join(script_dir, "..", "resources", "test-config") class EntryPointTest(unittest.TestCase): @@ -44,3 +48,32 @@ def test_entry_point_with_baseline_without_current_raise_file_exception(self): "current_generation_config is not specified when " "baseline_generation_config is specified.", ) + + def test_validate_generation_config_succeeds( + self, + ): + runner = CliRunner() + # noinspection PyTypeChecker + result = runner.invoke( + validate_generation_config, + [f"--generation-config-path={test_resource_dir}/generation_config.yaml"], + ) + self.assertEqual(0, result.exit_code) + + def test_validate_generation_config_with_duplicate_library_name_raise_file_exception( + self, + ): + runner = CliRunner() + # noinspection PyTypeChecker + result = runner.invoke( + validate_generation_config, + [ + f"--generation-config-path={test_resource_dir}/generation_config_with_duplicate_library_name.yaml" + ], + ) + self.assertEqual(1, result.exit_code) + self.assertEqual(SystemExit, result.exc_info[0]) + self.assertRegex( + result.output, + "have the same library name", + ) diff --git a/library_generation/test/generate_library_unit_tests.sh b/library_generation/test/generate_library_unit_tests.sh index ac499435c8..9b5f8bc456 100755 --- a/library_generation/test/generate_library_unit_tests.sh +++ b/library_generation/test/generate_library_unit_tests.sh @@ -28,16 +28,16 @@ get_grpc_version_failed_with_invalid_generator_version_test() { assertEquals 1 $((res)) } -get_protobuf_version_succeed_with_valid_generator_version_test() { +get_protoc_version_succeed_with_valid_generator_version_test() { local actual_version - actual_version=$(get_protobuf_version "2.24.0") + actual_version=$(get_protoc_version "2.24.0") assertEquals "23.2" "${actual_version}" rm "gapic-generator-java-pom-parent-2.24.0.pom" } -get_protobuf_version_failed_with_invalid_generator_version_test() { +get_protoc_version_failed_with_invalid_generator_version_test() { local res=0 - $(get_protobuf_version "1.99.0") || res=$? + $(get_protoc_version "1.99.0") || res=$? assertEquals 1 $((res)) } @@ -110,27 +110,27 @@ download_generator_failed_with_invalid_version_test() { assertEquals 1 $((res)) } -download_protobuf_succeed_with_valid_version_linux_test() { - download_protobuf "23.2" "linux-x86_64" - assertFileOrDirectoryExists "protobuf-23.2" - rm -rf "protobuf-23.2" +download_protoc_succeed_with_valid_version_linux_test() { + download_protoc "23.2" "linux-x86_64" + assertFileOrDirectoryExists "protoc-23.2" + rm -rf "protoc-23.2" } -download_protobuf_succeed_with_valid_version_macos_test() { - download_protobuf "23.2" "osx-x86_64" - assertFileOrDirectoryExists "protobuf-23.2" - rm -rf "protobuf-23.2" "google" +download_protoc_succeed_with_valid_version_macos_test() { + download_protoc "23.2" "osx-x86_64" + assertFileOrDirectoryExists "protoc-23.2" + rm -rf "protoc-23.2" "google" } -download_protobuf_failed_with_invalid_version_linux_test() { +download_protoc_failed_with_invalid_version_linux_test() { local res=0 - $(download_protobuf "22.99" "linux-x86_64") || res=$? + $(download_protoc "22.99" "linux-x86_64") || res=$? assertEquals 1 $((res)) } -download_protobuf_failed_with_invalid_arch_test() { +download_protoc_failed_with_invalid_arch_test() { local res=0 - $(download_protobuf "23.2" "customized-x86_64") || res=$? + $(download_protoc "23.2" "customized-x86_64") || res=$? assertEquals 1 $((res)) } @@ -166,7 +166,7 @@ generate_library_failed_with_invalid_generator_version() { -p google/cloud/alloydb/v1 \ -d ../"${destination}" \ --gapic_generator_version 1.99.0 \ - --protobuf_version 23.2 \ + --protoc_version 23.2 \ --grpc_version 1.55.1 \ --transport grpc+rest \ --rest_numeric_enums true || res=$? @@ -175,7 +175,7 @@ generate_library_failed_with_invalid_generator_version() { cleanup "${destination}" } -generate_library_failed_with_invalid_protobuf_version() { +generate_library_failed_with_invalid_protoc_version() { local destination="google-cloud-alloydb-v1-java" local res=0 cd "${script_dir}/resources" @@ -183,7 +183,7 @@ generate_library_failed_with_invalid_protobuf_version() { -p google/cloud/alloydb/v1 \ -d ../"${destination}" \ --gapic_generator_version 2.24.0 \ - --protobuf_version 22.99 \ + --protoc_version 22.99 \ --grpc_version 1.55.1 \ --transport grpc+rest \ --rest_numeric_enums true || res=$? @@ -256,24 +256,24 @@ test_list=( extract_folder_name_test get_grpc_version_succeed_with_valid_generator_version_test get_grpc_version_failed_with_invalid_generator_version_test - get_protobuf_version_succeed_with_valid_generator_version_test - get_protobuf_version_failed_with_invalid_generator_version_test + get_protoc_version_succeed_with_valid_generator_version_test + get_protoc_version_failed_with_invalid_generator_version_test get_gapic_opts_with_rest_test get_gapic_opts_without_rest_test get_gapic_opts_with_non_default_test remove_grpc_version_test download_generator_success_with_valid_version_test download_generator_failed_with_invalid_version_test - download_protobuf_succeed_with_valid_version_linux_test - download_protobuf_succeed_with_valid_version_macos_test - download_protobuf_failed_with_invalid_version_linux_test - download_protobuf_failed_with_invalid_arch_test + download_protoc_succeed_with_valid_version_linux_test + download_protoc_succeed_with_valid_version_macos_test + download_protoc_failed_with_invalid_version_linux_test + download_protoc_failed_with_invalid_arch_test download_grpc_plugin_succeed_with_valid_version_linux_test download_grpc_plugin_succeed_with_valid_version_macos_test download_grpc_plugin_failed_with_invalid_version_linux_test download_grpc_plugin_failed_with_invalid_arch_test generate_library_failed_with_invalid_generator_version - generate_library_failed_with_invalid_protobuf_version + generate_library_failed_with_invalid_protoc_version generate_library_failed_with_invalid_grpc_version copy_directory_if_exists_valid_folder_succeeds copy_directory_if_exists_invalid_folder_does_not_copy diff --git a/library_generation/test/generate_pr_description_unit_tests.py b/library_generation/test/generate_pr_description_unit_tests.py index c633268aa4..959c442805 100644 --- a/library_generation/test/generate_pr_description_unit_tests.py +++ b/library_generation/test/generate_pr_description_unit_tests.py @@ -61,11 +61,9 @@ def test_generate_pr_description_with_same_googleapis_commits(self): gapic_generator_version="", googleapis_commitish=commit_sha, libraries_bom_version="", - owlbot_cli_image="", - synthtool_commitish="", template_excludes=[], grpc_version="", - protobuf_version="", + protoc_version="", libraries=[], ), baseline_commit=commit_sha, diff --git a/library_generation/test/generate_repo_unit_tests.py b/library_generation/test/generate_repo_unit_tests.py index a947e29f5e..9269fb08a1 100644 --- a/library_generation/test/generate_repo_unit_tests.py +++ b/library_generation/test/generate_repo_unit_tests.py @@ -46,8 +46,6 @@ def __get_an_empty_generation_config() -> GenerationConfig: gapic_generator_version="", googleapis_commitish="", libraries_bom_version="", - synthtool_commitish="", - owlbot_cli_image="", template_excludes=[], libraries=[], ) diff --git a/library_generation/test/integration_tests.py b/library_generation/test/integration_tests.py index 356bdec447..e3f950300e 100644 --- a/library_generation/test/integration_tests.py +++ b/library_generation/test/integration_tests.py @@ -65,31 +65,25 @@ def test_entry_point_running_in_container(self): config_files = self.__get_config_files(config_dir) for repo, config_file in config_files: config = from_yaml(config_file) + repo_location = f"{output_dir}/{repo}" + config_location = f"{golden_dir}/../{repo}" # 1. pull repository repo_dest = self.__pull_repo_to( - Path(f"{output_dir}/{repo}"), repo, committish_map[repo] + Path(repo_location), repo, committish_map[repo] ) # 2. prepare golden files library_names = self.__get_library_names_from_config(config) self.__prepare_golden_files( config=config, library_names=library_names, repo_dest=repo_dest ) - # 3. bind repository and configuration to docker volumes - self.__bind_device_to_volumes( - volume_name=f"repo-{repo}", device_dir=f"{output_dir}/{repo}" - ) - self.__bind_device_to_volumes( - volume_name=f"config-{repo}", device_dir=f"{golden_dir}/../{repo}" - ) - repo_volumes = f"-v repo-{repo}:/workspace/{repo} -v config-{repo}:/workspace/config-{repo}" - # 4. run entry_point.py in docker container + # 3. run entry_point.py in docker container self.__run_entry_point_in_docker_container( - repo=repo, - repo_volumes=repo_volumes, + repo_location=repo_location, + config_location=config_location, baseline_config=baseline_config_name, current_config=current_config_name, ) - # 5. compare generation result with golden files + # 4. compare generation result with golden files print( "Generation finished successfully. " "Will now compare differences between generated and existing " @@ -233,71 +227,35 @@ def __prepare_golden_files( else: copy_tree(f"{repo_dest}", f"{golden_dir}/{library_name}") - @classmethod - def __bind_device_to_volumes(cls, volume_name: str, device_dir: str): - # We use a volume to hold the repositories used in the integration - # tests. This is because the test container creates a child container - # using the host machine's docker socket, meaning that we can only - # reference volumes created from within the host machine (i.e. the - # machine running this script). - # - # To summarize, we create a special volume that can be referenced both - # in the main container and in any child containers created by this one. - - # use subprocess.run because we don't care about the return value (we - # want to remove the volume in any case). - subprocess.run(["docker", "volume", "rm", volume_name]) - subprocess.check_call( - [ - "docker", - "volume", - "create", - "--name", - volume_name, - "--opt", - "type=none", - "--opt", - f"device={device_dir}", - "--opt", - "o=bind", - ] - ) - @classmethod def __run_entry_point_in_docker_container( cls, - repo: str, - repo_volumes: str, + repo_location: str, + config_location: str, baseline_config: str, current_config: str, ): + # we use the calling user to prevent the mapped volumes from changing + # owners + user_id = shell_call("id -u") + group_id = shell_call("id -g") subprocess.check_call( [ "docker", "run", + "-u", + f"{user_id}:{group_id}", "--rm", "-v", - f"repo-{repo}:/workspace/{repo}", - "-v", - f"config-{repo}:/workspace/config-{repo}", - "-v", - "/tmp:/tmp", + f"{repo_location}:/workspace/repo", "-v", - "/var/run/docker.sock:/var/run/docker.sock", - "-e", - "RUNNING_IN_DOCKER=true", - "-e", - f"REPO_BINDING_VOLUMES={repo_volumes}", + f"{config_location}:/workspace/config", "-w", - "/src", + "/workspace/repo", image_tag, - "python", - "/src/cli/entry_point.py", - "generate", - f"--baseline-generation-config-path=/workspace/config-{repo}/{baseline_config}", - f"--current-generation-config-path=/workspace/config-{repo}/{current_config}", - f"--repository-path=/workspace/{repo}", - ] + f"--baseline-generation-config-path=/workspace/config/{baseline_config}", + f"--current-generation-config-path=/workspace/config/{current_config}", + ], ) @classmethod diff --git a/library_generation/test/model/config_change_unit_tests.py b/library_generation/test/model/config_change_unit_tests.py index 388dd1f614..8349a7e1fa 100644 --- a/library_generation/test/model/config_change_unit_tests.py +++ b/library_generation/test/model/config_change_unit_tests.py @@ -240,11 +240,9 @@ def __get_a_gen_config( gapic_generator_version="", googleapis_commitish=googleapis_commitish, libraries_bom_version="", - owlbot_cli_image="", - synthtool_commitish="", template_excludes=[], grpc_version="", - protobuf_version="", + protoc_version="", libraries=libraries, ) diff --git a/library_generation/test/model/generation_config_unit_test.py b/library_generation/test/model/generation_config_unit_test.py index 08fea21523..d9efb494c0 100644 --- a/library_generation/test/model/generation_config_unit_test.py +++ b/library_generation/test/model/generation_config_unit_test.py @@ -41,18 +41,11 @@ class GenerationConfigTest(unittest.TestCase): def test_from_yaml_succeeds(self): config = from_yaml(f"{test_config_dir}/generation_config.yaml") self.assertEqual("2.34.0", config.gapic_generator_version) - self.assertEqual(25.2, config.protobuf_version) + self.assertEqual(25.2, config.protoc_version) self.assertEqual( "1a45bf7393b52407188c82e63101db7dc9c72026", config.googleapis_commitish ) self.assertEqual("26.37.0", config.libraris_bom_version) - self.assertEqual( - "sha256:623647ee79ac605858d09e60c1382a716c125fb776f69301b72de1cd35d49409", - config.owlbot_cli_image, - ) - self.assertEqual( - "6612ab8f3afcd5e292aecd647f0fa68812c9f5b5", config.synthtool_commitish - ) self.assertEqual( [ ".github/*", @@ -115,8 +108,6 @@ def test_is_monorepo_with_one_library_returns_false(self): gapic_generator_version="", googleapis_commitish="", libraries_bom_version="", - owlbot_cli_image="", - synthtool_commitish="", template_excludes=[], libraries=[library_1], ) @@ -127,9 +118,157 @@ def test_is_monorepo_with_two_libraries_returns_true(self): gapic_generator_version="", googleapis_commitish="", libraries_bom_version="", - owlbot_cli_image="", - synthtool_commitish="", template_excludes=[], libraries=[library_1, library_2], ) self.assertTrue(config.is_monorepo()) + + def test_validate_with_duplicate_library_name_raise_exception(self): + self.assertRaisesRegex( + ValueError, + "the same library name", + GenerationConfig, + gapic_generator_version="", + googleapis_commitish="", + libraries_bom_version="", + owlbot_cli_image="", + synthtool_commitish="", + template_excludes=[], + libraries=[ + LibraryConfig( + api_shortname="secretmanager", + name_pretty="Secret API", + product_documentation="", + api_description="", + gapic_configs=list(), + ), + LibraryConfig( + api_shortname="another-secret", + name_pretty="Another Secret API", + product_documentation="", + api_description="", + gapic_configs=list(), + library_name="secretmanager", + ), + ], + ) + + def test_from_yaml_without_gapic_generator_version_raise_exception(self): + self.assertRaisesRegex( + ValueError, + "Repo level parameter, gapic_generator_version", + from_yaml, + f"{test_config_dir}/config_without_generator.yaml", + ) + + def test_from_yaml_without_googleapis_commitish_raise_exception(self): + self.assertRaisesRegex( + ValueError, + "Repo level parameter, googleapis_commitish", + from_yaml, + f"{test_config_dir}/config_without_googleapis.yaml", + ) + + def test_from_yaml_without_libraries_bom_version_raise_exception(self): + self.assertRaisesRegex( + ValueError, + "Repo level parameter, libraries_bom_version", + from_yaml, + f"{test_config_dir}/config_without_libraries_bom_version.yaml", + ) + + def test_from_yaml_without_owlbot_cli_image_raise_exception(self): + self.assertRaisesRegex( + ValueError, + "Repo level parameter, owlbot_cli_image", + from_yaml, + f"{test_config_dir}/config_without_owlbot.yaml", + ) + + def test_from_yaml_without_synthtool_commitish_raise_exception(self): + self.assertRaisesRegex( + ValueError, + "Repo level parameter, synthtool_commitish", + from_yaml, + f"{test_config_dir}/config_without_synthtool.yaml", + ) + + def test_from_yaml_without_template_excludes_raise_exception(self): + self.assertRaisesRegex( + ValueError, + "Repo level parameter, template_excludes", + from_yaml, + f"{test_config_dir}/config_without_temp_excludes.yaml", + ) + + def test_from_yaml_without_libraries_raise_exception(self): + self.assertRaisesRegex( + ValueError, + "Repo level parameter, libraries", + from_yaml, + f"{test_config_dir}/config_without_libraries.yaml", + ) + + def test_from_yaml_without_api_shortname_raise_exception(self): + self.assertRaisesRegex( + ValueError, + "Library level parameter, api_shortname", + from_yaml, + f"{test_config_dir}/config_without_api_shortname.yaml", + ) + + def test_from_yaml_without_api_description_raise_exception(self): + self.assertRaisesRegex( + ValueError, + r"Library level parameter, api_description.*'api_shortname': 'apigeeconnect'.*", + from_yaml, + f"{test_config_dir}/config_without_api_description.yaml", + ) + + def test_from_yaml_without_name_pretty_raise_exception(self): + self.assertRaisesRegex( + ValueError, + r"Library level parameter, name_pretty.*'api_shortname': 'apigeeconnect'.*", + from_yaml, + f"{test_config_dir}/config_without_name_pretty.yaml", + ) + + def test_from_yaml_without_product_documentation_raise_exception(self): + self.assertRaisesRegex( + ValueError, + r"Library level parameter, product_documentation.*'api_shortname': 'apigeeconnect'.*", + from_yaml, + f"{test_config_dir}/config_without_product_docs.yaml", + ) + + def test_from_yaml_without_gapics_raise_exception(self): + self.assertRaisesRegex( + ValueError, + "Library level parameter, GAPICs.*'api_shortname': 'apigeeconnect'.*", + from_yaml, + f"{test_config_dir}/config_without_gapics_key.yaml", + ) + + def test_from_yaml_without_proto_path_raise_exception(self): + self.assertRaisesRegex( + ValueError, + "GAPIC level parameter, proto_path", + from_yaml, + f"{test_config_dir}/config_without_proto_path.yaml", + ) + + def test_from_yaml_with_zero_library_raise_exception(self): + self.assertRaisesRegex( + ValueError, + "Library is None", + from_yaml, + f"{test_config_dir}/config_without_library_value.yaml", + ) + + def test_from_yaml_with_zero_proto_path_raise_exception(self): + self.assertRaisesRegex( + ValueError, + r"GAPICs is None in.*'api_shortname': 'apigeeconnect'.*", + from_yaml, + f"{test_config_dir}/config_without_gapics_value.yaml", + ) diff --git a/library_generation/test/resources/integration/google-cloud-java/baseline_generation_config.yaml b/library_generation/test/resources/integration/google-cloud-java/baseline_generation_config.yaml index 9bfa47a7c5..2b13ebb50f 100644 --- a/library_generation/test/resources/integration/google-cloud-java/baseline_generation_config.yaml +++ b/library_generation/test/resources/integration/google-cloud-java/baseline_generation_config.yaml @@ -1,9 +1,7 @@ gapic_generator_version: 2.38.1 -protobuf_version: 25.2 +protoc_version: 25.2 googleapis_commitish: a17d4caf184b050d50cacf2b0d579ce72c31ce74 libraries_bom_version: 26.37.0 -owlbot_cli_image: sha256:623647ee79ac605858d09e60c1382a716c125fb776f69301b72de1cd35d49409 -synthtool_commitish: 63cc541da2c45fcfca2136c43e638da1fbae174d template_excludes: - ".github/*" - ".kokoro/*" @@ -56,4 +54,4 @@ libraries: api_description: Provides insights about your customers and their Assured Workloads based on your Sovereign Controls by Partners offering. GAPICs: - proto_path: google/cloud/cloudcontrolspartner/v1 - - proto_path: google/cloud/cloudcontrolspartner/v1beta \ No newline at end of file + - proto_path: google/cloud/cloudcontrolspartner/v1beta diff --git a/library_generation/test/resources/integration/google-cloud-java/current_generation_config.yaml b/library_generation/test/resources/integration/google-cloud-java/current_generation_config.yaml index 447c525424..995ab31eb9 100644 --- a/library_generation/test/resources/integration/google-cloud-java/current_generation_config.yaml +++ b/library_generation/test/resources/integration/google-cloud-java/current_generation_config.yaml @@ -1,9 +1,7 @@ gapic_generator_version: 2.38.1 -protobuf_version: 25.2 +protoc_version: 25.2 googleapis_commitish: 4ce0ff67a3d4509be641cbe47a35844ddc1268fc libraries_bom_version: 26.37.0 -owlbot_cli_image: sha256:623647ee79ac605858d09e60c1382a716c125fb776f69301b72de1cd35d49409 -synthtool_commitish: 63cc541da2c45fcfca2136c43e638da1fbae174d template_excludes: - ".github/*" - ".kokoro/*" @@ -56,4 +54,4 @@ libraries: api_description: Provides insights about your customers and their Assured Workloads based on your Sovereign Controls by Partners offering. GAPICs: - proto_path: google/cloud/cloudcontrolspartner/v1 - - proto_path: google/cloud/cloudcontrolspartner/v1beta \ No newline at end of file + - proto_path: google/cloud/cloudcontrolspartner/v1beta diff --git a/library_generation/test/resources/integration/java-bigtable/generation_config.yaml b/library_generation/test/resources/integration/java-bigtable/generation_config.yaml index 48afd9eef7..784206521f 100644 --- a/library_generation/test/resources/integration/java-bigtable/generation_config.yaml +++ b/library_generation/test/resources/integration/java-bigtable/generation_config.yaml @@ -1,8 +1,6 @@ gapic_generator_version: 2.37.0 -protobuf_version: 25.2 +protoc_version: 25.2 googleapis_commitish: 9868a57470a969ffa1d21194a5c05d7a6e4e98cc -owlbot_cli_image: sha256:623647ee79ac605858d09e60c1382a716c125fb776f69301b72de1cd35d49409 -synthtool_commitish: a6fb7d5f072b75698af1cbf06c5b001565753cfb template_excludes: - ".gitignore" - ".kokoro/presubmit/integration.cfg" diff --git a/library_generation/test/resources/test-config/config_without_gapics_key.yaml b/library_generation/test/resources/test-config/config_without_gapics_key.yaml new file mode 100644 index 0000000000..739a4d9239 --- /dev/null +++ b/library_generation/test/resources/test-config/config_without_gapics_key.yaml @@ -0,0 +1,3 @@ +gapic_generator_version: 2.34.0 +libraries: + - api_shortname: apigeeconnect diff --git a/library_generation/test/resources/test-config/config_without_gapics_value.yaml b/library_generation/test/resources/test-config/config_without_gapics_value.yaml new file mode 100644 index 0000000000..ec49e4a669 --- /dev/null +++ b/library_generation/test/resources/test-config/config_without_gapics_value.yaml @@ -0,0 +1,4 @@ +gapic_generator_version: 2.34.0 +libraries: + - api_shortname: apigeeconnect + GAPICs: diff --git a/library_generation/test/resources/test-config/config_without_gapics.yaml b/library_generation/test/resources/test-config/config_without_library_value.yaml similarity index 75% rename from library_generation/test/resources/test-config/config_without_gapics.yaml rename to library_generation/test/resources/test-config/config_without_library_value.yaml index 0f0c49fc48..174a293000 100644 --- a/library_generation/test/resources/test-config/config_without_gapics.yaml +++ b/library_generation/test/resources/test-config/config_without_library_value.yaml @@ -1,3 +1,2 @@ gapic_generator_version: 2.34.0 libraries: - random_key: diff --git a/library_generation/test/resources/test-config/config_without_owlbot.yaml b/library_generation/test/resources/test-config/config_without_owlbot.yaml deleted file mode 100644 index 0d1bb7deea..0000000000 --- a/library_generation/test/resources/test-config/config_without_owlbot.yaml +++ /dev/null @@ -1,10 +0,0 @@ -gapic_generator_version: 2.34.0 -googleapis_commitish: 1a45bf7393b52407188c82e63101db7dc9c72026 -libraries_bom_version: 26.37.0 -libraries: - - api_shortname: apigeeconnect - name_pretty: Apigee Connect - api_description: "allows the Apigee hybrid management" - product_documentation: "https://cloud.google.com/apigee/docs/hybrid/v1.3/apigee-connect/" - GAPICs: - - proto_path: google/cloud/apigeeconnect/v1 diff --git a/library_generation/test/resources/test-config/config_without_synthtool.yaml b/library_generation/test/resources/test-config/config_without_synthtool.yaml deleted file mode 100644 index 820c53032e..0000000000 --- a/library_generation/test/resources/test-config/config_without_synthtool.yaml +++ /dev/null @@ -1,11 +0,0 @@ -gapic_generator_version: 2.34.0 -googleapis_commitish: 1a45bf7393b52407188c82e63101db7dc9c72026 -libraries_bom_version: 26.37.0 -owlbot_cli_image: sha256:623647ee79ac605858d09e60c1382a716c125fb776f69301b72de1cd35d49409 -libraries: - - api_shortname: apigeeconnect - name_pretty: Apigee Connect - api_description: "allows the Apigee hybrid management" - product_documentation: "https://cloud.google.com/apigee/docs/hybrid/v1.3/apigee-connect/" - GAPICs: - - proto_path: google/cloud/apigeeconnect/v1 diff --git a/library_generation/test/resources/test-config/config_without_temp_excludes.yaml b/library_generation/test/resources/test-config/config_without_temp_excludes.yaml index 54dab6449d..0d1bb7deea 100644 --- a/library_generation/test/resources/test-config/config_without_temp_excludes.yaml +++ b/library_generation/test/resources/test-config/config_without_temp_excludes.yaml @@ -1,8 +1,6 @@ gapic_generator_version: 2.34.0 googleapis_commitish: 1a45bf7393b52407188c82e63101db7dc9c72026 libraries_bom_version: 26.37.0 -owlbot_cli_image: sha256:623647ee79ac605858d09e60c1382a716c125fb776f69301b72de1cd35d49409 -synthtool_commitish: 6612ab8f3afcd5e292aecd647f0fa68812c9f5b5 libraries: - api_shortname: apigeeconnect name_pretty: Apigee Connect diff --git a/library_generation/test/resources/test-config/generation_config.yaml b/library_generation/test/resources/test-config/generation_config.yaml index a6deecfeeb..6bd83e20d2 100644 --- a/library_generation/test/resources/test-config/generation_config.yaml +++ b/library_generation/test/resources/test-config/generation_config.yaml @@ -1,9 +1,7 @@ gapic_generator_version: 2.34.0 -protobuf_version: 25.2 +protoc_version: 25.2 googleapis_commitish: 1a45bf7393b52407188c82e63101db7dc9c72026 libraries_bom_version: 26.37.0 -owlbot_cli_image: sha256:623647ee79ac605858d09e60c1382a716c125fb776f69301b72de1cd35d49409 -synthtool_commitish: 6612ab8f3afcd5e292aecd647f0fa68812c9f5b5 template_excludes: - ".github/*" - ".kokoro/*" diff --git a/library_generation/test/resources/test-config/generation_config_with_duplicate_library_name.yaml b/library_generation/test/resources/test-config/generation_config_with_duplicate_library_name.yaml new file mode 100644 index 0000000000..c5613f4308 --- /dev/null +++ b/library_generation/test/resources/test-config/generation_config_with_duplicate_library_name.yaml @@ -0,0 +1,51 @@ +gapic_generator_version: 2.34.0 +protoc_version: 25.2 +googleapis_commitish: 1a45bf7393b52407188c82e63101db7dc9c72026 +libraries_bom_version: 26.37.0 +owlbot_cli_image: sha256:623647ee79ac605858d09e60c1382a716c125fb776f69301b72de1cd35d49409 +synthtool_commitish: 6612ab8f3afcd5e292aecd647f0fa68812c9f5b5 +template_excludes: + - ".github/*" + - ".kokoro/*" + - "samples/*" + - "CODE_OF_CONDUCT.md" + - "CONTRIBUTING.md" + - "LICENSE" + - "SECURITY.md" + - "java.header" + - "license-checks.xml" + - "renovate.json" + - ".gitignore" +libraries: + - api_shortname: cloudasset + name_pretty: Cloud Asset + product_documentation: "https://cloud.google.com/resource-manager/docs/cloud-asset-inventory/overview" + api_description: "provides inventory services based on a time series database." + library_name: "asset" + client_documentation: "https://cloud.google.com/java/docs/reference/google-cloud-asset/latest/overview" + distribution_name: "com.google.cloud:google-cloud-asset" + release_level: "stable" + issue_tracker: "https://issuetracker.google.com/issues/new?component=187210&template=0" + api_reference: "https://cloud.google.com/resource-manager/docs/cloud-asset-inventory/overview" + codeowner_team: "@googleapis/analytics-dpe" + excluded_poms: proto-google-iam-v1-bom,google-iam-policy,proto-google-iam-v1 + excluded_dependencies: google-iam-policy + GAPICs: + - proto_path: google/cloud/asset/v1 + - proto_path: google/cloud/asset/v1p1beta1 + - proto_path: google/cloud/asset/v1p2beta1 + - proto_path: google/cloud/asset/v1p5beta1 + - proto_path: google/cloud/asset/v1p7beta1 + + - api_shortname: another-cloudasset + name_pretty: Cloud Asset Inventory + product_documentation: "https://cloud.google.com/resource-manager/docs/cloud-asset-inventory/overview" + api_description: "provides inventory services based on a time series database." + library_name: "asset" + client_documentation: "https://cloud.google.com/java/docs/reference/google-cloud-asset/latest/overview" + distribution_name: "com.google.cloud:google-cloud-asset" + release_level: "stable" + issue_tracker: "https://issuetracker.google.com/issues/new?component=187210&template=0" + api_reference: "https://cloud.google.com/resource-manager/docs/cloud-asset-inventory/overview" + GAPICs: + - proto_path: google/cloud/asset/v1 diff --git a/library_generation/test/resources/test_monorepo_postprocessing/pom-golden.xml b/library_generation/test/resources/test_monorepo_postprocessing/pom-golden.xml index 8347287bc3..44a1df9409 100644 --- a/library_generation/test/resources/test_monorepo_postprocessing/pom-golden.xml +++ b/library_generation/test/resources/test_monorepo_postprocessing/pom-golden.xml @@ -25,7 +25,7 @@ org.apache.maven.plugins maven-deploy-plugin - 3.1.1 + 3.1.2 true diff --git a/library_generation/test/utilities_unit_tests.py b/library_generation/test/utilities_unit_tests.py index 5e5869d0c1..736eba26e4 100644 --- a/library_generation/test/utilities_unit_tests.py +++ b/library_generation/test/utilities_unit_tests.py @@ -26,7 +26,6 @@ from library_generation.model.gapic_config import GapicConfig from library_generation.model.generation_config import GenerationConfig from library_generation.model.gapic_inputs import parse as parse_build_file -from library_generation.model.generation_config import from_yaml from library_generation.model.library_config import LibraryConfig from library_generation.test.test_utils import FileComparator from library_generation.test.test_utils import cleanup @@ -114,55 +113,6 @@ def test_eprint_valid_input_succeeds(self): # print() appends a `\n` each time it's called self.assertEqual(test_input + "\n", result) - # parameterized tests need to run from the class, see - # https://github.com/wolever/parameterized/issues/37 for more info. - # This test confirms that a ValueError with an error message about a - # missing key (specified in the first parameter of each `parameterized` - # tuple) when parsing a test configuration yaml (second parameter) will - # be raised. - @parameterized.expand( - [ - ("libraries", f"{test_config_dir}/config_without_libraries.yaml"), - ("GAPICs", f"{test_config_dir}/config_without_gapics.yaml"), - ("proto_path", f"{test_config_dir}/config_without_proto_path.yaml"), - ("api_shortname", f"{test_config_dir}/config_without_api_shortname.yaml"), - ( - "api_description", - f"{test_config_dir}/config_without_api_description.yaml", - ), - ("name_pretty", f"{test_config_dir}/config_without_name_pretty.yaml"), - ( - "product_documentation", - f"{test_config_dir}/config_without_product_docs.yaml", - ), - ( - "gapic_generator_version", - f"{test_config_dir}/config_without_generator.yaml", - ), - ( - "googleapis_commitish", - f"{test_config_dir}/config_without_googleapis.yaml", - ), - ( - "libraries_bom_version", - f"{test_config_dir}/config_without_libraries_bom_version.yaml", - ), - ("owlbot_cli_image", f"{test_config_dir}/config_without_owlbot.yaml"), - ("synthtool_commitish", f"{test_config_dir}/config_without_synthtool.yaml"), - ( - "template_excludes", - f"{test_config_dir}/config_without_temp_excludes.yaml", - ), - ] - ) - def test_from_yaml_without_key_fails(self, error_message_contains, path_to_yaml): - self.assertRaisesRegex( - ValueError, - error_message_contains, - from_yaml, - path_to_yaml, - ) - @parameterized.expand( [ ("BUILD_no_additional_protos.bazel", " "), @@ -344,17 +294,6 @@ def test_prepare_repo_monorepo_success(self): ["java-bare-metal-solution", "java-secretmanager"], library_path ) - def test_prepare_repo_monorepo_duplicated_library_name_failed(self): - gen_config = self.__get_a_gen_config(3) - self.assertRaisesRegex( - ValueError, - "secretmanager", - util.prepare_repo, - gen_config, - gen_config.libraries, - f"{resources_dir}/misc", - ) - def test_prepare_repo_monorepo_failed(self): gen_config = self.__get_a_gen_config(2) self.assertRaises( @@ -433,8 +372,6 @@ def __get_a_gen_config( gapic_generator_version="", googleapis_commitish="", libraries_bom_version="", - owlbot_cli_image="", - synthtool_commitish="", template_excludes=[ ".github/*", ".kokoro/*", diff --git a/library_generation/test/utils/generation_config_comparator_unit_tests.py b/library_generation/test/utils/generation_config_comparator_unit_tests.py index a782cebe21..fa466ac34d 100644 --- a/library_generation/test/utils/generation_config_comparator_unit_tests.py +++ b/library_generation/test/utils/generation_config_comparator_unit_tests.py @@ -40,22 +40,18 @@ def setUp(self) -> None: gapic_generator_version="", googleapis_commitish="", libraries_bom_version="", - owlbot_cli_image="", - synthtool_commitish="", template_excludes=[], grpc_version="", - protobuf_version="", + protoc_version="", libraries=[self.baseline_library], ) self.current_config = GenerationConfig( gapic_generator_version="", googleapis_commitish="", libraries_bom_version="", - owlbot_cli_image="", - synthtool_commitish="", template_excludes=[], grpc_version="", - protobuf_version="", + protoc_version="", libraries=[self.current_library], ) @@ -107,37 +103,9 @@ def test_compare_config_libraries_bom_update(self): self.assertEqual("libraris_bom_version", config_change.changed_param) self.assertEqual("26.37.0", config_change.current_value) - def test_compare_config_owlbot_cli_update(self): - self.baseline_config.owlbot_cli_image = "image_version_123" - self.current_config.owlbot_cli_image = "image_version_456" - result = compare_config( - baseline_config=self.baseline_config, - current_config=self.current_config, - ) - self.assertTrue( - len(result.change_to_libraries[ChangeType.REPO_LEVEL_CHANGE]) == 1 - ) - config_change = result.change_to_libraries[ChangeType.REPO_LEVEL_CHANGE][0] - self.assertEqual("owlbot_cli_image", config_change.changed_param) - self.assertEqual("image_version_456", config_change.current_value) - - def test_compare_config_synthtool_update(self): - self.baseline_config.synthtool_commitish = "commit123" - self.current_config.synthtool_commitish = "commit456" - result = compare_config( - baseline_config=self.baseline_config, - current_config=self.current_config, - ) - self.assertTrue( - len(result.change_to_libraries[ChangeType.REPO_LEVEL_CHANGE]) == 1 - ) - config_change = result.change_to_libraries[ChangeType.REPO_LEVEL_CHANGE][0] - self.assertEqual("synthtool_commitish", config_change.changed_param) - self.assertEqual("commit456", config_change.current_value) - def test_compare_protobuf_update(self): - self.baseline_config.protobuf_version = "3.25.2" - self.current_config.protobuf_version = "3.27.0" + self.baseline_config.protoc_version = "3.25.2" + self.current_config.protoc_version = "3.27.0" result = compare_config( baseline_config=self.baseline_config, current_config=self.current_config, @@ -146,7 +114,7 @@ def test_compare_protobuf_update(self): len(result.change_to_libraries[ChangeType.REPO_LEVEL_CHANGE]) == 1 ) config_change = result.change_to_libraries[ChangeType.REPO_LEVEL_CHANGE][0] - self.assertEqual("protobuf_version", config_change.changed_param) + self.assertEqual("protoc_version", config_change.changed_param) self.assertEqual("3.27.0", config_change.current_value) def test_compare_config_grpc_update(self): diff --git a/library_generation/utils/utilities.py b/library_generation/utils/utilities.py index 1456ede48f..71c58f0455 100755 --- a/library_generation/utils/utilities.py +++ b/library_generation/utils/utilities.py @@ -130,10 +130,6 @@ def prepare_repo( # use absolute path because docker requires absolute path # in volume name. absolute_library_path = str(Path(library_path).resolve()) - if absolute_library_path in libraries: - # check whether the java_library is unique among all libraries - # because two libraries should not go to the same destination. - raise ValueError(f"{absolute_library_path} already exists.") libraries[absolute_library_path] = library # remove existing .repo-metadata.json json_name = ".repo-metadata.json" diff --git a/library_generation/utils/utilities.sh b/library_generation/utils/utilities.sh index 1c3feb937b..16ad766ce5 100755 --- a/library_generation/utils/utilities.sh +++ b/library_generation/utils/utilities.sh @@ -108,25 +108,25 @@ get_grpc_version() { echo "${grpc_version}" } -get_protobuf_version() { +get_protoc_version() { local gapic_generator_version=$1 - local protobuf_version + local protoc_version pushd "${output_folder}" > /dev/null # get protobuf version from gapic-generator-java-pom-parent/pom.xml download_gapic_generator_pom_parent "${gapic_generator_version}" - protobuf_version=$(grep protobuf.version "gapic-generator-java-pom-parent-${gapic_generator_version}.pom" | sed 's/\(.*\)<\/protobuf\.version>/\1/' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | cut -d "." -f2-) + protoc_version=$(grep protobuf.version "gapic-generator-java-pom-parent-${gapic_generator_version}.pom" | sed 's/\(.*\)<\/protobuf\.version>/\1/' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | cut -d "." -f2-) popd > /dev/null - echo "${protobuf_version}" + echo "${protoc_version}" } download_tools() { local gapic_generator_version=$1 - local protobuf_version=$2 + local protoc_version=$2 local grpc_version=$3 local os_architecture=$4 pushd "${output_folder}" download_generator_artifact "${gapic_generator_version}" "gapic-generator-java-${gapic_generator_version}.jar" - download_protobuf "${protobuf_version}" "${os_architecture}" + download_protoc "${protoc_version}" "${os_architecture}" download_grpc_plugin "${grpc_version}" "${os_architecture}" popd } @@ -154,22 +154,22 @@ download_generator_artifact() { fi } -download_protobuf() { - local protobuf_version=$1 +download_protoc() { + local protoc_version=$1 local os_architecture=$2 - if [ ! -d "protobuf-${protobuf_version}" ]; then + if [ ! -d "protoc-${protoc_version}" ]; then # pull proto files and protoc from protobuf repository as maven central # doesn't have proto files download_from \ - "https://github.com/protocolbuffers/protobuf/releases/download/v${protobuf_version}/protoc-${protobuf_version}-${os_architecture}.zip" \ - "protobuf-${protobuf_version}.zip" \ + "https://github.com/protocolbuffers/protobuf/releases/download/v${protoc_version}/protoc-${protoc_version}-${os_architecture}.zip" \ + "protoc-${protoc_version}.zip" \ "GitHub" - unzip -o -q "protobuf-${protobuf_version}.zip" -d "protobuf-${protobuf_version}" - cp -r "protobuf-${protobuf_version}/include/google" . - rm "protobuf-${protobuf_version}.zip" + unzip -o -q "protoc-${protoc_version}.zip" -d "protoc-${protoc_version}" + cp -r "protoc-${protoc_version}/include/google" . + rm "protoc-${protoc_version}.zip" fi - protoc_path="${output_folder}/protobuf-${protobuf_version}/bin" + protoc_path="${output_folder}/protoc-${protoc_version}/bin" } download_grpc_plugin() { diff --git a/pom.xml b/pom.xml index bb18ea81cd..a26c57a42a 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ org.apache.maven.plugins maven-deploy-plugin - 3.1.1 + 3.1.2 true diff --git a/showcase/gapic-showcase/src/main/java/com/google/showcase/v1beta1/stub/EchoStubSettings.java b/showcase/gapic-showcase/src/main/java/com/google/showcase/v1beta1/stub/EchoStubSettings.java index 1e659ed8d7..a54d329a0e 100644 --- a/showcase/gapic-showcase/src/main/java/com/google/showcase/v1beta1/stub/EchoStubSettings.java +++ b/showcase/gapic-showcase/src/main/java/com/google/showcase/v1beta1/stub/EchoStubSettings.java @@ -479,8 +479,8 @@ public static TransportChannelProvider defaultTransportChannelProvider() { public static ApiClientHeaderProvider.Builder defaultGrpcApiClientHeaderProviderBuilder() { return ApiClientHeaderProvider.newBuilder() .setGeneratedLibToken("gapic", GaxProperties.getLibraryVersion(EchoStubSettings.class)) - .setTransportToken( - GaxGrpcProperties.getGrpcTokenName(), GaxGrpcProperties.getGrpcVersion()); + .setTransportToken(GaxGrpcProperties.getGrpcTokenName(), GaxGrpcProperties.getGrpcVersion()) + .setApiVersionToken("v1_20240408"); } public static ApiClientHeaderProvider.Builder defaultHttpJsonApiClientHeaderProviderBuilder() { @@ -488,7 +488,8 @@ public static ApiClientHeaderProvider.Builder defaultHttpJsonApiClientHeaderProv .setGeneratedLibToken("gapic", GaxProperties.getLibraryVersion(EchoStubSettings.class)) .setTransportToken( GaxHttpJsonProperties.getHttpJsonTokenName(), - GaxHttpJsonProperties.getHttpJsonVersion()); + GaxHttpJsonProperties.getHttpJsonVersion()) + .setApiVersionToken("v1_20240408"); } public static ApiClientHeaderProvider.Builder defaultApiClientHeaderProviderBuilder() {