Skip to content

Commit

Permalink
ci: linakge checker test (#4494)
Browse files Browse the repository at this point in the history
* ci: linkage checker test

* ci: xmx12g

* ci: running linkage checker only for release PRs
  • Loading branch information
suztomo authored Jun 9, 2022
1 parent c1544a8 commit fd644a3
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 0 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/full-convergence-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@ jobs:
# BomContentTest should run part of the verify
mvn -B -V -ntp verify -Dtest="BomContentTest#testLibrariesBomReachable"
working-directory: tests

linkage-checker:
name: Linkage Checker to find new linkage errors
runs-on: ubuntu-latest
if: github.repository_owner == 'googleapis' && github.head_ref == 'release-please--branches--main'
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: zulu
java-version: 8
- name: Install BOMs
run: |
mvn -B -V -ntp install
- name: Ensure the Libraries BOM does not contain new linkage errors
run: |
mvn -B -V -ntp test -Dtest="MaximumLinkageErrorsTest"
working-directory: tests

full-dependencies-convergence:
runs-on: ubuntu-latest
if: github.repository_owner == 'googleapis' && github.head_ref == 'release-please--branches--main'
Expand Down
14 changes: 14 additions & 0 deletions tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,18 @@
<scope>test</scope>
</dependency>
</dependencies>

<build>
<!-- To use the plugin goals in your POM or parent POM -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M7</version>
<configuration>
<argLine>-Xmx8g</argLine>
</configuration>
</plugin>
</plugins>
</build>
</project>
119 changes: 119 additions & 0 deletions tests/src/test/java/com/google/cloud/MaximumLinkageErrorsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* Copyright 2019 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 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.classpath.LinkageChecker;
import com.google.cloud.tools.opensource.classpath.LinkageProblem;
import com.google.cloud.tools.opensource.dependencies.Bom;
import com.google.cloud.tools.opensource.dependencies.MavenRepositoryException;
import com.google.cloud.tools.opensource.dependencies.RepositoryUtility;
import com.google.cloud.tools.opensource.dependencies.UnresolvableArtifactProblem;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.aether.RepositoryException;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.version.InvalidVersionSpecificationException;
import org.junit.Assert;
import org.junit.Test;

public class MaximumLinkageErrorsTest {

@Test
public void testForNewLinkageErrors()
throws IOException, MavenRepositoryException, RepositoryException {
// Not using RepositoryUtility.findLatestCoordinates, which may return a snapshot version
String version = findLatestNonSnapshotVersion();
String baselineCoordinates = "com.google.cloud:libraries-bom:" + version;
Bom baseline = Bom.readBom(baselineCoordinates);

Path bomFile = Paths.get("../libraries-bom/pom.xml");
Bom bom = Bom.readBom(bomFile);

ImmutableSet<LinkageProblem> oldProblems = createLinkageChecker(baseline).findLinkageProblems();
LinkageChecker checker = createLinkageChecker(bom);
ImmutableSet<LinkageProblem> currentProblems = checker.findLinkageProblems();

// This only tests for newly missing methods, not new invocations of
// previously missing methods.
Set<LinkageProblem> newProblems = Sets.difference(currentProblems, oldProblems);

// Appengine-api-1.0-sdk is known to contain linkage errors because it shades dependencies
// https://github.com/GoogleCloudPlatform/cloud-opensource-java/issues/441
newProblems =
newProblems.stream()
.filter(problem -> !hasLinkageProblemFromArtifactId(problem, "appengine-api-1.0-sdk"))
.collect(Collectors.toSet());

// Check that no new linkage errors have been introduced since the baseline
StringBuilder message = new StringBuilder("Baseline BOM: " + baselineCoordinates + "\n");
if (!newProblems.isEmpty()) {
message.append("Newly introduced problems:\n");
message.append(LinkageProblem.formatLinkageProblems(newProblems, null));
Assert.fail(message.toString());
}
}

private LinkageChecker createLinkageChecker(Bom bom)
throws InvalidVersionSpecificationException, IOException {
ImmutableList<Artifact> managedDependencies = bom.getManagedDependencies();
ClassPathBuilder classPathBuilder = new ClassPathBuilder();

// full: false to avoid fetching optional dependencies.
ClassPathResult classPathResult =
classPathBuilder.resolve(managedDependencies, false, DependencyMediation.MAVEN);
ImmutableList<ClassPathEntry> classpath = classPathResult.getClassPath();
ImmutableList<UnresolvableArtifactProblem> artifactProblems =
classPathResult.getArtifactProblems();
if (!artifactProblems.isEmpty()) {
throw new IOException("Could not resolve artifacts: " + artifactProblems);
}
List<ClassPathEntry> artifactsInBom = classpath.subList(0, managedDependencies.size());
ImmutableSet<ClassPathEntry> entryPoints = ImmutableSet.copyOf(artifactsInBom);
return LinkageChecker.create(classpath, entryPoints, null);
}

private boolean hasLinkageProblemFromArtifactId(LinkageProblem problem, String artifactId) {
ClassPathEntry sourceClassPathEntry = problem.getSourceClass().getClassPathEntry();
Artifact sourceArtifact = sourceClassPathEntry.getArtifact();
return artifactId.equals(sourceArtifact.getArtifactId());
}

private String findLatestNonSnapshotVersion() throws MavenRepositoryException {
ImmutableList<String> versions =
RepositoryUtility.findVersions(
RepositoryUtility.newRepositorySystem(), "com.google.cloud", "libraries-bom");
ImmutableList<String> versionsLatestFirst = versions.reverse();
Optional<String> highestNonsnapshotVersion =
versionsLatestFirst.stream().filter(version -> !version.contains("SNAPSHOT")).findFirst();
if (!highestNonsnapshotVersion.isPresent()) {
Assert.fail("Could not find non-snapshot version of the BOM");
}
return highestNonsnapshotVersion.get();
}
}

0 comments on commit fd644a3

Please sign in to comment.