diff --git a/.cloudbuild/graalvm/cloudbuild-test-a-downstream-kms.yaml b/.cloudbuild/graalvm/cloudbuild-test-a-downstream-kms.yaml index 0ff3ee6986..b0d07a5b7d 100644 --- a/.cloudbuild/graalvm/cloudbuild-test-a-downstream-kms.yaml +++ b/.cloudbuild/graalvm/cloudbuild-test-a-downstream-kms.yaml @@ -15,7 +15,7 @@ timeout: 7200s # 2 hours substitutions: _SHARED_DEPENDENCIES_VERSION: '3.30.1-SNAPSHOT' # {x-version-update:google-cloud-shared-dependencies:current} - _JAVA_SHARED_CONFIG_VERSION: '1.8.0' + _JAVA_SHARED_CONFIG_VERSION: '1.8.1' options: machineType: 'E2_HIGHCPU_8' steps: diff --git a/.cloudbuild/graalvm/cloudbuild-test-a-downstream-kmsinventory.yaml b/.cloudbuild/graalvm/cloudbuild-test-a-downstream-kmsinventory.yaml index 79e08a9f9c..f58a759cf4 100644 --- a/.cloudbuild/graalvm/cloudbuild-test-a-downstream-kmsinventory.yaml +++ b/.cloudbuild/graalvm/cloudbuild-test-a-downstream-kmsinventory.yaml @@ -15,7 +15,7 @@ timeout: 7200s # 2 hours substitutions: _SHARED_DEPENDENCIES_VERSION: '3.30.1-SNAPSHOT' # {x-version-update:google-cloud-shared-dependencies:current} - _JAVA_SHARED_CONFIG_VERSION: '1.8.0' + _JAVA_SHARED_CONFIG_VERSION: '1.8.1' options: machineType: 'E2_HIGHCPU_8' steps: diff --git a/.cloudbuild/graalvm/cloudbuild-test-a.yaml b/.cloudbuild/graalvm/cloudbuild-test-a.yaml index c1832db54f..7e21506f57 100644 --- a/.cloudbuild/graalvm/cloudbuild-test-a.yaml +++ b/.cloudbuild/graalvm/cloudbuild-test-a.yaml @@ -14,8 +14,8 @@ timeout: 7200s # 2 hours substitutions: - _SHARED_DEPENDENCIES_VERSION: '3.31.0' # {x-version-update:google-cloud-shared-dependencies:current} - _JAVA_SHARED_CONFIG_VERSION: '1.8.0' + _SHARED_DEPENDENCIES_VERSION: '3.32.0' # {x-version-update:google-cloud-shared-dependencies:current} + _JAVA_SHARED_CONFIG_VERSION: '1.8.1' options: machineType: 'E2_HIGHCPU_8' steps: diff --git a/.cloudbuild/graalvm/cloudbuild-test-b-downstream-kms.yaml b/.cloudbuild/graalvm/cloudbuild-test-b-downstream-kms.yaml index 28ab65bc44..5d4da64801 100644 --- a/.cloudbuild/graalvm/cloudbuild-test-b-downstream-kms.yaml +++ b/.cloudbuild/graalvm/cloudbuild-test-b-downstream-kms.yaml @@ -15,7 +15,7 @@ timeout: 7200s # 2 hours substitutions: _SHARED_DEPENDENCIES_VERSION: '3.30.1-SNAPSHOT' # {x-version-update:google-cloud-shared-dependencies:current} - _JAVA_SHARED_CONFIG_VERSION: '1.8.0' + _JAVA_SHARED_CONFIG_VERSION: '1.8.1' options: machineType: 'E2_HIGHCPU_8' steps: diff --git a/.cloudbuild/graalvm/cloudbuild-test-b-downstream-kmsinventory.yaml b/.cloudbuild/graalvm/cloudbuild-test-b-downstream-kmsinventory.yaml index 8e5b02be45..28d418c32b 100644 --- a/.cloudbuild/graalvm/cloudbuild-test-b-downstream-kmsinventory.yaml +++ b/.cloudbuild/graalvm/cloudbuild-test-b-downstream-kmsinventory.yaml @@ -15,7 +15,7 @@ timeout: 7200s # 2 hours substitutions: _SHARED_DEPENDENCIES_VERSION: '3.30.1-SNAPSHOT' # {x-version-update:google-cloud-shared-dependencies:current} - _JAVA_SHARED_CONFIG_VERSION: '1.8.0' + _JAVA_SHARED_CONFIG_VERSION: '1.8.1' options: machineType: 'E2_HIGHCPU_8' steps: diff --git a/.cloudbuild/graalvm/cloudbuild-test-b.yaml b/.cloudbuild/graalvm/cloudbuild-test-b.yaml index abb4531de8..313e6e70f8 100644 --- a/.cloudbuild/graalvm/cloudbuild-test-b.yaml +++ b/.cloudbuild/graalvm/cloudbuild-test-b.yaml @@ -14,8 +14,8 @@ timeout: 7200s # 2 hours substitutions: - _SHARED_DEPENDENCIES_VERSION: '3.31.0' # {x-version-update:google-cloud-shared-dependencies:current} - _JAVA_SHARED_CONFIG_VERSION: '1.8.0' + _SHARED_DEPENDENCIES_VERSION: '3.32.0' # {x-version-update:google-cloud-shared-dependencies:current} + _JAVA_SHARED_CONFIG_VERSION: '1.8.1' options: machineType: 'E2_HIGHCPU_8' steps: diff --git a/.cloudbuild/graalvm/cloudbuild.yaml b/.cloudbuild/graalvm/cloudbuild.yaml index f3151a7465..e95934666f 100644 --- a/.cloudbuild/graalvm/cloudbuild.yaml +++ b/.cloudbuild/graalvm/cloudbuild.yaml @@ -14,8 +14,8 @@ timeout: 7200s # 2 hours substitutions: - _SHARED_DEPENDENCIES_VERSION: '3.31.0' # {x-version-update:google-cloud-shared-dependencies:current} - _JAVA_SHARED_CONFIG_VERSION: '1.8.0' + _SHARED_DEPENDENCIES_VERSION: '3.32.0' # {x-version-update:google-cloud-shared-dependencies:current} + _JAVA_SHARED_CONFIG_VERSION: '1.8.1' steps: # GraalVM A build - name: gcr.io/cloud-builders/docker diff --git a/.cloudbuild/library_generation/cloudbuild-library-generation-push.yaml b/.cloudbuild/library_generation/cloudbuild-library-generation-push.yaml index 296cdb6db5..2025a6c481 100644 --- a/.cloudbuild/library_generation/cloudbuild-library-generation-push.yaml +++ b/.cloudbuild/library_generation/cloudbuild-library-generation-push.yaml @@ -15,8 +15,10 @@ timeout: 7200s # 2 hours substitutions: _IMAGE_NAME: "gcr.io/cloud-devrel-public-resources/java-library-generation" + _GAPIC_GENERATOR_JAVA_VERSION: '2.41.1-SNAPSHOT' # {x-version-update:gapic-generator-java:current} _SHA_IMAGE_ID: "${_IMAGE_NAME}:${COMMIT_SHA}" _LATEST_IMAGE_ID: "${_IMAGE_NAME}:latest" + _VERSIONED_IMAGE_ID: "${_IMAGE_NAME}:${_GAPIC_GENERATOR_JAVA_VERSION}" steps: # Library generation build - name: gcr.io/cloud-builders/docker @@ -24,6 +26,7 @@ steps: "build", "-t", "${_SHA_IMAGE_ID}", "-t", "${_LATEST_IMAGE_ID}", + "-t", "${_VERSIONED_IMAGE_ID}", "--file", ".cloudbuild/library_generation/library_generation.Dockerfile", "."] id: library-generation-build waitFor: ["-"] @@ -31,3 +34,4 @@ steps: images: - ${_SHA_IMAGE_ID} - ${_LATEST_IMAGE_ID} + - ${_VERSIONED_IMAGE_ID} diff --git a/.cloudbuild/library_generation/cloudbuild-library-generation-release.yaml b/.cloudbuild/library_generation/cloudbuild-library-generation-release.yaml deleted file mode 100644 index 7a3664f169..0000000000 --- a/.cloudbuild/library_generation/cloudbuild-library-generation-release.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2024 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -timeout: 7200s # 2 hours -substitutions: - _GAPIC_GENERATOR_JAVA_VERSION: '2.41.0' # {x-version-update:gapic-generator-java:current} - _IMAGE_ID: "gcr.io/cloud-devrel-public-resources/java-library-generation:${_GAPIC_GENERATOR_JAVA_VERSION}" -steps: - # Library generation build - - name: gcr.io/cloud-builders/docker - args: [ - "build", - "-t", "${_IMAGE_ID}", - "--file", ".cloudbuild/library_generation/library_generation.Dockerfile", "."] - id: library-generation-build - waitFor: ["-"] - -images: - - ${_IMAGE_ID} - diff --git a/.github/scripts/hermetic_library_generation.sh b/.github/scripts/hermetic_library_generation.sh index a2337a88a4..cf29c87b3f 100755 --- a/.github/scripts/hermetic_library_generation.sh +++ b/.github/scripts/hermetic_library_generation.sh @@ -2,10 +2,10 @@ set -e # This script should be run at the root of the repository. # This script is used to, when a pull request changes the generation -# configuration (generation_config.yaml by default): +# configuration (generation_config.yaml by default) or Dockerfile: # 1. Find whether the last commit in this pull request contains changes to -# the generation configuration and exit early if it doesn't have such a change -# since the generation result would be the same. +# the generation configuration and Dockerfile and exit early if it doesn't have +# such a change since the generation result would be the same. # 2. Compare generation configurations in the current branch (with which the # pull request associated) and target branch (into which the pull request is # merged); @@ -17,6 +17,7 @@ set -e # 1. git # 2. gh # 3. docker +# 4. mvn # The parameters of this script is: # 1. target_branch, the branch into which the pull request is merged. @@ -73,6 +74,7 @@ fi workspace_name="/workspace" baseline_generation_config="baseline_generation_config.yaml" +docker_file="library_generation.Dockerfile" message="chore: generate libraries at $(date)" git checkout "${target_branch}" @@ -80,14 +82,22 @@ git checkout "${current_branch}" # if the last commit doesn't contain changes to generation configuration, # do not generate again as the result will be the same. change_of_last_commit="$(git diff-tree --no-commit-id --name-only HEAD~1..HEAD -r)" -if [[ ! ("${change_of_last_commit}" == *"${generation_config}"*) ]]; then - echo "The last commit doesn't contain any changes to the generation_config.yaml, skipping the whole generation process." || true +if [[ ! ("${change_of_last_commit}" == *"${generation_config}"* || "${change_of_last_commit}" == *"${docker_file}"*) ]]; then + echo "The last commit doesn't contain any changes to the generation_config.yaml or Dockerfile, skipping the whole generation process." || true exit 0 fi # copy generation configuration from target branch to current branch. git show "${target_branch}":"${generation_config}" > "${baseline_generation_config}" config_diff=$(diff "${generation_config}" "${baseline_generation_config}" || true) +# install generator locally since we're using a SNAPSHOT version. +mvn -V -B -ntp clean install -DskipTests + +# build image locally since we want to include latest change. +docker build \ + -f .cloudbuild/library_generation/library_generation.Dockerfile \ + -t gcr.io/cloud-devrel-public-resources/java-library-generation:"${image_tag}" \ + . # run hermetic code generation docker image. docker run \ --rm \ @@ -103,7 +113,7 @@ rm -rdf output googleapis "${baseline_generation_config}" git add --all -- ':!pr_description.txt' changed_files=$(git diff --cached --name-only) if [[ "${changed_files}" == "" ]]; then - echo "There is no generated code change with the generation config change ${config_diff}." + echo "There is no generated code change with the generation config and Dockerfile change ${config_diff}." echo "Skip committing to the pull request." exit 0 fi diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b16d799d4e..f6a43b3557 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -327,7 +327,7 @@ jobs: run: | mvn install -B -ntp -DskipTests -Dclirr.skip -Dcheckstyle.skip - name: Validate gapic-generator-java-bom - uses: googleapis/java-cloud-bom/tests/validate-bom@59c776be18728bcdc53f868c497baf1f5039abb6 + uses: googleapis/java-cloud-bom/tests/validate-bom@17cc5ecf3730d0671f233c0879dc654337b38cba with: bom-path: gapic-generator-java-bom/pom.xml diff --git a/.github/workflows/hermetic_library_generation.yaml b/.github/workflows/hermetic_library_generation.yaml index c613fa90c9..ab4f59b08f 100644 --- a/.github/workflows/hermetic_library_generation.yaml +++ b/.github/workflows/hermetic_library_generation.yaml @@ -27,17 +27,6 @@ jobs: with: fetch-depth: 0 token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }} - - name: Build image - shell: bash - run: | - docker build \ - -f .cloudbuild/library_generation/library_generation.Dockerfile \ - -t gcr.io/cloud-devrel-public-resources/java-library-generation:latest \ - . - - name: Install gapic-generator-java-pom-parent - shell: bash - run: | - mvn clean install -pl gapic-generator-java-pom-parent - name: Generate changed libraries shell: bash run: | diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 29ad411bac..c33eb8cbe1 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.41.0" + ".": "2.42.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b387baa108..6044a91fbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,37 @@ # Changelog +## [2.42.0](https://github.com/googleapis/sdk-platform-java/compare/v2.41.0...v2.42.0) (2024-06-25) + + +### Features + +* Allow Adding Client Level Attributes to MetricsTracerFactory ([#2614](https://github.com/googleapis/sdk-platform-java/issues/2614)) ([f122c6f](https://github.com/googleapis/sdk-platform-java/commit/f122c6f3beebd005a257fe687cf018baf7673b63)) +* gapic-generator-java to perform a no-op when no services are detected ([#2460](https://github.com/googleapis/sdk-platform-java/issues/2460)) ([c0b5646](https://github.com/googleapis/sdk-platform-java/commit/c0b56462a1550c3720a3e5d0b11dcc1a21add7ef)) +* Make Layout Parser generally available in V1 ([e508ae6](https://github.com/googleapis/sdk-platform-java/commit/e508ae69e13455ba2f5c325e0c33d9ff2704e3b1)) +* populate `.repo-metadata.json` from highest version ([#2890](https://github.com/googleapis/sdk-platform-java/issues/2890)) ([f587541](https://github.com/googleapis/sdk-platform-java/commit/f58754178d16e5054326d78d1d372efe1408fa5e)) +* push SNAPSHOT versions of the hermetic build docker image ([#2888](https://github.com/googleapis/sdk-platform-java/issues/2888)) ([81df866](https://github.com/googleapis/sdk-platform-java/commit/81df8660f85785ac7f8ff07ba7686caa0bfd583d)) + + +### Bug Fixes + +* **deps:** update the Java code generator (gapic-generator-java) to 1.2.3 ([e508ae6](https://github.com/googleapis/sdk-platform-java/commit/e508ae69e13455ba2f5c325e0c33d9ff2704e3b1)) +* Expose Gax meter name ([#2865](https://github.com/googleapis/sdk-platform-java/issues/2865)) ([6c5d6ce](https://github.com/googleapis/sdk-platform-java/commit/6c5d6cee7d5034dfc20c43a520d6321689299f21)) +* Move the logic of getting systemProductName from static block to static method ([#2874](https://github.com/googleapis/sdk-platform-java/issues/2874)) ([536f1eb](https://github.com/googleapis/sdk-platform-java/commit/536f1eb6658b44794e9dbba7d9536ecfade84cc3)) +* Update default Otel Attribute from method_name to method ([#2833](https://github.com/googleapis/sdk-platform-java/issues/2833)) ([af10a9e](https://github.com/googleapis/sdk-platform-java/commit/af10a9ef26a5fd9f24fc5341d144b8ee00ff3d00)) + + +### Dependencies + +* update dependency com.google.auto.value:auto-value to v1.11.0 ([#2842](https://github.com/googleapis/sdk-platform-java/issues/2842)) ([dd27fdf](https://github.com/googleapis/sdk-platform-java/commit/dd27fdf03ed756799212ba34a99568b234e13a2a)) +* update dependency com.google.auto.value:auto-value-annotations to v1.11.0 ([#2843](https://github.com/googleapis/sdk-platform-java/issues/2843)) ([bf8e67f](https://github.com/googleapis/sdk-platform-java/commit/bf8e67f3f4c582b7584b6811eb2ae6cb46f8c90e)) +* update dependency com.google.cloud:grpc-gcp to v1.6.1 ([#2943](https://github.com/googleapis/sdk-platform-java/issues/2943)) ([9f16b40](https://github.com/googleapis/sdk-platform-java/commit/9f16b403807a97d8e620aeb5feb74dc4e14367e1)) +* update dependency org.checkerframework:checker-qual to v3.44.0 ([#2848](https://github.com/googleapis/sdk-platform-java/issues/2848)) ([7a99c50](https://github.com/googleapis/sdk-platform-java/commit/7a99c508695e342e10e011dea9bbab371df61ac4)) +* update dependency org.easymock:easymock to v5.3.0 ([#2871](https://github.com/googleapis/sdk-platform-java/issues/2871)) ([c243f7d](https://github.com/googleapis/sdk-platform-java/commit/c243f7dbea5441620364cd51f1829f2690628661)) +* update google api dependencies ([#2846](https://github.com/googleapis/sdk-platform-java/issues/2846)) ([b5ef698](https://github.com/googleapis/sdk-platform-java/commit/b5ef6983f8474c8444caf650116fb34b2e602636)) +* update googleapis/java-cloud-bom digest to 17cc5ec ([#2882](https://github.com/googleapis/sdk-platform-java/issues/2882)) ([d6abd8e](https://github.com/googleapis/sdk-platform-java/commit/d6abd8e0aa37de42038c47e262020a7dd9090907)) +* update netty dependencies to v4.1.111.final ([#2877](https://github.com/googleapis/sdk-platform-java/issues/2877)) ([b5f10b9](https://github.com/googleapis/sdk-platform-java/commit/b5f10b94a16e065aba5d5abe6c0348be87ecf01b)) +* update opentelemetry-java monorepo to v1.39.0 ([#2863](https://github.com/googleapis/sdk-platform-java/issues/2863)) ([9d1f3a8](https://github.com/googleapis/sdk-platform-java/commit/9d1f3a8cd7478df6068b9171c8dc8eb65dc70313)) + ## [2.41.0](https://github.com/googleapis/sdk-platform-java/compare/v2.40.1...v2.41.0) (2024-05-31) diff --git a/WORKSPACE b/WORKSPACE index 152dd88731..ccc806d3de 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -60,7 +60,7 @@ maven_install( repositories = ["https://repo.maven.apache.org/maven2/"], ) -_gapic_generator_java_version = "2.41.0" # {x-version-update:gapic-generator-java:current} +_gapic_generator_java_version = "2.42.0" # {x-version-update:gapic-generator-java:current} maven_install( artifacts = [ diff --git a/api-common-java/pom.xml b/api-common-java/pom.xml index 7cd24ea30b..a6b0b4f34a 100644 --- a/api-common-java/pom.xml +++ b/api-common-java/pom.xml @@ -5,14 +5,14 @@ com.google.api api-common jar - 2.32.0 + 2.33.0 API Common Common utilities for Google APIs in Java com.google.api gapic-generator-java-pom-parent - 2.41.0 + 2.42.0 ../gapic-generator-java-pom-parent diff --git a/coverage-report/pom.xml b/coverage-report/pom.xml index 5ac82165f6..21fbe1757a 100644 --- a/coverage-report/pom.xml +++ b/coverage-report/pom.xml @@ -31,22 +31,22 @@ com.google.api gax - 2.49.0 + 2.50.0 com.google.api gax-grpc - 2.49.0 + 2.50.0 com.google.api gax-httpjson - 2.49.0 + 2.50.0 com.google.api api-common - 2.32.0 + 2.33.0 diff --git a/gapic-generator-java-bom/pom.xml b/gapic-generator-java-bom/pom.xml index c3daa4e14a..ed9169c3c1 100644 --- a/gapic-generator-java-bom/pom.xml +++ b/gapic-generator-java-bom/pom.xml @@ -4,7 +4,7 @@ com.google.api gapic-generator-java-bom pom - 2.41.0 + 2.42.0 GAPIC Generator Java BOM BOM for the libraries in gapic-generator-java repository. Users should not @@ -15,7 +15,7 @@ com.google.api gapic-generator-java-pom-parent - 2.41.0 + 2.42.0 ../gapic-generator-java-pom-parent @@ -75,61 +75,61 @@ com.google.api api-common - 2.32.0 + 2.33.0 com.google.api gax-bom - 2.49.0 + 2.50.0 pom import com.google.api gapic-generator-java - 2.41.0 + 2.42.0 com.google.api.grpc grpc-google-common-protos - 2.40.0 + 2.41.0 com.google.api.grpc proto-google-common-protos - 2.40.0 + 2.41.0 com.google.api.grpc proto-google-iam-v1 - 1.35.0 + 1.36.0 com.google.api.grpc proto-google-iam-v2 - 1.35.0 + 1.36.0 com.google.api.grpc proto-google-iam-v2beta - 1.35.0 + 1.36.0 com.google.api.grpc grpc-google-iam-v1 - 1.35.0 + 1.36.0 com.google.api.grpc grpc-google-iam-v2 - 1.35.0 + 1.36.0 com.google.api.grpc grpc-google-iam-v2beta - 1.35.0 + 1.36.0 diff --git a/gapic-generator-java-pom-parent/pom.xml b/gapic-generator-java-pom-parent/pom.xml index f05fbe1fec..a290702950 100644 --- a/gapic-generator-java-pom-parent/pom.xml +++ b/gapic-generator-java-pom-parent/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.google.api gapic-generator-java-pom-parent - 2.41.0 + 2.42.0 pom GAPIC Generator Java POM Parent https://github.com/googleapis/sdk-platform-java @@ -15,7 +15,7 @@ com.google.cloud google-cloud-shared-config - 1.8.0 + 1.8.1 @@ -32,7 +32,7 @@ 2.11.0 33.1.0-jre 3.25.3 - 1.38.0 + 1.39.0 8 2.28.0 3.0.0 @@ -115,7 +115,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.5 + 3.3.0 @@ -131,7 +131,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 3.2.5 + 3.3.0 diff --git a/gapic-generator-java/pom.xml b/gapic-generator-java/pom.xml index bf49747176..a17a3a1ce6 100644 --- a/gapic-generator-java/pom.xml +++ b/gapic-generator-java/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.google.api gapic-generator-java - 2.41.0 + 2.42.0 GAPIC Generator Java GAPIC generator Java @@ -22,7 +22,7 @@ com.google.api gapic-generator-java-pom-parent - 2.41.0 + 2.42.0 ../gapic-generator-java-pom-parent @@ -31,7 +31,7 @@ com.google.api gapic-generator-java-bom - 2.41.0 + 2.42.0 pom import @@ -317,7 +317,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.5 + 3.3.0 diff --git a/gapic-generator-java/src/main/java/com/google/api/generator/Main.java b/gapic-generator-java/src/main/java/com/google/api/generator/Main.java index 2ad75c19ba..027eedaf81 100644 --- a/gapic-generator-java/src/main/java/com/google/api/generator/Main.java +++ b/gapic-generator-java/src/main/java/com/google/api/generator/Main.java @@ -14,6 +14,8 @@ package com.google.api.generator; +import static com.google.api.generator.gapic.protowriter.Writer.EMPTY_RESPONSE; + import com.google.api.generator.gapic.Generator; import com.google.protobuf.ExtensionRegistry; import com.google.protobuf.compiler.PluginProtos.CodeGeneratorRequest; @@ -26,6 +28,8 @@ public static void main(String[] args) throws IOException { ProtoRegistry.registerAllExtensions(registry); CodeGeneratorRequest request = CodeGeneratorRequest.parseFrom(System.in, registry); CodeGeneratorResponse response = Generator.generateGapic(request); - response.writeTo(System.out); + if (response != EMPTY_RESPONSE) { + response.writeTo(System.out); + } } } diff --git a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/ClientLibraryPackageInfoComposer.java b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/ClientLibraryPackageInfoComposer.java index cb794b4230..5bd24bdbd0 100644 --- a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/ClientLibraryPackageInfoComposer.java +++ b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/ClientLibraryPackageInfoComposer.java @@ -29,11 +29,15 @@ import com.google.api.generator.gapic.model.GapicPackageInfo; import com.google.api.generator.gapic.model.Sample; import com.google.api.generator.gapic.model.Service; -import com.google.common.base.Preconditions; import com.google.common.base.Strings; +import java.util.logging.Logger; import javax.annotation.Generated; public class ClientLibraryPackageInfoComposer { + + private static final Logger LOGGER = + Logger.getLogger(ClientLibraryPackageInfoComposer.class.getName()); + private static final String DIVIDER = "======================="; private static final String PACKAGE_INFO_DESCRIPTION = @@ -44,7 +48,10 @@ public class ClientLibraryPackageInfoComposer { private static final String SERVICE_DESCRIPTION_HEADER_PATTERN = "Service Description: %s"; public static GapicPackageInfo generatePackageInfo(GapicContext context) { - Preconditions.checkState(!context.services().isEmpty(), "No services found to generate"); + if (!context.containsServices()) { + LOGGER.warning("Generating empty package info since no services were found"); + return null; + } // Pick some service's package, as we assume they are all the same. String libraryPakkage = context.services().get(0).pakkage(); 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 f2ffa56016..51da8f919a 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 @@ -53,6 +53,9 @@ public static List composeServiceClasses(GapicContext context) { } public static GapicPackageInfo composePackageInfo(GapicContext context) { + if (!context.containsServices()) { + return null; + } return addApacheLicense(ClientLibraryPackageInfoComposer.generatePackageInfo(context)); } diff --git a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/GapicContext.java b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/GapicContext.java index 8fdba8d3ee..780890c664 100644 --- a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/GapicContext.java +++ b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/GapicContext.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.TreeMap; import java.util.stream.Collectors; @@ -32,6 +33,16 @@ public abstract class GapicContext { // it iteratively as we generate client methods. private GapicMetadata gapicMetadata = defaultGapicMetadata(); + public static final GapicContext EMPTY = + builder() + .setServices(Collections.emptyList()) + .setMessages(Collections.emptyMap()) + .setServiceConfig(GapicServiceConfig.create(Optional.empty())) + .setResourceNames(Collections.emptyMap()) + .setHelperResourceNames(Collections.emptySet()) + .setTransport(Transport.GRPC) + .build(); + // Maps the message name (as it appears in the protobuf) to Messages. public abstract ImmutableMap messages(); @@ -59,6 +70,10 @@ public GapicMetadata gapicMetadata() { @Nullable public abstract com.google.api.Service serviceYamlProto(); + public boolean containsServices() { + return !services().isEmpty(); + } + public boolean hasServiceYamlProto() { return serviceYamlProto() != null; } 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 747faa25c3..e7c6bd8967 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 @@ -79,14 +79,18 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Function; +import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.IntStream; public class Parser { + + private static final Logger LOGGER = Logger.getLogger(Parser.class.getName()); private static final String COMMA = ","; private static final String COLON = ":"; private static final String DEFAULT_PORT = "443"; @@ -175,7 +179,10 @@ public static GapicContext parse(CodeGeneratorRequest request) { mixinServices, transport); - Preconditions.checkState(!services.isEmpty(), "No services found to generate"); + if (services.isEmpty()) { + LOGGER.warning("No services found to generate. This will cause a no-op (no files generated)"); + return GapicContext.EMPTY; + } // TODO(vam-google): Figure out whether we should keep this allowlist or bring // back the unused resource names for all APIs. @@ -1102,7 +1109,8 @@ private static Map getFilesToGenerate(CodeGeneratorReque return fileDescriptors; } - private static String parseServiceJavaPackage(CodeGeneratorRequest request) { + @VisibleForTesting + static String parseServiceJavaPackage(CodeGeneratorRequest request) { Map javaPackageCount = new HashMap<>(); Map fileDescriptors = getFilesToGenerate(request); for (String fileToGenerate : request.getFileToGenerateList()) { @@ -1135,13 +1143,12 @@ private static String parseServiceJavaPackage(CodeGeneratorRequest request) { processedJavaPackageCount = javaPackageCount; } - String finalJavaPackage = - processedJavaPackageCount.entrySet().stream() - .max(Map.Entry.comparingByValue()) - .get() - .getKey(); - Preconditions.checkState( - !Strings.isNullOrEmpty(finalJavaPackage), "No service Java package found"); + String finalJavaPackage = ""; + Optional> finalPackageEntry = + processedJavaPackageCount.entrySet().stream().max(Map.Entry.comparingByValue()); + if (finalPackageEntry.isPresent()) { + finalJavaPackage = finalPackageEntry.get().getKey(); + } return finalJavaPackage; } diff --git a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protowriter/Writer.java b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protowriter/Writer.java index f0390ff6ea..79c9cbf349 100644 --- a/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protowriter/Writer.java +++ b/gapic-generator-java/src/main/java/com/google/api/generator/gapic/protowriter/Writer.java @@ -36,29 +36,29 @@ import java.util.jar.JarOutputStream; public class Writer { - static class GapicWriterException extends RuntimeException { - public GapicWriterException(String errorMessage) { - super(errorMessage); - } + static class GapicWriterException extends RuntimeException { public GapicWriterException(String errorMessage, Throwable cause) { super(errorMessage, cause); } } - public static CodeGeneratorResponse write( + public static final CodeGeneratorResponse EMPTY_RESPONSE = null; + + @VisibleForTesting + protected static CodeGeneratorResponse write( GapicContext context, List clazzes, GapicPackageInfo gapicPackageInfo, List reflectConfigInfo, - String outputFilePath) { - ByteString.Output output = ByteString.newOutput(); + String outputFilePath, + JarOutputStream jos, + ByteString.Output output) + throws IOException { JavaWriterVisitor codeWriter = new JavaWriterVisitor(); - JarOutputStream jos; - try { - jos = new JarOutputStream(output); - } catch (IOException e) { - throw new GapicWriterException(e.getMessage(), e); + + if (!context.containsServices()) { + return EMPTY_RESPONSE; } for (GapicClass gapicClazz : clazzes) { @@ -72,12 +72,8 @@ public static CodeGeneratorResponse write( writeMetadataFile(context, writePackageInfo(gapicPackageInfo, codeWriter, jos), jos); writeReflectConfigFile(gapicPackageInfo.packageInfo().pakkage(), reflectConfigInfo, jos); - try { - jos.finish(); - jos.flush(); - } catch (IOException e) { - throw new GapicWriterException(e.getMessage(), e); - } + jos.finish(); + jos.flush(); CodeGeneratorResponse.Builder response = CodeGeneratorResponse.newBuilder(); response @@ -88,6 +84,23 @@ public static CodeGeneratorResponse write( return response.build(); } + public static CodeGeneratorResponse write( + GapicContext context, + List clazzes, + GapicPackageInfo gapicPackageInfo, + List reflectConfigInfo, + String outputFilePath) { + ByteString.Output output = ByteString.newOutput(); + CodeGeneratorResponse response; + try (JarOutputStream jos = new JarOutputStream(output)) { + response = + write(context, clazzes, gapicPackageInfo, reflectConfigInfo, outputFilePath, jos, output); + } catch (IOException e) { + throw new GapicWriterException(e.getMessage(), e); + } + return response; + } + @VisibleForTesting static void writeReflectConfigFile( String pakkage, List reflectConfigInfo, JarOutputStream jos) { @@ -167,7 +180,8 @@ private static void writeSamples( } } - private static String writePackageInfo( + @VisibleForTesting + static String writePackageInfo( GapicPackageInfo gapicPackageInfo, JavaWriterVisitor codeWriter, JarOutputStream jos) { PackageInfoDefinition packageInfo = gapicPackageInfo.packageInfo(); packageInfo.accept(codeWriter); diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/ClientLibraryPackageInfoComposerTest.java b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/ClientLibraryPackageInfoComposerTest.java index df828d5119..5110e3efaf 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/ClientLibraryPackageInfoComposerTest.java +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/ClientLibraryPackageInfoComposerTest.java @@ -14,6 +14,8 @@ package com.google.api.generator.gapic.composer; +import static org.junit.jupiter.api.Assertions.assertNull; + import com.google.api.generator.engine.writer.JavaWriterVisitor; import com.google.api.generator.gapic.model.GapicContext; import com.google.api.generator.gapic.model.GapicPackageInfo; @@ -39,4 +41,9 @@ void composePackageInfo_showcase() { GoldenFileWriter.getGoldenDir(this.getClass()), "ShowcaseWithEchoPackageInfo.golden"); Assert.assertCodeEquals(goldenFilePath, visitor.write()); } + + @Test + void testGeneratePackageInfo_noServices_returnsNullPackageInfo() { + assertNull(ClientLibraryPackageInfoComposer.generatePackageInfo(GapicContext.EMPTY)); + } } 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 1d2053944f..ad370307c1 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 @@ -14,8 +14,10 @@ package com.google.api.generator.gapic.composer; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import com.google.api.generator.engine.ast.ClassDefinition; import com.google.api.generator.engine.ast.ScopeNode; @@ -35,6 +37,7 @@ import java.nio.file.Paths; import java.util.Arrays; import java.util.List; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class ComposerTest { @@ -53,8 +56,13 @@ class ComposerTest { .build(); private List ListofSamples = Arrays.asList(new Sample[] {sample}); + @BeforeEach + void initialSanityCheck() { + assertTrue(context.containsServices()); + } + @Test - void gapicClass_addApacheLicense() { + public void gapicClass_addApacheLicense_validInput_succeeds() { ClassDefinition classDef = ClassDefinition.builder() .setPackageString("com.google.showcase.v1beta1.stub") @@ -84,14 +92,14 @@ void composeSamples_showcase() { assertFalse(composedSamples.isEmpty()); for (Sample sample : composedSamples) { assertEquals( - "File header should be APACHE", Arrays.asList(CommentComposer.APACHE_LICENSE_COMMENT), - sample.fileHeader()); + sample.fileHeader(), + "File header should be APACHE"); assertEquals( - "ApiShortName should be Localhost7469", "Localhost7469", - sample.regionTag().apiShortName()); - assertEquals("ApiVersion should be V1Beta1", "V1Beta1", sample.regionTag().apiVersion()); + sample.regionTag().apiShortName(), + "ApiShortName should be Localhost7469"); + assertEquals("V1Beta1", sample.regionTag().apiVersion(), "ApiVersion should be V1Beta1"); } } @@ -120,10 +128,10 @@ void composeSamples_parseProtoPackage() { for (Sample sample : composedSamples) { assertEquals( - "ApiShortName should be Accessapproval", + "Accessapproval", sample.regionTag().apiShortName(), - "Accessapproval"); - assertEquals("ApiVersion should be V1", sample.regionTag().apiVersion(), "V1"); + "ApiShortName should be Accessapproval"); + assertEquals("V1", sample.regionTag().apiVersion(), "ApiVersion should be V1"); } protoPack = "google.cloud.vision.v1p1beta1"; @@ -136,8 +144,8 @@ void composeSamples_parseProtoPackage() { assertFalse(composedSamples.isEmpty()); for (Sample sample : composedSamples) { - assertEquals("ApiShortName should be Vision", sample.regionTag().apiShortName(), "Vision"); - assertEquals("ApiVersion should be V1P1Beta1", sample.regionTag().apiVersion(), "V1P1Beta1"); + assertEquals("Vision", sample.regionTag().apiShortName(), "ApiShortName should be Vision"); + assertEquals("V1P1Beta1", sample.regionTag().apiVersion(), "ApiVersion should be V1P1Beta1"); } protoPack = "google.cloud.vision"; @@ -149,11 +157,21 @@ void composeSamples_parseProtoPackage() { assertFalse(composedSamples.isEmpty()); for (Sample sample : composedSamples) { - assertEquals("ApiShortName should be Vision", sample.regionTag().apiShortName(), "Vision"); - assertEquals("ApiVersion should be empty", sample.regionTag().apiVersion(), ""); + assertEquals("Vision", sample.regionTag().apiShortName(), "ApiShortName should be Vision"); + assertTrue(sample.regionTag().apiVersion().isEmpty(), "ApiVersion should be empty"); } } + @Test + void testEmptyGapicContext_doesNotThrow() { + assertTrue(Composer.composeServiceClasses(GapicContext.EMPTY).isEmpty()); + } + + @Test + void testComposePackageInfo_emptyGapicContext_returnsNull() { + assertNull(Composer.composePackageInfo(GapicContext.EMPTY)); + } + private List getTestClassListFromService(Service testService) { GapicClass testClass = GrpcServiceCallableFactoryClassComposer.instance() 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 66f2bf49a9..93c4eb3599 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 @@ -15,11 +15,11 @@ package com.google.api.generator.gapic.protoparser; 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; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import com.google.api.FieldInfo.Format; import com.google.api.MethodSettings; @@ -30,6 +30,7 @@ import com.google.api.generator.engine.ast.TypeNode; import com.google.api.generator.engine.ast.VaporReference; import com.google.api.generator.gapic.model.Field; +import com.google.api.generator.gapic.model.GapicContext; import com.google.api.generator.gapic.model.Message; import com.google.api.generator.gapic.model.Method; import com.google.api.generator.gapic.model.MethodArgument; @@ -44,6 +45,7 @@ import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Descriptors.MethodDescriptor; import com.google.protobuf.Descriptors.ServiceDescriptor; +import com.google.protobuf.compiler.PluginProtos.CodeGeneratorRequest; import com.google.showcase.v1beta1.EchoOuterClass; import com.google.showcase.v1beta1.TestingOuterClass; import com.google.testgapic.v1beta1.LockerProto; @@ -609,6 +611,17 @@ void parseNestedProtoTypeName() { "google.ads.googleads.v3.resources.MutateJob.MutateJobMetadata")); } + @Test + void testParse_noServices_returnsEmptyGapicContext() { + GapicContext result = Parser.parse(CodeGeneratorRequest.newBuilder().build()); + assertEquals(GapicContext.EMPTY, result); + } + + @Test + void testParseServiceJavaPackage_emptyRequest_noop() { + assertThat(Parser.parseServiceJavaPackage(CodeGeneratorRequest.newBuilder().build())).isEmpty(); + } + @Test void parseServiceApiVersionTest() { FileDescriptor apiVersionFileDescriptor = ApiVersionTestingOuterClass.getDescriptor(); diff --git a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protowriter/WriterTest.java b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protowriter/WriterTest.java index 04d0dfa7de..c366d2085e 100644 --- a/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protowriter/WriterTest.java +++ b/gapic-generator-java/src/test/java/com/google/api/generator/gapic/protowriter/WriterTest.java @@ -1,12 +1,21 @@ package com.google.api.generator.gapic.protowriter; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import com.google.api.generator.engine.ast.PackageInfoDefinition; +import com.google.api.generator.gapic.model.GapicClass; +import com.google.api.generator.gapic.model.GapicContext; +import com.google.api.generator.gapic.model.GapicPackageInfo; import com.google.api.generator.gapic.model.ReflectConfig; +import com.google.common.collect.ImmutableList; import com.google.common.reflect.TypeToken; import com.google.gson.Gson; +import com.google.protobuf.ByteString; +import com.google.protobuf.compiler.PluginProtos.CodeGeneratorResponse; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; @@ -39,6 +48,12 @@ void createJarOutputStream() throws IOException { file = path.toFile(); } + private void closeJarOutputStream() throws IOException { + jarOutputStream.finish(); + jarOutputStream.flush(); + jarOutputStream.close(); + } + @AfterEach void assertJarOutputStream_isClosed() { assertThrows( @@ -49,9 +64,7 @@ void assertJarOutputStream_isClosed() { void reflectConfig_notWritten_ifEmptyInput() throws IOException { Writer.writeReflectConfigFile("com.google", Collections.emptyList(), jarOutputStream); - jarOutputStream.finish(); - jarOutputStream.flush(); - jarOutputStream.close(); + closeJarOutputStream(); try (JarFile jarFile = new JarFile(file)) { assertThat(jarFile.entries().hasMoreElements()).isFalse(); @@ -65,9 +78,7 @@ void reflectConfig_isWritten() throws IOException { Collections.singletonList(new ReflectConfig("com.google.Class")), jarOutputStream); - jarOutputStream.finish(); - jarOutputStream.flush(); - jarOutputStream.close(); + closeJarOutputStream(); try (JarFile jarFile = new JarFile(file)) { Enumeration entries = jarFile.entries(); @@ -85,4 +96,52 @@ void reflectConfig_isWritten() throws IOException { } } } + + @Test + void write_emptyGapicContext_writesNoBytes() throws IOException { + ByteString.Output output = ByteString.newOutput(); + CodeGeneratorResponse response = + Writer.write( + GapicContext.EMPTY, + Collections.emptyList(), + null, + Collections.emptyList(), + "temp-codegen.srcjar", + jarOutputStream, + output); + assertTrue(output.size() == 0); + closeJarOutputStream(); + } + + @Test + void write_emptyGapicContextAndFilledPackageInfo_succeeds() throws IOException { + ByteString.Output output = ByteString.newOutput(); + CodeGeneratorResponse response = + Writer.write( + GapicContext.EMPTY, + ImmutableList.of(GapicClass.createNonGeneratedGapicClass()), + GapicPackageInfo.with(PackageInfoDefinition.builder().setPakkage("com.test").build()), + Collections.emptyList(), + "temp-codegen.srcjar", + jarOutputStream, + output); + assertTrue(output.size() == 0); + closeJarOutputStream(); + } + + @Test + void productionWrite_emptyGapicContext_succeeds() throws IOException { + // This is a special case test to confirm the production function works as expected. + // We don't need the output stream + jarOutputStream.close(); + + CodeGeneratorResponse result = + Writer.write( + GapicContext.EMPTY, + ImmutableList.of(GapicClass.createNonGeneratedGapicClass()), + GapicPackageInfo.with(PackageInfoDefinition.builder().setPakkage("com.test").build()), + Collections.emptyList(), + "temp-codegen.srcjar"); + assertNull(result); + } } diff --git a/gax-java/README.md b/gax-java/README.md index dc7c5deb45..cd16848b2c 100644 --- a/gax-java/README.md +++ b/gax-java/README.md @@ -34,27 +34,27 @@ If you are using Maven, add this to your pom.xml file com.google.api gax - 2.49.0 + 2.50.0 com.google.api gax-grpc - 2.49.0 + 2.50.0 ``` If you are using Gradle, add this to your dependencies ```Groovy -compile 'com.google.api:gax:2.49.0', - 'com.google.api:gax-grpc:2.49.0' +compile 'com.google.api:gax:2.50.0', + 'com.google.api:gax-grpc:2.50.0' ``` If you are using SBT, add this to your dependencies ```Scala -libraryDependencies += "com.google.api" % "gax" % "2.49.0" -libraryDependencies += "com.google.api" % "gax-grpc" % "2.49.0" +libraryDependencies += "com.google.api" % "gax" % "2.50.0" +libraryDependencies += "com.google.api" % "gax-grpc" % "2.50.0" ``` [//]: # ({x-version-update-end}) diff --git a/gax-java/dependencies.properties b/gax-java/dependencies.properties index 5e00359177..10e96c602b 100644 --- a/gax-java/dependencies.properties +++ b/gax-java/dependencies.properties @@ -8,16 +8,16 @@ # Versions of oneself # {x-version-update-start:gax:current} -version.gax=2.49.0 +version.gax=2.50.0 # {x-version-update-end} # {x-version-update-start:gax:current} -version.gax_grpc=2.49.0 +version.gax_grpc=2.50.0 # {x-version-update-end} # {x-version-update-start:gax:current} -version.gax_bom=2.49.0 +version.gax_bom=2.50.0 # {x-version-update-end} # {x-version-update-start:gax:current} -version.gax_httpjson=2.49.0 +version.gax_httpjson=2.50.0 # {x-version-update-end} # Versions for dependencies which actual artifacts differ between Bazel and Gradle. @@ -35,26 +35,26 @@ version.io_grpc=1.62.2 # It should be constructed the following way: # 1) Take full artifact id (including the group and classifier (if any) portions) and remove version portion. # 2) Replace all characters which are neither alphabetic nor digits with the underscore ('_') character -maven.com_google_api_grpc_proto_google_common_protos=com.google.api.grpc:proto-google-common-protos:2.39.1 -maven.com_google_api_grpc_grpc_google_common_protos=com.google.api.grpc:grpc-google-common-protos:2.39.1 +maven.com_google_api_grpc_proto_google_common_protos=com.google.api.grpc:proto-google-common-protos:2.40.0 +maven.com_google_api_grpc_grpc_google_common_protos=com.google.api.grpc:grpc-google-common-protos:2.40.0 maven.com_google_auth_google_auth_library_oauth2_http=com.google.auth:google-auth-library-oauth2-http:1.23.0 maven.com_google_auth_google_auth_library_credentials=com.google.auth:google-auth-library-credentials:1.23.0 -maven.io_opentelemetry_opentelemetry_api=io.opentelemetry:opentelemetry-api:1.38.0 +maven.io_opentelemetry_opentelemetry_api=io.opentelemetry:opentelemetry-api:1.39.0 maven.io_opencensus_opencensus_api=io.opencensus:opencensus-api:0.31.1 maven.io_opencensus_opencensus_contrib_grpc_metrics=io.opencensus:opencensus-contrib-grpc-metrics:0.31.1 maven.io_opencensus_opencensus_contrib_http_util=io.opencensus:opencensus-contrib-http-util:0.31.1 maven.io_netty_netty_tcnative_boringssl_static=io.netty:netty-tcnative-boringssl-static:2.0.65.Final -maven.io_netty_netty_handler=io.netty:netty-handler:4.1.110.Final -maven.io_netty_netty_common=io.netty:netty-common:4.1.110.Final -maven.io_netty_netty_codec_socks=io.netty:netty-codec-socks:4.1.110.Final -maven.io_netty_netty_codec_http2=io.netty:netty-codec-http2:4.1.110.Final -maven.io_netty_netty_codec_http=io.netty:netty-codec-http:4.1.110.Final -maven.io_netty_netty_codec=io.netty:netty-codec:4.1.110.Final -maven.io_netty_netty_buffer=io.netty:netty-buffer:4.1.110.Final -maven.io_netty_netty_resolver=io.netty:netty-resolver:4.1.110.Final -maven.io_netty_netty_transport=io.netty:netty-transport:4.1.110.Final -maven.io_netty_netty_handler_proxy=io.netty:netty-handler-proxy:4.1.110.Final -maven.io_netty_netty_transport_native_unix_common=io.netty:netty-transport-native-unix-common:4.1.110.Final +maven.io_netty_netty_handler=io.netty:netty-handler:4.1.111.Final +maven.io_netty_netty_common=io.netty:netty-common:4.1.111.Final +maven.io_netty_netty_codec_socks=io.netty:netty-codec-socks:4.1.111.Final +maven.io_netty_netty_codec_http2=io.netty:netty-codec-http2:4.1.111.Final +maven.io_netty_netty_codec_http=io.netty:netty-codec-http:4.1.111.Final +maven.io_netty_netty_codec=io.netty:netty-codec:4.1.111.Final +maven.io_netty_netty_buffer=io.netty:netty-buffer:4.1.111.Final +maven.io_netty_netty_resolver=io.netty:netty-resolver:4.1.111.Final +maven.io_netty_netty_transport=io.netty:netty-transport:4.1.111.Final +maven.io_netty_netty_handler_proxy=io.netty:netty-handler-proxy:4.1.111.Final +maven.io_netty_netty_transport_native_unix_common=io.netty:netty-transport-native-unix-common:4.1.111.Final maven.io_perfmark_perfmark_api=io.perfmark:perfmark-api:0.27.0 maven.org_apache_tomcat_annotations_api=org.apache.tomcat:annotations-api:6.0.53 maven.com_google_code_gson_gson=com.google.code.gson:gson:2.11.0 @@ -65,12 +65,12 @@ maven.com_google_android_annotations=com.google.android:annotations:4.1.1.4 maven.com_google_code_findbugs_jsr305=com.google.code.findbugs:jsr305:3.0.2 maven.com_google_errorprone_error_prone_annotations=com.google.errorprone:error_prone_annotations:2.28.0 maven.com_google_j2objc_j2objc_annotations=com.google.j2objc:j2objc-annotations:2.8 -maven.com_google_auto_value_auto_value=com.google.auto.value:auto-value:1.10.4 -maven.com_google_auto_value_auto_value_annotations=com.google.auto.value:auto-value-annotations:1.10.4 -maven.com_google_api_api_common=com.google.api:api-common:2.31.1 +maven.com_google_auto_value_auto_value=com.google.auto.value:auto-value:1.11.0 +maven.com_google_auto_value_auto_value_annotations=com.google.auto.value:auto-value-annotations:1.11.0 +maven.com_google_api_api_common=com.google.api:api-common:2.32.0 maven.org_threeten_threetenbp=org.threeten:threetenbp:1.6.9 -maven.com_google_api_grpc_grpc_google_iam_v1=com.google.api.grpc:grpc-google-iam-v1:1.34.1 -maven.com_google_api_grpc_proto_google_iam_v1=com.google.api.grpc:proto-google-iam-v1:1.34.1 +maven.com_google_api_grpc_grpc_google_iam_v1=com.google.api.grpc:grpc-google-iam-v1:1.35.0 +maven.com_google_api_grpc_proto_google_iam_v1=com.google.api.grpc:proto-google-iam-v1:1.35.0 maven.com_google_http_client_google_http_client=com.google.http-client:google-http-client:1.44.2 maven.com_google_http_client_google_http_client_gson=com.google.http-client:google-http-client-gson:1.44.2 maven.org_codehaus_mojo_animal_sniffer_annotations=org.codehaus.mojo:animal-sniffer-annotations:1.23 diff --git a/gax-java/gax-bom/pom.xml b/gax-java/gax-bom/pom.xml index 31200857cb..f74691c2ce 100644 --- a/gax-java/gax-bom/pom.xml +++ b/gax-java/gax-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.api gax-bom - 2.49.0 + 2.50.0 pom GAX (Google Api eXtensions) for Java (BOM) Google Api eXtensions for Java (BOM) @@ -11,7 +11,7 @@ com.google.cloud google-cloud-shared-config - 1.8.0 + 1.8.1 @@ -43,55 +43,55 @@ com.google.api gax - 2.49.0 + 2.50.0 com.google.api gax - 2.49.0 + 2.50.0 test-jar testlib com.google.api gax - 2.49.0 + 2.50.0 testlib com.google.api gax-grpc - 2.49.0 + 2.50.0 com.google.api gax-grpc - 2.49.0 + 2.50.0 test-jar testlib com.google.api gax-grpc - 2.49.0 + 2.50.0 testlib com.google.api gax-httpjson - 2.49.0 + 2.50.0 com.google.api gax-httpjson - 2.49.0 + 2.50.0 test-jar testlib com.google.api gax-httpjson - 2.49.0 + 2.50.0 testlib diff --git a/gax-java/gax-grpc/pom.xml b/gax-java/gax-grpc/pom.xml index 772c91555a..b6c4d05bf0 100644 --- a/gax-java/gax-grpc/pom.xml +++ b/gax-java/gax-grpc/pom.xml @@ -3,7 +3,7 @@ 4.0.0 gax-grpc - 2.49.0 + 2.50.0 jar GAX (Google Api eXtensions) for Java (gRPC) Google Api eXtensions for Java (gRPC) @@ -11,7 +11,7 @@ com.google.api gax-parent - 2.49.0 + 2.50.0 diff --git a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java index 5969ed4693..539e06cd69 100644 --- a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java +++ b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java @@ -32,7 +32,6 @@ import com.google.api.core.ApiFunction; import com.google.api.core.BetaApi; import com.google.api.core.InternalApi; -import com.google.api.core.InternalExtensionOnly; import com.google.api.gax.core.ExecutorProvider; import com.google.api.gax.rpc.FixedHeaderProvider; import com.google.api.gax.rpc.HeaderProvider; @@ -82,13 +81,14 @@ *

The client lib header and generator header values are used to form a value that goes into the * http header of requests to the service. */ -@InternalExtensionOnly public final class InstantiatingGrpcChannelProvider implements TransportChannelProvider { + + private static String systemProductName; + @VisibleForTesting static final Logger LOG = Logger.getLogger(InstantiatingGrpcChannelProvider.class.getName()); - private static final String DIRECT_PATH_ENV_DISABLE_DIRECT_PATH = - "GOOGLE_CLOUD_DISABLE_DIRECT_PATH"; + static final String DIRECT_PATH_ENV_DISABLE_DIRECT_PATH = "GOOGLE_CLOUD_DISABLE_DIRECT_PATH"; private static final String DIRECT_PATH_ENV_ENABLE_XDS = "GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS"; static final long DIRECT_PATH_KEEP_ALIVE_TIME_SECONDS = 3600; static final long DIRECT_PATH_KEEP_ALIVE_TIMEOUT_SECONDS = 20; @@ -147,6 +147,19 @@ private InstantiatingGrpcChannelProvider(Builder builder) { : builder.directPathServiceConfig; } + /** + * Package-Private constructor that is only visible for testing DirectPath functionality inside + * tests. This overrides the computed systemProductName when the class is initialized to help + * configure the result of {@link #isOnComputeEngine()} check. + * + *

If productName is null, that represents the result of an IOException + */ + @VisibleForTesting + InstantiatingGrpcChannelProvider(Builder builder, String productName) { + this(builder); + systemProductName = productName; + } + /** * @deprecated If executor is not set, this channel provider will create channels with default * grpc executor. @@ -257,8 +270,8 @@ private boolean isDirectPathEnabled() { return false; } - @VisibleForTesting - boolean isDirectPathXdsEnabled() { + @InternalApi + public boolean isDirectPathXdsEnabled() { // Method 1: Enable DirectPath xDS by option. if (Boolean.TRUE.equals(attemptDirectPathXds)) { return true; @@ -320,19 +333,29 @@ boolean isCredentialDirectPathCompatible() { static boolean isOnComputeEngine() { String osName = System.getProperty("os.name"); if ("Linux".equals(osName)) { - try { - String result = - Files.asCharSource(new File("/sys/class/dmi/id/product_name"), StandardCharsets.UTF_8) - .readFirstLine(); - return result.contains(GCE_PRODUCTION_NAME_PRIOR_2016) - || result.contains(GCE_PRODUCTION_NAME_AFTER_2016); - } catch (IOException ignored) { - return false; - } + String systemProductName = getSystemProductName(); + // systemProductName will be empty string if not on Compute Engine + return systemProductName.contains(GCE_PRODUCTION_NAME_PRIOR_2016) + || systemProductName.contains(GCE_PRODUCTION_NAME_AFTER_2016); } return false; } + private static String getSystemProductName() { + // The static field systemProductName should only be set in tests + if (systemProductName != null) { + return systemProductName; + } + try { + return Files.asCharSource(new File("/sys/class/dmi/id/product_name"), StandardCharsets.UTF_8) + .readFirstLine(); + } catch (IOException e) { + // If not on Compute Engine, FileNotFoundException will be thrown. Use empty string + // as it won't match with the GCE_PRODUCTION_NAME constants + return ""; + } + } + // Universe Domain configuration is currently only supported in the GDU @VisibleForTesting boolean canUseDirectPathWithUniverseDomain() { @@ -370,10 +393,7 @@ private ManagedChannel createSingleChannel() throws IOException { // Check DirectPath traffic. boolean useDirectPathXds = false; - if (isDirectPathEnabled() - && isCredentialDirectPathCompatible() - && isOnComputeEngine() - && canUseDirectPathWithUniverseDomain()) { + if (canUseDirectPath()) { CallCredentials callCreds = MoreCallCredentials.from(credentials); ChannelCredentials channelCreds = GoogleDefaultChannelCredentials.newBuilder().callCredentials(callCreds).build(); @@ -446,6 +466,24 @@ && canUseDirectPathWithUniverseDomain()) { return managedChannel; } + /** + * Marked as Internal Api and intended for internal use. DirectPath must be enabled via the + * settings and a few other configurations/settings must also be valid for the request to go + * through DirectPath. + * + *

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