diff --git a/java-shared-dependencies/.github/workflows/upper-bound-check.yaml b/java-shared-dependencies/.github/workflows/upper-bound-check.yaml deleted file mode 100644 index 45cb8b9d95..0000000000 --- a/java-shared-dependencies/.github/workflows/upper-bound-check.yaml +++ /dev/null @@ -1,23 +0,0 @@ -on: - push: - branches: - - main - pull_request: -name: upper-bound-check -jobs: - upper-bound-check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: stCarolas/setup-maven@v4 - with: - maven-version: 3.8.1 - - uses: actions/setup-java@v1 - with: - java-version: 8 - - run: java -version - - name: Install the BOM to local Maven repository - run: .kokoro/build.sh - - name: Check the BOM content satisfies the upper-bound-check test case - run: mvn -B -V -ntp verify -Dcheckstyle.skip - working-directory: upper-bound-check diff --git a/java-shared-dependencies/.github/workflows/version-check.yaml b/java-shared-dependencies/.github/workflows/version-check.yaml new file mode 100644 index 0000000000..b78a560fbc --- /dev/null +++ b/java-shared-dependencies/.github/workflows/version-check.yaml @@ -0,0 +1,41 @@ +on: + push: + branches: + - main + pull_request: +name: version-check +jobs: + upper-bound-check: + name: Upper-bound check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: stCarolas/setup-maven@v4 + with: + maven-version: 3.8.1 + - uses: actions/setup-java@v1 + with: + java-version: 8 + - run: java -version + - name: Install the BOM to local Maven repository + run: .kokoro/build.sh + - name: Check the BOM content satisfies the upper-bound-check test case + run: mvn -B -V -ntp verify -Dcheckstyle.skip + working-directory: upper-bound-check + grpc-convergence-check: + name: gRPC dependency convergence check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: stCarolas/setup-maven@v4 + with: + maven-version: 3.8.1 + - uses: actions/setup-java@v1 + with: + java-version: 8 + - run: java -version + - name: Install the BOM to local Maven repository + run: .kokoro/build.sh + - name: Check the BOM content satisfies the dependency-convergence-check test + run: mvn -B -V -ntp verify -Dcheckstyle.skip + working-directory: dependency-convergence-check diff --git a/java-shared-dependencies/dependency-convergence-check/README.md b/java-shared-dependencies/dependency-convergence-check/README.md new file mode 100644 index 0000000000..d593196ece --- /dev/null +++ b/java-shared-dependencies/dependency-convergence-check/README.md @@ -0,0 +1,6 @@ +# Dependency Convergence Check + +This project includes a test case for dependency convergence for some (not all) +artifacts in the Google Cloud Shared Dependencies BOM. + +This project is not meant to be used by end-users or published to Maven Central. diff --git a/java-shared-dependencies/dependency-convergence-check/pom.xml b/java-shared-dependencies/dependency-convergence-check/pom.xml new file mode 100644 index 0000000000..3e0edf56c6 --- /dev/null +++ b/java-shared-dependencies/dependency-convergence-check/pom.xml @@ -0,0 +1,76 @@ + + + 4.0.0 + com.google.cloud + shared-dependencies-dependency-convergence-test + 2.7.0 + Dependency convergence test for certain artifacts in Google Cloud Shared Dependencies + https://github.com/googleapis/java-shared-dependencies + + An dependency convergence test case for the shared dependencies BOM. A failure of this test case means + the shared dependencies BOM has outdated dependencies; there are newer version of artifacts + appearing in the dependency tree. + + + + Google LLC + + + + scm:git:git@github.com:googleapis/java-shared-dependencies.git + scm:git:git@github.com:googleapis/java-shared-dependencies.git + https://github.com/googleapis/java-shared-dependencies + HEAD + + + + https://github.com/googleapis/java-shared-dependencies/issues + GitHub Issues + + + + + Apache-2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + + + + + UTF-8 + 1.8 + 1.8 + + + + + + com.google.cloud + google-cloud-shared-dependencies + 2.7.0 + pom + import + + + + + + + com.google.guava + guava + 31.0.1-jre + test + + + com.google.cloud.tools + dependencies + 1.5.12 + test + + + junit + junit + 4.13.1 + test + + + diff --git a/java-shared-dependencies/dependency-convergence-check/src/test/java/com/google/cloud/DependencyConvergenceTest.java b/java-shared-dependencies/dependency-convergence-check/src/test/java/com/google/cloud/DependencyConvergenceTest.java new file mode 100644 index 0000000000..6552438363 --- /dev/null +++ b/java-shared-dependencies/dependency-convergence-check/src/test/java/com/google/cloud/DependencyConvergenceTest.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +package com.google.cloud; + +import static org.junit.Assert.assertTrue; + +import com.google.cloud.tools.opensource.classpath.ClassPathBuilder; +import com.google.cloud.tools.opensource.classpath.ClassPathEntry; +import com.google.cloud.tools.opensource.classpath.ClassPathResult; +import com.google.cloud.tools.opensource.classpath.DependencyMediation; +import com.google.cloud.tools.opensource.dependencies.Bom; +import com.google.cloud.tools.opensource.dependencies.DependencyPath; +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import java.nio.file.Paths; +import java.util.HashSet; +import java.util.Set; +import org.eclipse.aether.artifact.Artifact; +import org.junit.Test; + +/** + * Test to ensure that certain artifacts in the dependency tree of each entry of the shared + * dependencies BOM have the same version. + */ +public class DependencyConvergenceTest { + + @Test + public void testGrpcConvergence() throws Exception { + // There were cases where the gRPC version set in the shared dependencies BOM and the gRPC + // version declared in gax-grpc's dependency broke the build of downstream projects. Two + // artifacts were using version range to specify exact gRPC versions. + // https://github.com/googleapis/java-shared-dependencies/pull/595 + Bom bom = Bom.readBom(Paths.get("../pom.xml")); + assertConvergence( + bom, + "io.grpc", + "grpc-netty-shaded", + ImmutableSet.of( + // Because OpenCensus's gRPC version does not use version range notation, it does not + // break downstream build + "opencensus-exporter-trace-stackdriver", + "opencensus-exporter-stats-stackdriver", + // Because grpc-gcp's gRPC version does not use version range notation, it does not + // break downstream build + "grpc-gcp")); + } + + /** + * Asserts the artifact specified at {@code groupId} and {@code artifactId} have the same version + * across the dependency trees of the managed dependencies of {@code bom}. + * + *

Use {@code excludingArtifactIds} to ignore certain artifacts. + */ + private void assertConvergence( + Bom bom, String groupId, String artifactId, Set excludingArtifactIds) + throws Exception { + ImmutableList managedDependencies = bom.getManagedDependencies(); + + Set foundPaths = new HashSet<>(); + Set foundVersions = new HashSet<>(); + for (Artifact managedDependency : managedDependencies) { + if (excludingArtifactIds.contains(managedDependency.getArtifactId())) { + continue; + } + + ClassPathBuilder classPathBuilder = new ClassPathBuilder(); + ClassPathResult result = + classPathBuilder.resolve( + ImmutableList.of(managedDependency), false, DependencyMediation.MAVEN); + ImmutableList classPath = result.getClassPath(); + for (ClassPathEntry entry : classPath) { + Artifact artifact = entry.getArtifact(); + if (artifactId.equals(artifact.getArtifactId()) && groupId.equals(artifact.getGroupId())) { + ImmutableList dependencyPaths = result.getDependencyPaths(entry); + foundPaths.add(dependencyPaths.get(0)); + foundVersions.add(artifact.getVersion()); + } + } + } + + assertTrue( + "There should be at least one version in the graph but empty; " + + "please check the assertion is using correct groupID and artifactID.", + foundVersions.size() >= 1); + + // Duplicate versions found in the dependency trees + assertTrue( + "The version for " + + groupId + + ":" + + artifactId + + " should be one but there are multiple of them: " + + Joiner.on(", ").join(foundPaths), + foundVersions.size() <= 1); + } +}