From 0117dbf6e950a1c402198a991c3f34f96c206f8a Mon Sep 17 00:00:00 2001 From: Tomo Suzuki Date: Wed, 29 Oct 2025 19:11:22 +0000 Subject: [PATCH] chore: remove unused modules The Libraries BOM has moved to the java-cloud-bom repository. We have cloud-lts-bom still in this repository but it's not released as part of the root project. Removing it from the root pom.xml. The dashboard from the dashboard module is no longer used. Let's stop the periodic build job. The linkage-monitor directory is not released as part of the root module. This change also fixes the CI of the Gradle plugin. The Gradle plugin is published to Gradle plugin portal, not Maven Central. https://plugins.gradle.org/plugin/com.google.cloud.tools.linkagechecker --- README.md | 12 +- boms/cloud-oss-bom/pom.xml | 288 -------- boms/pom.xml | 1 - dashboard/README.md | 7 - dashboard/pom.xml | 80 --- .../opensource/dashboard/ArtifactCache.java | 50 -- .../opensource/dashboard/ArtifactInfo.java | 54 -- .../opensource/dashboard/ArtifactResults.java | 85 --- .../dashboard/DashboardArguments.java | 179 ----- .../opensource/dashboard/DashboardMain.java | 623 ------------------ .../tools/opensource/dashboard/PieChart.java | 55 -- .../src/main/resources/css/dashboard.css | 147 ----- dashboard/src/main/resources/js/dashboard.js | 27 - dashboard/src/main/resources/poms/demo.xml | 49 -- .../resources/templates/artifact_details.ftl | 55 -- .../main/resources/templates/component.ftl | 156 ----- .../resources/templates/dependency_trees.ftl | 22 - .../src/main/resources/templates/index.ftl | 142 ---- .../src/main/resources/templates/macros.ftl | 142 ---- .../templates/unstable_artifacts.ftl | 40 -- .../resources/templates/version_index.ftl | 20 - .../dashboard/ArtifactResultsTest.java | 51 -- .../dashboard/DashboardArgumentsTest.java | 116 ---- .../opensource/dashboard/DashboardTest.java | 491 -------------- .../DashboardUnavailableArtifactTest.java | 169 ----- .../opensource/dashboard/FreemarkerTest.java | 146 ---- .../opensource/dashboard/PieChartTest.java | 88 --- dependencies/pom.xml | 18 - enforcer-rules/pom.xml | 50 +- gradle-plugin/build.gradle | 2 +- .../java8-incompatible-reference-check.sh | 11 - kokoro/ubuntu/periodic.cfg | 13 - kokoro/ubuntu/periodic.sh | 22 - pom.xml | 3 - 34 files changed, 35 insertions(+), 3379 deletions(-) delete mode 100644 boms/cloud-oss-bom/pom.xml delete mode 100644 dashboard/README.md delete mode 100644 dashboard/pom.xml delete mode 100644 dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/ArtifactCache.java delete mode 100644 dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/ArtifactInfo.java delete mode 100644 dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/ArtifactResults.java delete mode 100644 dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/DashboardArguments.java delete mode 100644 dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/DashboardMain.java delete mode 100644 dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/PieChart.java delete mode 100644 dashboard/src/main/resources/css/dashboard.css delete mode 100644 dashboard/src/main/resources/js/dashboard.js delete mode 100644 dashboard/src/main/resources/poms/demo.xml delete mode 100644 dashboard/src/main/resources/templates/artifact_details.ftl delete mode 100644 dashboard/src/main/resources/templates/component.ftl delete mode 100644 dashboard/src/main/resources/templates/dependency_trees.ftl delete mode 100644 dashboard/src/main/resources/templates/index.ftl delete mode 100644 dashboard/src/main/resources/templates/macros.ftl delete mode 100644 dashboard/src/main/resources/templates/unstable_artifacts.ftl delete mode 100644 dashboard/src/main/resources/templates/version_index.ftl delete mode 100644 dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/ArtifactResultsTest.java delete mode 100644 dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/DashboardArgumentsTest.java delete mode 100644 dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/DashboardTest.java delete mode 100644 dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/DashboardUnavailableArtifactTest.java delete mode 100644 dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/FreemarkerTest.java delete mode 100644 dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/PieChartTest.java delete mode 100644 kokoro/ubuntu/java8-incompatible-reference-check.sh delete mode 100644 kokoro/ubuntu/periodic.cfg delete mode 100755 kokoro/ubuntu/periodic.sh diff --git a/README.md b/README.md index 4e18b55387..a4c78f000d 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,6 @@ This project explores common infrastructure and best practices for open source Java projects for the Google Cloud Platform (GCP). -# Google Cloud Platform Java Dependency Dashboard - -[Google Cloud Platform Java Dependency Dashboard]( -https://storage.googleapis.com/cloud-opensource-java-dashboard/com.google.cloud/libraries-bom/snapshot/index.html) -(runs daily; work in progress) shows multiple checks on the consistency among -Google Cloud Java libraries. For manually generating the dashboard, see -[its README](./dashboard/README.md). - # Google Best Practices for Java Libraries [Google Best Practices for Java Libraries](https://googlecloudplatform.github.io/cloud-opensource-java/) @@ -43,6 +35,8 @@ The [GCP Libraries BOM](https://cloud.google.com/java/docs/bom) is a Bill-of-Mat provides consistent versions of Google Cloud Java libraries that work together without linkage errors. +This has moved to https://github.com/googleapis/java-cloud-bom/tree/main/libraries-bom. + # Development This project is built using _Maven_. @@ -62,5 +56,3 @@ This project is built using _Maven_. This is not an officially supported Google product. - - diff --git a/boms/cloud-oss-bom/pom.xml b/boms/cloud-oss-bom/pom.xml deleted file mode 100644 index 0fbd96533f..0000000000 --- a/boms/cloud-oss-bom/pom.xml +++ /dev/null @@ -1,288 +0,0 @@ - - - 4.0.0 - - com.google.cloud - libraries-bom - 25.3.1-SNAPSHOT - pom - - Google Cloud Platform Supported Libraries - - A compatible set of Google Cloud open source libraries. - Document: https://cloud.google.com/java/docs/bom - - https://cloud.google.com/java/docs/bom - - Google LLC - https://cloud.google.com - - 2019 - - - Elliotte Rusty Harold - - - - - https://github.com/GoogleCloudPlatform/cloud-opensource-java/issues - - - scm:git:git@github.com:GoogleCloudPlatform/cloud-opensource-java.git - scm:git:git@github.com:GoogleCloudPlatform/cloud-opensource-java.git - - https://github.com/GoogleCloudPlatform/cloud-opensource-java/boms/cloud-oss-bom - HEAD - - - - - The Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - - - - - UTF-8 - 31.1-jre - 2.9.0 - 0.174.0 - 2.6.0 - 1.45.1 - 1.41.7 - 3.19.4 - - 2.16.0 - 0.101.0 - 1.6.0 - 2.1.5 - 2.8.3 - 1.3.1 - - - - - sonatype-nexus-snapshots - Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots/ - - - - - - - - com.google.guava - guava - ${guava.version} - - - com.google.guava - guava-testlib - ${guava.version} - - - com.google.code.gson - gson - ${gson.version} - - - - com.google.protobuf - protobuf-bom - ${protobuf.version} - pom - import - - - - - com.google.http-client - google-http-client - ${http.version} - - - com.google.http-client - google-http-client-android - ${http.version} - - - com.google.http-client - google-http-client-apache-v2 - ${http.version} - - - com.google.http-client - google-http-client-appengine - ${http.version} - - - com.google.http-client - google-http-client-gson - ${http.version} - - - com.google.http-client - google-http-client-jackson2 - ${http.version} - - - com.google.http-client - google-http-client-protobuf - ${http.version} - - - com.google.http-client - google-http-client-test - ${http.version} - - - com.google.http-client - google-http-client-xml - ${http.version} - - - - - io.grpc - grpc-alts - ${io.grpc.version} - - - io.grpc - grpc-api - ${io.grpc.version} - - - io.grpc - grpc-auth - ${io.grpc.version} - - - io.grpc - grpc-context - ${io.grpc.version} - - - io.grpc - grpc-core - ${io.grpc.version} - - - io.grpc - grpc-grpclb - ${io.grpc.version} - - - io.grpc - grpc-netty - ${io.grpc.version} - - - io.grpc - grpc-netty-shaded - ${io.grpc.version} - - - io.grpc - grpc-okhttp - ${io.grpc.version} - - - io.grpc - grpc-protobuf - ${io.grpc.version} - - - io.grpc - grpc-protobuf-lite - ${io.grpc.version} - - - io.grpc - grpc-services - ${io.grpc.version} - - - io.grpc - grpc-stub - ${io.grpc.version} - - - io.grpc - grpc-testing - ${io.grpc.version} - - - - - com.google.cloud - google-cloud-bom - ${google.cloud.bom.version} - pom - import - - - - com.google.api - api-common - ${api-common.version} - - - com.google.api - gax - ${gax.version} - - - com.google.api - gax-grpc - ${gax.version} - - - com.google.api - gax-httpjson - ${gax.httpjson.version} - - - com.google.auth - google-auth-library-bom - ${auth.version} - pom - import - - - com.google.cloud - google-cloud-core-bom - ${google.cloud.core.version} - pom - import - - - com.google.api.grpc - proto-google-common-protos - ${common.protos.version} - - - com.google.api.grpc - grpc-google-common-protos - ${common.protos.version} - - - com.google.api.grpc - proto-google-iam-v1 - ${iam.protos.version} - - - com.google.api.grpc - grpc-google-iam-v1 - ${iam.protos.version} - - - - - - diff --git a/boms/pom.xml b/boms/pom.xml index 507915a380..5aa20037ba 100644 --- a/boms/pom.xml +++ b/boms/pom.xml @@ -29,7 +29,6 @@ - cloud-oss-bom cloud-lts-bom upper-bounds-check integration-tests diff --git a/dashboard/README.md b/dashboard/README.md deleted file mode 100644 index 9e83166283..0000000000 --- a/dashboard/README.md +++ /dev/null @@ -1,7 +0,0 @@ -To generate the dashboard from the root directory run: - -``` -$ mvn clean install -$ cd dashboard -$ mvn exec:java -Dexec.arguments="-f ../boms/cloud-oss-bom/pom.xml" -``` diff --git a/dashboard/pom.xml b/dashboard/pom.xml deleted file mode 100644 index 932ec0e4f3..0000000000 --- a/dashboard/pom.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - 4.0.0 - - com.google.cloud.tools - dependencies-parent - 1.5.16-SNAPSHOT - - dashboard - - Cloud Tools Open Source Code Hygiene Dashboard - https://github.com/GoogleCloudPlatform/cloud-opensource-java/dashboard - - Google LLC. - https://www.google.com - - - - - The Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - - - - - UTF-8 - 1.8 - 1.8 - - - - - org.freemarker - freemarker - 2.3.31 - - - com.google.guava - guava - - - ${project.groupId} - dependencies - ${project.version} - - - - xom - xom - 1.3.7 - test - - - junit - junit - test - - - com.google.truth - truth - test - - - - - - - org.codehaus.mojo - exec-maven-plugin - - false - com.google.cloud.tools.opensource.dashboard.DashboardMain - - - - - - diff --git a/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/ArtifactCache.java b/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/ArtifactCache.java deleted file mode 100644 index ec12246c52..0000000000 --- a/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/ArtifactCache.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 - * - * 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.tools.opensource.dashboard; - -import java.util.List; -import java.util.Map; - -import org.eclipse.aether.artifact.Artifact; - -import com.google.cloud.tools.opensource.dependencies.DependencyGraph; - -/** - * Unified return type to bundle a lot of information about multiple artifacts together. - */ -class ArtifactCache { - - private Map infoMap; - private List globalDependencies; - - void setInfoMap(Map infoMap) { - this.infoMap = infoMap; - } - - void setGlobalDependencies(List globalDependencies) { - this.globalDependencies = globalDependencies; - } - - Map getInfoMap() { - return infoMap; - } - - List getGlobalDependencies() { - return globalDependencies; - } - -} diff --git a/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/ArtifactInfo.java b/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/ArtifactInfo.java deleted file mode 100644 index 1bf711c88e..0000000000 --- a/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/ArtifactInfo.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 - * - * 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.tools.opensource.dashboard; - -import org.eclipse.aether.RepositoryException; - -import com.google.cloud.tools.opensource.dependencies.DependencyGraph; - -/** - * Cache of info looked up for an artifact. - */ -class ArtifactInfo { - - private DependencyGraph completeDependencies; - private DependencyGraph transitiveDependencies; - private RepositoryException exception; - - ArtifactInfo(DependencyGraph completeDependencies, - DependencyGraph transitiveDependencies) { - this.completeDependencies = completeDependencies; - this.transitiveDependencies = transitiveDependencies; - } - - ArtifactInfo(RepositoryException ex) { - this.exception = ex; - } - - DependencyGraph getCompleteDependencies() { - return completeDependencies; - } - - DependencyGraph getTransitiveDependencies() { - return transitiveDependencies; - } - - RepositoryException getException() { - return exception; - } - -} diff --git a/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/ArtifactResults.java b/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/ArtifactResults.java deleted file mode 100644 index da528a2f84..0000000000 --- a/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/ArtifactResults.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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 - * - * 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.tools.opensource.dashboard; - -import java.util.HashMap; -import java.util.Map; - -import javax.annotation.Nullable; - -import org.eclipse.aether.artifact.Artifact; - -import com.google.cloud.tools.opensource.dependencies.Artifacts; - -/** - * Collection of test results for a single artifact. - */ -public final class ArtifactResults { - - private final Map results = new HashMap<>(); - private final Artifact artifact; - private String exceptionMessage; - - public ArtifactResults(Artifact artifact) { - this.artifact = artifact; - } - - public void setExceptionMessage(String exceptionMessage) { - this.exceptionMessage = exceptionMessage; - } - - void addResult(String testName, int failures) { - results.put(testName, failures); - } - - /** - * @return true for pass, false for fail, null for unknown test - */ - @Nullable - public Boolean getResult(String testName) { - Integer failures = results.get(testName); - if (failures != null) { - return failures == 0; - } - return null; - } - - public String getCoordinates() { - return Artifacts.toCoordinates(artifact); - } - - /** - * @return message of exception occurred when running test, null for no exception - */ - @Nullable - public String getExceptionMessage() { - return exceptionMessage; - } - - /** - * - * @return number of times the specified test failed. Returns 0 - * if the test was not run. - */ - public int getFailureCount(String testName) { - Integer failures = results.get(testName); - if (failures == null) { - return 0; - } - return failures; - } -} diff --git a/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/DashboardArguments.java b/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/DashboardArguments.java deleted file mode 100644 index 6dda1bb91a..0000000000 --- a/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/DashboardArguments.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * 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.tools.opensource.dashboard; - -import com.google.common.collect.ImmutableList; -import java.nio.file.Path; -import java.nio.file.Paths; -import javax.annotation.Nullable; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.OptionGroup; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; - -/** - * Command-line option for {@link DashboardMain}. The tool takes either a pom.xml file path or Maven - * coordinates for a BOM. - */ -final class DashboardArguments { - private static final Options options = configureOptions(); - private static final HelpFormatter helpFormatter = new HelpFormatter(); - - private static final ImmutableList validDependencyMediationValues = - ImmutableList.of("maven", "gradle"); - - private final CommandLine commandLine; - - private DashboardArguments(CommandLine commandLine) { - this.commandLine = commandLine; - } - - /** - * Returns true if the argument for a file is specified. False if the argument for coordinates is - * specified. - * - *

It is guaranteed that either a file path or Maven coordinates for a BOM are available. - */ - boolean hasFile() { - return commandLine.hasOption('f'); - } - - /** - * Returns true if the argument for a versionless coordinates is specified; otherwise false. - * - *

It is guaranteed that either a file path or Maven coordinates for a BOM are available. - */ - boolean hasVersionlessCoordinates() { - return commandLine.hasOption('a'); - } - - /** Returns an absolute path to pom.xml file of a BOM. Null if file is not specified. */ - @Nullable - Path getBomFile() { - if (!commandLine.hasOption('f')) { - return null; - } - // Trim the value so that maven exec plugin can pass arguments with exec.arguments="-f pom.xml" - return Paths.get(commandLine.getOptionValue('f').trim()).toAbsolutePath(); - } - - /** Returns the Maven coordinates of a BOM. Null if coordinates are not specified. */ - @Nullable - String getBomCoordinates() { - if (!commandLine.hasOption('c')) { - return null; - } - return commandLine.getOptionValue('c').trim(); - } - - /** - * Returns the versionless Maven coordinates of a BOM. Null if versionless coordinates are not - * specified. - */ - @Nullable - String getVersionlessCoordinates() { - if (!commandLine.hasOption('a')) { - return null; - } - return commandLine.getOptionValue('a').trim(); - } - - static DashboardArguments readCommandLine(String... arguments) throws ParseException { - CommandLineParser parser = new DefaultParser(); - - try { - // Throws ParseException if required option group ('-f' or '-c') is not specified - CommandLine commandLine = parser.parse(options, arguments); - String dependencyMediationValue = commandLine.getOptionValue('m'); - if (dependencyMediationValue != null - && !validDependencyMediationValues.contains(dependencyMediationValue)) { - throw new ParseException("Valid values for '-m' are " + validDependencyMediationValues); - } - - return new DashboardArguments(commandLine); - } catch (ParseException ex) { - helpFormatter.printHelp("DashboardMain", options); - throw ex; - } - } - - enum DependencyMediationAlgorithm { - MAVEN, - GRADLE, - } - - /** - * Returns dependency mediation algorithm. By default it's {@link - * DependencyMediationAlgorithm#MAVEN}. - */ - DependencyMediationAlgorithm getDependencyMediation() { - if (!commandLine.hasOption('m')) { - return DependencyMediationAlgorithm.MAVEN; - } - String optionValue = commandLine.getOptionValue('m').trim(); - return "maven".equals(optionValue) - ? DependencyMediationAlgorithm.MAVEN - : DependencyMediationAlgorithm.GRADLE; - } - - private static Options configureOptions() { - Options options = new Options(); - OptionGroup inputGroup = new OptionGroup(); - inputGroup.setRequired(true); - - Option inputFileOption = - Option.builder("f").longOpt("bom-file").hasArg().desc("File to a BOM (pom.xml)").build(); - inputGroup.addOption(inputFileOption); - - Option inputCoordinatesOption = - Option.builder("c") - .longOpt("bom-coordinates") - .hasArg() - .desc( - "Maven coordinates of a BOM. For example, com.google.cloud:libraries-bom:1.0.0") - .build(); - inputGroup.addOption(inputCoordinatesOption); - - Option versionlessCoordinatesOption = - Option.builder("a") - .longOpt("all-versions") - .hasArg() - .desc( - "Maven coordinates of a BOM without version. " - + "For example, com.google.cloud:libraries-bom") - .build(); - inputGroup.addOption(versionlessCoordinatesOption); - - Option dependencyMediationOption = - Option.builder("m") - .longOpt("dependency-mediation") - .hasArg() - .desc( - "The dependency mediation algorithm to choose versions. The valid values are:\n" - + "- 'maven' for nearest-win strategy (default)\n" - + "- 'gradle' for highest-win strategy.") - .build(); - options.addOption(dependencyMediationOption); - - options.addOptionGroup(inputGroup); - return options; - } -} diff --git a/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/DashboardMain.java b/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/DashboardMain.java deleted file mode 100644 index 94427516e2..0000000000 --- a/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/DashboardMain.java +++ /dev/null @@ -1,623 +0,0 @@ -/* - * 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 - * - * 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.tools.opensource.dashboard; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.cloud.tools.opensource.classpath.ClassFile; -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.GradleDependencyMediation; -import com.google.cloud.tools.opensource.classpath.LinkageChecker; -import com.google.cloud.tools.opensource.classpath.LinkageProblem; -import com.google.cloud.tools.opensource.dashboard.DashboardArguments.DependencyMediationAlgorithm; -import com.google.cloud.tools.opensource.dependencies.Artifacts; -import com.google.cloud.tools.opensource.dependencies.Bom; -import com.google.cloud.tools.opensource.dependencies.DependencyGraph; -import com.google.cloud.tools.opensource.dependencies.DependencyGraphBuilder; -import com.google.cloud.tools.opensource.dependencies.DependencyPath; -import com.google.cloud.tools.opensource.dependencies.MavenRepositoryException; -import com.google.cloud.tools.opensource.dependencies.RepositoryUtility; -import com.google.cloud.tools.opensource.dependencies.Update; -import com.google.cloud.tools.opensource.dependencies.VersionComparator; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Joiner; -import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimaps; -import com.google.common.collect.Sets; -import freemarker.template.Configuration; -import freemarker.template.DefaultObjectWrapper; -import freemarker.template.DefaultObjectWrapperBuilder; -import freemarker.template.Template; -import freemarker.template.TemplateException; -import freemarker.template.TemplateHashModel; -import freemarker.template.Version; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.TreeMap; -import org.apache.commons.cli.ParseException; -import org.eclipse.aether.RepositoryException; -import org.eclipse.aether.RepositorySystem; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.graph.Dependency; -import org.eclipse.aether.version.InvalidVersionSpecificationException; - -public class DashboardMain { - - public static final String TEST_NAME_LINKAGE_CHECK = "Linkage Errors"; - public static final String TEST_NAME_UPPER_BOUND = "Upper Bounds"; - public static final String TEST_NAME_GLOBAL_UPPER_BOUND = "Global Upper Bounds"; - public static final String TEST_NAME_DEPENDENCY_CONVERGENCE = "Dependency Convergence"; - public static final int LATEST_VERSIONS_COUNT = 10; - - private static final Configuration freemarkerConfiguration = configureFreemarker(); - - private static final DependencyGraphBuilder dependencyGraphBuilder = new DependencyGraphBuilder(); - private static final ClassPathBuilder classPathBuilder = - new ClassPathBuilder(dependencyGraphBuilder); - - /** - * Generates a code hygiene dashboard for a BOM. This tool takes a path to pom.xml of the BOM as - * an argument or Maven coordinates to a BOM. - * - *

Generated dashboard is at {@code target/$groupId/$artifactId/$version/index.html}, where - * each value is from BOM coordinates except {@code $version} is "snapshot" if the BOM has - * snapshot version. - */ - public static void main(String[] arguments) - throws IOException, TemplateException, RepositoryException, URISyntaxException, - ParseException, MavenRepositoryException { - DashboardArguments dashboardArguments = DashboardArguments.readCommandLine(arguments); - - if (dashboardArguments.hasVersionlessCoordinates()) { - generateLatestVersions( - dashboardArguments.getVersionlessCoordinates(), - dashboardArguments.getDependencyMediation()); - } else if (dashboardArguments.hasFile()) { - generate(dashboardArguments.getBomFile(), dashboardArguments.getDependencyMediation()); - } else { - generate(dashboardArguments.getBomCoordinates(), dashboardArguments.getDependencyMediation()); - } - } - - private static void generateLatestVersions( - String versionlessCoordinates, DependencyMediationAlgorithm dependencyMediationAlgorithm) - throws IOException, TemplateException, RepositoryException, URISyntaxException, - MavenRepositoryException { - List elements = Splitter.on(':').splitToList(versionlessCoordinates); - if (elements.size() != 2) { - System.err.println( - "Versionless coordinates should have one colon: " + versionlessCoordinates); - return; - } - String groupId = elements.get(0); - String artifactId = elements.get(1); - - RepositorySystem repositorySystem = RepositoryUtility.newRepositorySystem(); - // The highest version comes last. - ImmutableList versions = - RepositoryUtility.findVersions(repositorySystem, groupId, artifactId); - ImmutableList latestVersions = - versions.size() > LATEST_VERSIONS_COUNT ? versions.subList( - versions.size() - LATEST_VERSIONS_COUNT, - versions.size()) : versions; - for (String version : latestVersions) { - generate( - String.format("%s:%s:%s", groupId, artifactId, version), dependencyMediationAlgorithm); - } - generateVersionIndex(groupId, artifactId, versions); - } - - @VisibleForTesting - static Path generateVersionIndex(String groupId, String artifactId, List versions) - throws IOException, TemplateException, URISyntaxException { - Path directory = outputDirectory(groupId, artifactId, "snapshot").getParent(); - directory.toFile().mkdirs(); - Path page = directory.resolve("index.html"); - - Map templateData = new HashMap<>(); - templateData.put("versions", versions); - templateData.put("groupId", groupId); - templateData.put("artifactId", artifactId); - - File dashboardFile = page.toFile(); - try (Writer out = - new OutputStreamWriter(new FileOutputStream(dashboardFile), StandardCharsets.UTF_8)) { - Template dashboard = freemarkerConfiguration.getTemplate("/templates/version_index.ftl"); - dashboard.process(templateData, out); - } - - copyResource(directory, "css/dashboard.css"); - - return page; - } - - @VisibleForTesting - static Path generate( - String bomCoordinates, DependencyMediationAlgorithm dependencyMediationAlgorithm) - throws IOException, TemplateException, RepositoryException, URISyntaxException { - Path output = generate(Bom.readBom(bomCoordinates), dependencyMediationAlgorithm); - System.out.println("Wrote dashboard for " + bomCoordinates + " to " + output); - return output; - } - - @VisibleForTesting - static Path generate(Path bomFile, DependencyMediationAlgorithm dependencyMediationAlgorithm) - throws IOException, TemplateException, URISyntaxException, MavenRepositoryException, - InvalidVersionSpecificationException { - checkArgument(Files.isRegularFile(bomFile), "The input BOM %s is not a regular file", bomFile); - checkArgument(Files.isReadable(bomFile), "The input BOM %s is not readable", bomFile); - Path output = generate(Bom.readBom(bomFile), dependencyMediationAlgorithm); - System.out.println("Wrote dashboard for " + bomFile + " to " + output); - return output; - } - - private static Path generate(Bom bom, DependencyMediationAlgorithm dependencyMediationAlgorithm) - throws IOException, TemplateException, URISyntaxException, - InvalidVersionSpecificationException { - - ImmutableList managedDependencies = bom.getManagedDependencies(); - - DependencyMediation dependencyMediation = - dependencyMediationAlgorithm == DependencyMediationAlgorithm.MAVEN - ? DependencyMediation.MAVEN - : GradleDependencyMediation.withEnforcedPlatform(bom); - - ClassPathResult classPathResult = - classPathBuilder.resolve(managedDependencies, false, dependencyMediation); - ImmutableList classpath = classPathResult.getClassPath(); - - LinkageChecker linkageChecker = LinkageChecker.create(classpath); - - ImmutableSet linkageProblems = linkageChecker.findLinkageProblems(); - - ArtifactCache cache = loadArtifactInfo(managedDependencies); - Path output = generateHtml(bom, cache, classPathResult, linkageProblems); - - return output; - } - - private static Path outputDirectory(String groupId, String artifactId, String version) { - String versionPathElement = version.contains("-SNAPSHOT") ? "snapshot" : version; - return Paths.get("target", groupId, artifactId, versionPathElement); - } - - private static Path generateHtml( - Bom bom, - ArtifactCache cache, - ClassPathResult classPathResult, - ImmutableSet linkageProblems) - throws IOException, TemplateException, URISyntaxException { - - Artifact bomArtifact = new DefaultArtifact(bom.getCoordinates()); - - Path relativePath = - outputDirectory( - bomArtifact.getGroupId(), bomArtifact.getArtifactId(), bomArtifact.getVersion()); - Path output = Files.createDirectories(relativePath); - - copyResource(output, "css/dashboard.css"); - copyResource(output, "js/dashboard.js"); - - ImmutableMap> linkageProblemTable = - indexByJar(linkageProblems); - - List table = - generateReports( - freemarkerConfiguration, output, cache, linkageProblemTable, classPathResult, bom); - - generateDashboard( - freemarkerConfiguration, - output, - table, - cache.getGlobalDependencies(), - linkageProblemTable, - classPathResult, - bom); - - return output; - } - - private static void copyResource(Path output, String resourceName) - throws IOException, URISyntaxException { - ClassLoader classLoader = DashboardMain.class.getClassLoader(); - Path input = Paths.get(classLoader.getResource(resourceName).toURI()).toAbsolutePath(); - Path copy = output.resolve(input.getFileName()); - if (!Files.exists(copy)) { - Files.copy(input, copy); - } - } - - @VisibleForTesting - static Configuration configureFreemarker() { - Configuration configuration = new Configuration(new Version("2.3.28")); - configuration.setDefaultEncoding("UTF-8"); - configuration.setClassForTemplateLoading(DashboardMain.class, "/"); - return configuration; - } - - @VisibleForTesting - static List generateReports( - Configuration configuration, - Path output, - ArtifactCache cache, - ImmutableMap> linkageProblemTable, - ClassPathResult classPathResult, - Bom bom) - throws TemplateException { - - Map artifacts = cache.getInfoMap(); - List table = new ArrayList<>(); - for (Entry entry : artifacts.entrySet()) { - ArtifactInfo info = entry.getValue(); - try { - if (info.getException() != null) { - ArtifactResults unavailable = new ArtifactResults(entry.getKey()); - unavailable.setExceptionMessage(info.getException().getMessage()); - table.add(unavailable); - } else { - Artifact artifact = entry.getKey(); - ImmutableSet jarsInDependencyTree = - classPathResult.getClassPathEntries(Artifacts.toCoordinates(artifact)); - Map> relevantLinkageProblemTable = - Maps.filterKeys(linkageProblemTable, jarsInDependencyTree::contains); - - ArtifactResults results = - generateArtifactReport( - configuration, - output, - artifact, - entry.getValue(), - cache.getGlobalDependencies(), - ImmutableMap.copyOf(relevantLinkageProblemTable), - classPathResult, - bom); - table.add(results); - } - } catch (IOException ex) { - ArtifactResults unavailableTestResult = new ArtifactResults(entry.getKey()); - unavailableTestResult.setExceptionMessage(ex.getMessage()); - // Even when there's a problem generating test result, show the error in the dashboard - table.add(unavailableTestResult); - } - } - - return table; - } - - /** - * This is the only method that queries the Maven repository. - */ - private static ArtifactCache loadArtifactInfo(List artifacts) { - Map infoMap = new LinkedHashMap<>(); - List globalDependencies = new ArrayList<>(); - - for (Artifact artifact : artifacts) { - DependencyGraph completeDependencies = - dependencyGraphBuilder.buildVerboseDependencyGraph(artifact); - globalDependencies.add(completeDependencies); - - // picks versions according to Maven rules - DependencyGraph transitiveDependencies = - dependencyGraphBuilder.buildMavenDependencyGraph(new Dependency(artifact, "compile")); - - ArtifactInfo info = new ArtifactInfo(completeDependencies, transitiveDependencies); - infoMap.put(artifact, info); - } - - ArtifactCache cache = new ArtifactCache(); - cache.setInfoMap(infoMap); - cache.setGlobalDependencies(globalDependencies); - - return cache; - } - - private static ArtifactResults generateArtifactReport( - Configuration configuration, - Path output, - Artifact artifact, - ArtifactInfo artifactInfo, - List globalDependencies, - ImmutableMap> linkageProblemTable, - ClassPathResult classPathResult, - Bom bom) - throws IOException, TemplateException { - - String coordinates = Artifacts.toCoordinates(artifact); - File outputFile = output.resolve(coordinates.replace(':', '_') + ".html").toFile(); - - try (Writer out = new OutputStreamWriter( - new FileOutputStream(outputFile), StandardCharsets.UTF_8)) { - - // includes all versions - DependencyGraph graph = artifactInfo.getCompleteDependencies(); - List convergenceIssues = graph.findUpdates(); - - // picks versions according to Maven rules - DependencyGraph transitiveDependencies = artifactInfo.getTransitiveDependencies(); - - Map upperBoundFailures = - findUpperBoundsFailures(graph.getHighestVersionMap(), transitiveDependencies); - - Map globalUpperBoundFailures = findUpperBoundsFailures( - collectLatestVersions(globalDependencies), transitiveDependencies); - - long totalLinkageErrorCount = - linkageProblemTable.values().stream() - .flatMap(problemToClasses -> problemToClasses.stream().map(LinkageProblem::getSymbol)) - .distinct() // The dashboard counts linkage errors by the symbols - .count(); - - Template report = configuration.getTemplate("/templates/component.ftl"); - - Map templateData = new HashMap<>(); - - DefaultObjectWrapper wrapper = - new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_28).build(); - TemplateHashModel staticModels = wrapper.getStaticModels(); - templateData.put("linkageProblem", staticModels.get(LinkageProblem.class.getName())); - - templateData.put("artifact", artifact); - templateData.put("updates", convergenceIssues); - templateData.put("upperBoundFailures", upperBoundFailures); - templateData.put("globalUpperBoundFailures", globalUpperBoundFailures); - templateData.put("lastUpdated", LocalDateTime.now()); - templateData.put("dependencyGraph", graph); - templateData.put("linkageProblems", linkageProblemTable); - templateData.put("classPathResult", classPathResult); - templateData.put("totalLinkageErrorCount", totalLinkageErrorCount); - templateData.put("coordinates", bom.getCoordinates()); - - report.process(templateData, out); - - ArtifactResults results = new ArtifactResults(artifact); - results.addResult(TEST_NAME_UPPER_BOUND, upperBoundFailures.size()); - results.addResult(TEST_NAME_GLOBAL_UPPER_BOUND, globalUpperBoundFailures.size()); - results.addResult(TEST_NAME_DEPENDENCY_CONVERGENCE, convergenceIssues.size()); - results.addResult(TEST_NAME_LINKAGE_CHECK, (int) totalLinkageErrorCount); - - return results; - } - } - - private static Map findUpperBoundsFailures( - Map expectedVersionMap, - DependencyGraph transitiveDependencies) { - - Map actualVersionMap = transitiveDependencies.getHighestVersionMap(); - - VersionComparator comparator = new VersionComparator(); - - Map upperBoundFailures = new LinkedHashMap<>(); - - for (String id : expectedVersionMap.keySet()) { - String expectedVersion = expectedVersionMap.get(id); - String actualVersion = actualVersionMap.get(id); - // Check that the actual version is not null because it is - // possible for dependencies to appear or disappear from the tree - // depending on which version of another dependency is loaded. - // In both cases, no action is needed. - if (actualVersion != null && comparator.compare(actualVersion, expectedVersion) < 0) { - // Maven did not choose highest version - DefaultArtifact lower = new DefaultArtifact(id + ":" + actualVersion); - DefaultArtifact upper = new DefaultArtifact(id + ":" + expectedVersion); - upperBoundFailures.put(lower, upper); - } - } - return upperBoundFailures; - } - - /** - * Partitions {@code linkageProblems} by the JAR file that contains the {@link ClassFile}. - * - *

For example, {@code classes = result.get(JarX).get(linkageProblemY)} where {@code classes} - * are not null means that {@code JarX} has {@code linkageProblemY} and that {@code JarX} contains - * {@code classes} which reference {@code linkageProblemY.getSymbol()}. - */ - private static ImmutableMap> indexByJar( - ImmutableSet linkageProblems) { - - ImmutableMap> jarMap = - Multimaps.index(linkageProblems, problem -> problem.getSourceClass().getClassPathEntry()) - .asMap(); - - return ImmutableMap.copyOf(Maps.transformValues(jarMap, ImmutableSet::copyOf)); - } - - @VisibleForTesting - static void generateDashboard( - Configuration configuration, - Path output, - List table, - List globalDependencies, - ImmutableMap> linkageProblemTable, - ClassPathResult classPathResult, - Bom bom) - throws IOException, TemplateException { - - Map latestArtifacts = collectLatestVersions(globalDependencies); - - Map templateData = new HashMap<>(); - templateData.put("table", table); - templateData.put("lastUpdated", LocalDateTime.now()); - templateData.put("latestArtifacts", latestArtifacts); - templateData.put("linkageProblems", linkageProblemTable); - templateData.put("classPathResult", classPathResult); - templateData.put("dependencyPathRootCauses", findRootCauses(classPathResult)); - templateData.put("coordinates", bom.getCoordinates()); - templateData.put("dependencyGraphs", globalDependencies); - - // Accessing static methods from Freemarker template - // https://freemarker.apache.org/docs/pgui_misc_beanwrapper.html#autoid_60 - DefaultObjectWrapper wrapper = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_28) - .build(); - TemplateHashModel staticModels = wrapper.getStaticModels(); - templateData.put("dashboardMain", staticModels.get(DashboardMain.class.getName())); - templateData.put("pieChart", staticModels.get(PieChart.class.getName())); - templateData.put("linkageProblem", staticModels.get(LinkageProblem.class.getName())); - - File dashboardFile = output.resolve("index.html").toFile(); - try (Writer out = new OutputStreamWriter( - new FileOutputStream(dashboardFile), StandardCharsets.UTF_8)) { - Template dashboard = configuration.getTemplate("/templates/index.ftl"); - dashboard.process(templateData, out); - } - - File detailsFile = output.resolve("artifact_details.html").toFile(); - try (Writer out = new OutputStreamWriter( - new FileOutputStream(detailsFile), StandardCharsets.UTF_8)) { - Template details = configuration.getTemplate("/templates/artifact_details.ftl"); - details.process(templateData, out); - } - - File unstable = output.resolve("unstable_artifacts.html").toFile(); - try (Writer out = new OutputStreamWriter( - new FileOutputStream(unstable), StandardCharsets.UTF_8)) { - Template details = configuration.getTemplate("/templates/unstable_artifacts.ftl"); - details.process(templateData, out); - } - - File dependencyTrees = output.resolve("dependency_trees.html").toFile(); - try (Writer out = - new OutputStreamWriter(new FileOutputStream(dependencyTrees), StandardCharsets.UTF_8)) { - Template details = configuration.getTemplate("/templates/dependency_trees.ftl"); - details.process(templateData, out); - } - } - - private static Map collectLatestVersions( - List globalDependencies) { - Map latestArtifacts = new TreeMap<>(); - VersionComparator comparator = new VersionComparator(); - - if (globalDependencies != null) { - for (DependencyGraph graph : globalDependencies) { - Map map = graph.getHighestVersionMap(); - for (String key : map.keySet()) { - String newVersion = map.get(key); - String oldVersion = latestArtifacts.get(key); - if (oldVersion == null || comparator.compare(newVersion, oldVersion) > 0) { - latestArtifacts.put(key, map.get(key)); - } - } - } - } - return latestArtifacts; - } - - /** - * Returns the number of rows in {@code table} that show unavailable ({@code null} result) or some - * failures for {@code columnName}. - */ - public static long countFailures(List table, String columnName) { - return table.stream() - .filter(row -> row.getResult(columnName) == null || row.getFailureCount(columnName) > 0) - .count(); - } - - private static final int MINIMUM_NUMBER_DEPENDENCY_PATHS = 5; - - /** - * Returns mapping from jar files to summaries of the root problem in their {@link - * DependencyPath}s. The summary explains common patterns ({@code groupId:artifactId}) in the path - * elements. The returned map does not have a key for a jar file when it has fewer than {@link - * #MINIMUM_NUMBER_DEPENDENCY_PATHS} dependency paths or a common pattern is not found among the - * elements in the paths. - * - *

Example summary: "Artifacts 'com.google.http-client:google-http-client > - * commons-logging:commons-logging > log4j:log4j' exist in all 994 dependency paths. Example - * path: com.google.cloud:google-cloud-core:1.59.0 ..." - * - *

Using this summary in the BOM dashboard avoids repetitive items in the {@link - * DependencyPath} list that share the same root problem caused by widely-used libraries, for - * example, {@code commons-logging:commons-logging}, {@code com.google.http-client:google-http-client} - * and {@code log4j:log4j}. - */ - private static ImmutableMap findRootCauses(ClassPathResult classPathResult) { - // Freemarker is not good at handling non-string keys. Path object in .ftl is automatically - // converted to String. https://freemarker.apache.org/docs/app_faq.html#faq_nonstring_keys - ImmutableMap.Builder builder = ImmutableMap.builder(); - - for (ClassPathEntry entry : classPathResult.getClassPath()) { - List dependencyPaths = classPathResult.getDependencyPaths(entry); - - ImmutableList commonVersionlessArtifacts = - commonVersionlessArtifacts(dependencyPaths); - - if (dependencyPaths.size() > MINIMUM_NUMBER_DEPENDENCY_PATHS - && commonVersionlessArtifacts.size() > 1) { // The last paths elements are always same - builder.put( - entry.toString(), - summaryMessage( - dependencyPaths.size(), commonVersionlessArtifacts, dependencyPaths.get(0))); - } - } - return builder.build(); - } - - private static ImmutableList commonVersionlessArtifacts( - List dependencyPaths) { - ImmutableList initialVersionlessCoordinates = - dependencyPaths.get(0).getArtifactKeys(); - // LinkedHashSet remembers insertion order - LinkedHashSet versionlessCoordinatesIntersection = - Sets.newLinkedHashSet(initialVersionlessCoordinates); - for (DependencyPath dependencyPath : dependencyPaths) { - // List of versionless coordinates ("groupId:artifactId") - ImmutableList versionlessCoordinatesInPath = dependencyPath.getArtifactKeys(); - // intersection of elements in DependencyPaths - versionlessCoordinatesIntersection.retainAll(versionlessCoordinatesInPath); - } - - return ImmutableList.copyOf(versionlessCoordinatesIntersection); - } - - private static String summaryMessage( - int dependencyPathCount, List coordinates, DependencyPath examplePath) { - StringBuilder messageBuilder = new StringBuilder(); - messageBuilder.append("Dependency path '"); - messageBuilder.append(Joiner.on(" > ").join(coordinates)); - messageBuilder.append("' exists in all " + dependencyPathCount + " dependency paths. "); - messageBuilder.append("Example path: "); - messageBuilder.append(examplePath); - return messageBuilder.toString(); - } -} diff --git a/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/PieChart.java b/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/PieChart.java deleted file mode 100644 index 8b4ecd75f7..0000000000 --- a/dashboard/src/main/java/com/google/cloud/tools/opensource/dashboard/PieChart.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.tools.opensource.dashboard; - -import java.awt.geom.Point2D; - -public class PieChart { - - /** - * Calculate SVG arc end for a pie piece. Assumes the piece starts at the top of the circle. - * - * Do not forget: - * - * 1. SVG origin starts at top left. - * 2. x increases to the right and y increases **down**. - */ - static Point2D calculateEndPoint(double radius, double centerX, double centerY, double ratio) { - if (ratio > 1) { - ratio = 1.0; - } - - double radians = ratio * 2 * Math.PI; - - // Since we're starting at the top of the circle this is rotated 90 degrees - // from the normal coordinates. This is why we use sine for x and cosine for y. - double x = radius * (1 + Math.sin(radians)); - double y = radius * (1 - Math.cos(radians)); - return new Point2D.Double(x + centerX - radius, y + centerY - radius); - } - - // so I can avoid teaching FreeMarker how to wrap a java.awt.Point - public static double calculateEndPointX( - double radius, double centerX, double centerY, double ratio) { - return calculateEndPoint(radius, centerX, centerY, ratio).getX(); - } - - public static double calculateEndPointY( - double radius, double centerX, double centerY, double ratio) { - return calculateEndPoint(radius, centerX, centerY, ratio).getY(); - } -} diff --git a/dashboard/src/main/resources/css/dashboard.css b/dashboard/src/main/resources/css/dashboard.css deleted file mode 100644 index 9997f125cc..0000000000 --- a/dashboard/src/main/resources/css/dashboard.css +++ /dev/null @@ -1,147 +0,0 @@ -body { - font-family: "Poppins", sans-serif; - font-weight: 400; - line-height: 1.625; - margin-left: 2em; -} - -h1, -h2, -h3 { - color: #333333; - font-weight: 700; - margin: 0; - line-height: 1.2; - margin-top: 1ex; - margin-bottom: 1ex; -} - -h1 { - font-size: 3em; -} - -h2 { - font-size: 2.5em; -} - -h3 { - font-size: 2em; -} - -th, td { - padding: 5pt; -} - -pre { - line-height: normal; -} - -.pass { - background-color: lightgreen; - font-weight: bold; -} - -.fail { - background-color: pink; - font-weight: bold; -} - -.unavailable { - background-color: gray; - font-weight: bold; -} - -p.dependency-tree-node { - margin-top: 0; - margin-bottom: 0; -} - -.linkage-check-dependency-paths, .jar-linkage-report { - margin-left: 1em; -} - -p.jar-linkage-report-cause { - margin-bottom: 0; - margin-left: 2em; -} - -ul.jar-linkage-report-cause { - margin-top: 0; - margin-left: 3em; -} - -ul.jar-linkage-report-cause > li { - font: 1em 'Droid Sans Mono', monospace; -} - - /* ----- Statistic ----- */ -.statistics { - padding-top: 50px; -} - -.container { - min-height: 20ex; - display: flex; - flex-wrap: wrap; - align-items: flex-start; -} - -.statistic-item { - flex: 0 0 16em; - padding: 1.6em 2.5em; - position: relative; - min-height: 180px; - overflow: hidden; - margin-bottom: 40px; - border: none; - border-radius: 3px; - box-shadow: 0px 10px 20px 0px rgba(0, 0, 0, 0.03); - margin: 1em; - margin-left: unset; - margin-right: 2em; -} - -.statistic-item .desc { - font-size: 1.15em; - text-transform: uppercase; - font-weight: 300; - color: rgba(255, 255, 255, 0.6); -} - -.statistic-item h2 { - font-size: 2.3em; - font-weight: 300; - color: #fff; -} - -.statistic-item-green { - background: #00b26f; -} - -.statistic-item-orange { - background: #ff8300; -} - -.statistic-item-blue { - background: #00b5e9; -} - -.statistic-item-red { - background: #fa4251; -} - -.statistic-item-yellow { - background: #f1c40f; -} - -#piecharts th { - vertical-align: top; -} - -#piecharts td { - vertical-align: top; -} - -.pie { - "text-align: center" -} diff --git a/dashboard/src/main/resources/js/dashboard.js b/dashboard/src/main/resources/js/dashboard.js deleted file mode 100644 index 2a2128c45a..0000000000 --- a/dashboard/src/main/resources/js/dashboard.js +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - */ - -/** - * Toggles the visibility of an HTML element below the button. - * @param button clicked button element - */ -function toggleNextSiblingVisibility(button) { - const nextSibling = button.parentElement.nextElementSibling; - const currentVisibility = nextSibling.style.display !== "none"; - const nextVisibility = !currentVisibility; - nextSibling.style.display = nextVisibility ? "" : "none"; - button.innerText = nextVisibility ? "▼" : "▶"; -} diff --git a/dashboard/src/main/resources/poms/demo.xml b/dashboard/src/main/resources/poms/demo.xml deleted file mode 100644 index 7167c0415a..0000000000 --- a/dashboard/src/main/resources/poms/demo.xml +++ /dev/null @@ -1,49 +0,0 @@ - - 4.0.0 - - com.google.cloud - demo - 1.0-SNAPSHOT - jar - - demo-pom - - - UTF-8 - 1.8 - - - - - ${dependencyGroupId} - ${dependencyArtifactId} - ${dependencyVersion} - test - - - - - - - org.apache.maven.plugins - maven-enforcer-plugin - 3.0.0-M1 - - - enforce - - enforce - - - - - - - - - - - - \ No newline at end of file diff --git a/dashboard/src/main/resources/templates/artifact_details.ftl b/dashboard/src/main/resources/templates/artifact_details.ftl deleted file mode 100644 index 75acdcd51b..0000000000 --- a/dashboard/src/main/resources/templates/artifact_details.ftl +++ /dev/null @@ -1,55 +0,0 @@ - - - <#include "macros.ftl"> - - - Google Cloud Platform Java Open Source Dependency Dashboard Artifact Details Table - - - - -

Google Cloud Platform Java Dependency Dashboard Artifact Details

-

BOM: ${coordinates?html}

-

Dependency Details

- - - - - - - - - - <#list table as row> - <#assign report_url = row.getCoordinates()?replace(":", "_") + '.html' /> - - - <#-- The name key should match TEST_NAME_XXXX variables --> - <@testResult row=row name="Linkage Errors"/> - <@testResult row=row name="Upper Bounds"/> - <@testResult row=row name="Global Upper Bounds"/> - <@testResult row=row name="Dependency Convergence"/> - - -
Artifact - Linkage Check - Upper Bounds - Global Upper Bounds - Dependency Convergence
${row.getCoordinates()}
- -
- -

Linkage Errors

- - <#list linkageProblems as jar, problems> - <@formatJarLinkageReport jar problems classPathResult dependencyPathRootCauses/> - - -
-

Last generated at ${lastUpdated}

- - \ No newline at end of file diff --git a/dashboard/src/main/resources/templates/component.ftl b/dashboard/src/main/resources/templates/component.ftl deleted file mode 100644 index afdc26cc09..0000000000 --- a/dashboard/src/main/resources/templates/component.ftl +++ /dev/null @@ -1,156 +0,0 @@ - - - <#include "macros.ftl"> - <#assign groupId = artifact.getGroupId()> - <#assign artifactId = artifact.getArtifactId()> - <#assign version = artifact.getVersion()> - - - Google Cloud Platform Dependency Analysis Report for ${groupId}:${artifactId}:${version} - - - - - -

Dependency Analysis of ${groupId}:${artifactId}:${version}

-

BOM: ${coordinates?html}

-

Global Upper Bounds Check

- -

For each transitive dependency the library pulls in, the highest version - found anywhere in the union of the BOM's dependency trees is picked.

- - <#if globalUpperBoundFailures?size gt 0> -

Global Upper Bounds Fixes

- -

Suggested updates to bring this artifact into sync with the highest versions - of its dependencies used by any artifact in the BOM:

- -
    - <#list globalUpperBoundFailures as lower, upper> - <#if lower.getGroupId() == groupId && lower.getArtifactId() == artifactId - && lower.getVersion() == version ><#-- Not checking 'file' attribute of Artifact --> - <#-- When this is upgrading a BOM member --> -
  • - Upgrade ${lower} in the BOM to version "${upper.getVersion()}": - -

    Update the version of managed dependency element - ${groupId}:${artifactId} in the BOM:

    - -
    <dependencyManagement>
    -  <dependencies>
    -    ...
    -    <dependency>
    -      <groupId>${upper.getGroupId()}</groupId>
    -      <artifactId>${upper.getArtifactId()}</artifactId>
    -      <version>${upper.getVersion()}</version>
    -    </dependency>
    - -
  • - <#else > -
  • - Upgrade ${lower} to version "${upper.getVersion()}": - -

    Add this dependency element to the pom.xml for ${groupId}:${artifactId}:${version}: -

    - -
    <dependency>
    -<groupId>${upper.getGroupId()}</groupId>
    -<artifactId>${upper.getArtifactId()}</artifactId>
    -<version>${upper.getVersion()}</version>
    -</dependency>
    - -

    If the pom.xml for ${groupId}:${artifactId}:${version} already includes this - dependency, update the version of the existing dependency element. - Otherwise add a new dependency element to the - dependencyManagement section.

    -
  • - - -
- - <#else> -

- ${groupId}:${artifactId}:${version} selects the highest version of all dependencies. -

- - - -

Local Upper Bounds Check

- - -

For each transitive dependency the library pulls in, the highest version - found anywhere in the dependency tree is picked.

- - <#if upperBoundFailures?size gt 0> -

Upper Bounds Fixes

- -

Suggested updates to bring this artifact into sync with the highest versions - of each dependency found in its own dependency tree:

- -
    - <#list upperBoundFailures as lower, upper> -
  • Upgrade ${lower} to ${upper}: - -

    Add this dependency element to the pom.xml for ${groupId}:${artifactId}:${version}:

    - -
    <dependency>
    -  <groupId>${upper.getGroupId()}</groupId>
    -  <artifactId>${upper.getArtifactId()}</artifactId>
    -  <version>${upper.getVersion()}</version>
    -</dependency>
    - -
  • - -
- - <#else> -

- ${groupId}:${artifactId}:${version} selects the highest version of all dependencies. -

- - -

Dependency Convergence

- -

There is exactly one version of each dependency in the library's transitive dependency tree. - That is, two artifacts with the same group ID and artifact ID but different versions - do not appear in the tree. No dependency mediation is necessary.

- - <#if updates?size gt 0> -

Suggested Dependency Updates

- -

Caution: The algorithm for suggesting updates is imperfect. - They are not ordered by importance, and one change - may render another moot.

- -

Suggested updates to bring this artifact and its dependencies - into sync with the highest versions - of each dependency found in its own dependency tree:

- -
    - <#list updates as update> -
  • ${update}
  • - -
- <#else> -

${groupId}:${artifactId}:${version} Converges

- - - -

Linkage Check

- -

${totalLinkageErrorCount} linkage error(s)

- <#list linkageProblems as jar, problems> - <@formatJarLinkageReport jar problems classPathResult {} /> - - -

Dependencies

- - <#if dependencyGraph?? > - <@formatDependencyGraph dependencyGraph dependencyGraph.getRootPath() "" /> - <#else> -

Dependency information is unavailable

- -
-

Last generated at ${lastUpdated}

- - \ No newline at end of file diff --git a/dashboard/src/main/resources/templates/dependency_trees.ftl b/dashboard/src/main/resources/templates/dependency_trees.ftl deleted file mode 100644 index 6641141c2c..0000000000 --- a/dashboard/src/main/resources/templates/dependency_trees.ftl +++ /dev/null @@ -1,22 +0,0 @@ - - - <#include "macros.ftl"> - - - Google Cloud Platform Java Open Source Dependency Dashboard: Dependency Trees - - - - -

Dependency Tree of the Artifacts in ${coordinates}

-

BOM: ${coordinates?html}

- <#list dependencyGraphs as graph> - <#assign rootPath = graph.getRootPath() /> -

Dependency Tree of ${rootPath.getLeaf()?html}

- <@formatDependencyGraph graph rootPath "" /> - - -
-

Last generated at ${lastUpdated}

- - \ No newline at end of file diff --git a/dashboard/src/main/resources/templates/index.ftl b/dashboard/src/main/resources/templates/index.ftl deleted file mode 100644 index 36d5d1dade..0000000000 --- a/dashboard/src/main/resources/templates/index.ftl +++ /dev/null @@ -1,142 +0,0 @@ - - - <#include "macros.ftl"> - - - Google Cloud Platform Java Open Source Dependency Dashboard - - - - -

${coordinates} Dependency Status

-
- <#assign totalArtifacts = table?size> - -
-
-
-

${table?size}

- Total Artifacts Checked -
-
- <#assign linkageErrorCount = dashboardMain.countFailures(table, "Linkage Errors")> -

${linkageErrorCount}

- ${(linkageErrorCount == 1)?then("Has", "Have")} Linkage Errors -
-
- <#assign localUpperBoundsErrorCount = dashboardMain.countFailures(table, "Upper Bounds")> -

${dashboardMain.countFailures(table, "Upper Bounds")}

- ${(localUpperBoundsErrorCount == 1)?then("Has", "Have")} Upper Bounds Errors -
-
- <#assign globalUpperBoundsErrorCount = dashboardMain.countFailures(table, "Global Upper Bounds")> -

${dashboardMain.countFailures(table, "Global Upper Bounds")}

- ${(globalUpperBoundsErrorCount == 1)?then("Has", "Have")} Global Upper Bounds Errors -
-
- <#assign convergenceErrorCount = dashboardMain.countFailures(table, "Dependency Convergence")> -

${dashboardMain.countFailures(table, "Dependency Convergence")}

- ${(convergenceErrorCount == 1)?then("Fails", "Fail")} to Converge -
-
-
- - <#assign pieSize = 300 > -
- - - - - - - - - - - - - - - - - - - - - - - -
- Linkage Errors - Local Upper Bounds - Global Upper Bounds - Dependency Convergence
${linkageErrorCount} out of ${totalArtifacts} artifacts - ${plural(linkageErrorCount, "has", "have")} linkage errors. - ${localUpperBoundsErrorCount} out of ${totalArtifacts} artifacts - ${plural(localUpperBoundsErrorCount, "does not", "do not")} pick the - latest versions of all artifacts in their own dependency tree. - ${globalUpperBoundsErrorCount} out of ${totalArtifacts} artifacts - ${plural(globalUpperBoundsErrorCount, "does not", "do not")} select the - most recent version of all artifacts in the BOM.${convergenceErrorCount} out of ${totalArtifacts} artifacts - ${plural(convergenceErrorCount, "fails", "fail")} to converge. -
- <@pieChartSvg - description="${linkageErrorCount} out of ${totalArtifacts} artifacts have linkage - errors." - ratio=linkageErrorCount / totalArtifacts /> - - <#assign doesNot=plural(localUpperBoundsErrorCount, "does not", "do not")> - <@pieChartSvg - description="${localUpperBoundsErrorCount} out of ${totalArtifacts} artifacts - $doesNot pick the - latest versions of all artifacts in their own dependency tree." - ratio=localUpperBoundsErrorCount / totalArtifacts /> - - <@pieChartSvg - description="${globalUpperBoundsErrorCount} out of ${totalArtifacts} artifacts have - global upper bounds errors." - ratio=globalUpperBoundsErrorCount / totalArtifacts /> - - <#assign fails=plural(convergenceErrorCount, "fails", "fail")/> - <@pieChartSvg - description="${convergenceErrorCount} out of ${totalArtifacts} artifacts - ${fails} to converge." - ratio=convergenceErrorCount / totalArtifacts /> -
-
- -

- BOM source code -

- -

- Detailed Artifact Reports -

- -

- Pre 1.0 Artifacts -

- -

Recommended Versions

- -

These are the most recent versions of dependencies used by any of the covered artifacts.

- - - -

- Dependency Trees -

- -
- -

Last generated at ${lastUpdated}

- - \ No newline at end of file diff --git a/dashboard/src/main/resources/templates/macros.ftl b/dashboard/src/main/resources/templates/macros.ftl deleted file mode 100644 index 3d160cdcee..0000000000 --- a/dashboard/src/main/resources/templates/macros.ftl +++ /dev/null @@ -1,142 +0,0 @@ -<#function pluralize number singularNoun pluralNoun> - <#local plural = number gt 1 /> - <#return number + " " + plural?string(pluralNoun, singularNoun)> - -<#-- same as above but without the number --> -<#function plural number singularNoun pluralNoun> - <#local plural = number gt 1 /> - <#return plural?string(pluralNoun, singularNoun)> - - -<#macro formatJarLinkageReport classPathEntry linkageProblems classPathResult - dependencyPathRootCauses> - <#-- problemsToClasses: ImmutableMap> to get key and set of - values in Freemarker --> - <#assign problemsToClasses = linkageProblem.groupBySymbolProblem(linkageProblems) /> - <#assign symbolProblemCount = problemsToClasses?size /> - <#assign referenceCount = 0 /> - <#list problemsToClasses?values as classes> - <#assign referenceCount += classes?size /> - - -

${classPathEntry?html}

-

- ${pluralize(symbolProblemCount, "target class", "target classes")} - causing linkage errors referenced from - ${pluralize(referenceCount, "source class", "source classes")}. -

- <#list problemsToClasses as problem, sourceClasses> - <#if sourceClasses?size == 1> - <#assign sourceClass = sourceClasses[0] /> -

${problem?html}, referenced from ${sourceClass?html}

- <#else> -

${problem?html}, referenced from ${ - pluralize(sourceClasses?size, "class", "classes")?html} - -

- - - - - <#assign jarsInProblem = {} > - <#list linkageProblems as problem> - <#if (problem.getTargetClass())?? > - <#assign targetClassPathEntry = problem.getTargetClass().getClassPathEntry() /> - <#-- Freemarker's hash requires its keys to be strings. - https://freemarker.apache.org/docs/app_faq.html#faq_nonstring_keys --> - <#assign jarsInProblem = jarsInProblem + { targetClassPathEntry.toString() : targetClassPathEntry } > - - - <#list jarsInProblem?values as jarInProblem> - <@showDependencyPath dependencyPathRootCauses classPathResult jarInProblem /> - - <#if !jarsInProblem?values?seq_contains(classPathEntry) > - <@showDependencyPath dependencyPathRootCauses classPathResult classPathEntry /> - - - - -<#macro showDependencyPath dependencyPathRootCauses classPathResult classPathEntry> - <#assign dependencyPaths = classPathResult.getDependencyPaths(classPathEntry) /> - <#assign hasRootCause = dependencyPathRootCauses[classPathEntry]?? /> - <#assign hideDependencyPathsByDefault = (!hasRootCause) && (dependencyPaths?size > 5) /> -

- The following ${plural(dependencyPaths?size, "path contains", "paths contain")} ${classPathEntry?html}: - <#if hideDependencyPathsByDefault> - <#-- The dependency paths are not summarized --> - - -

- - <#if hasRootCause> -

${dependencyPathRootCauses[classPathEntry]?html} -

- <#else> - -
    - <#list dependencyPaths as dependencyPath > -
  • ${dependencyPath}
  • - -
- - - -<#macro formatDependencyGraph graph node parent> - <#if node == graph.getRootPath() > - <#assign label = 'root' /> - <#else> - <#assign label = 'parent: ' + parent.getLeaf() /> - -

${node.getLeaf()}

-
    - <#list graph.getChildren(node) as childNode> - <#if node != childNode> -
  • - <@formatDependencyGraph graph childNode node /> -
  • - - -
- - -<#macro testResult row name> - <#if row.getResult(name)?? ><#-- checking isNotNull() --> - <#-- When it's not null, the test ran. It's either PASS or FAIL --> - <#assign test_label = row.getResult(name)?then('PASS', 'FAIL')> - <#assign failure_count = row.getFailureCount(name)> - <#else> - <#-- Null means there's an exception and test couldn't run --> - <#assign test_label = "UNAVAILABLE"> - - - <#if row.getResult(name)?? > - <#assign page_anchor = name?replace(" ", "-")?lower_case /> - - <#if failure_count gt 0>${pluralize(failure_count, "FAILURE", "FAILURES")} - <#else>PASS - - - <#else>UNAVAILABLE - - - - -<#macro pieChartSvg description ratio> - <#assign largeArcFlag = (ratio gt 0.5)?string("1", "0")> - <#assign endPointX = pieChart.calculateEndPointX(100, 100, 100, ratio)> - <#assign endPointY = pieChart.calculateEndPointY(100, 100, 100, ratio)> - - ${description} - - - - \ No newline at end of file diff --git a/dashboard/src/main/resources/templates/unstable_artifacts.ftl b/dashboard/src/main/resources/templates/unstable_artifacts.ftl deleted file mode 100644 index e02e56204b..0000000000 --- a/dashboard/src/main/resources/templates/unstable_artifacts.ftl +++ /dev/null @@ -1,40 +0,0 @@ - - - <#include "macros.ftl"> - - - Google Cloud Platform Java Open Source Dependency Dashboard: Unstable Artifacts - - - - -

Dependency Status of ${coordinates}

-

BOM: ${coordinates?html}

-

Pre 1.0 Versions

- -

- These are dependencies found in the GCP orbit that have not yet reached 1.0. - No 1.0 or later library should depend on them. - If the libraries are stable, advance them to 1.0. - Otherwise replace the dependency with something else. -

- - <#assign unstableCount = 0> -
    - <#list latestArtifacts as artifact, version> - <#if version[0] == '0'> - <#assign unstableCount++> -
  • ${artifact}:${version}
  • - - -
- - <#if unstableCount == 0> -

All versions are 1.0 or later.

- - - -
-

Last generated at ${lastUpdated}

- - \ No newline at end of file diff --git a/dashboard/src/main/resources/templates/version_index.ftl b/dashboard/src/main/resources/templates/version_index.ftl deleted file mode 100644 index 602bdf633a..0000000000 --- a/dashboard/src/main/resources/templates/version_index.ftl +++ /dev/null @@ -1,20 +0,0 @@ - - - - - ${groupId}:${artifactId} - - - -

${groupId}:${artifactId}

- -
    - <#list versions as version> -
  • - ${version} -
  • - -
- - - diff --git a/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/ArtifactResultsTest.java b/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/ArtifactResultsTest.java deleted file mode 100644 index bcfab9e49c..0000000000 --- a/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/ArtifactResultsTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 - * - * 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.tools.opensource.dashboard; - -import org.eclipse.aether.artifact.DefaultArtifact; -import org.junit.Assert; -import org.junit.Test; - -public class ArtifactResultsTest { - - private ArtifactResults results = - new ArtifactResults(new DefaultArtifact("com.google.guava:guava:23.0")); - - @Test - public void testAddResult() { - results.addResult("foo", 0); - results.addResult("bar", 10); - Assert.assertTrue(results.getResult("foo")); - Assert.assertFalse(results.getResult("bar")); - Assert.assertNull(results.getResult("baz")); - } - - @Test - public void testGetFailureCount() { - results.addResult("foo", 0); - results.addResult("bar", 10); - Assert.assertEquals(0, results.getFailureCount("foo")); - Assert.assertEquals(10, results.getFailureCount("bar")); - Assert.assertEquals(0, results.getFailureCount("baz")); - } - - @Test - public void testGetCoordinates() { - Assert.assertEquals("com.google.guava:guava:23.0", results.getCoordinates()); - } - -} diff --git a/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/DashboardArgumentsTest.java b/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/DashboardArgumentsTest.java deleted file mode 100644 index 62204552b6..0000000000 --- a/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/DashboardArgumentsTest.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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.tools.opensource.dashboard; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import com.google.cloud.tools.opensource.dashboard.DashboardArguments.DependencyMediationAlgorithm; -import com.google.common.truth.Truth; -import java.nio.file.Paths; -import org.apache.commons.cli.AlreadySelectedException; -import org.apache.commons.cli.MissingOptionException; -import org.apache.commons.cli.ParseException; -import org.junit.Assert; -import org.junit.Test; - -public class DashboardArgumentsTest { - - @Test - public void testParseArgument_file() throws ParseException { - DashboardArguments dashboardArguments = DashboardArguments.readCommandLine("-f", "../pom.xml"); - - assertTrue(dashboardArguments.hasFile()); - assertEquals(dashboardArguments.getDependencyMediation(), DependencyMediationAlgorithm.MAVEN); - assertEquals(Paths.get("../pom.xml").toAbsolutePath(), dashboardArguments.getBomFile()); - assertNull(dashboardArguments.getBomCoordinates()); - } - - @Test - public void testParseArgument_coordinates() throws ParseException { - DashboardArguments dashboardArguments = - DashboardArguments.readCommandLine("-c", "com.google.cloud:libraries-bom:1.0.0"); - assertFalse(dashboardArguments.hasFile()); - assertEquals( - "com.google.cloud:libraries-bom:1.0.0", dashboardArguments.getBomCoordinates()); - } - - @Test - public void testParseArgument_coordinatesWithLeadingSpace() throws ParseException { - // Maven exec plugin adds a leading space when arguments are passed as - // -Dexec.arguments="-c com.google.cloud:libraries-bom:$VERSION" - DashboardArguments dashboardArguments = - DashboardArguments.readCommandLine("-c", " com.google.cloud:libraries-bom:1.0.0"); - assertEquals( - "com.google.cloud:libraries-bom:1.0.0", dashboardArguments.getBomCoordinates()); - assertNull(dashboardArguments.getBomFile()); - } - - @Test - public void testParseArgument_missingInput() throws ParseException { - try { - DashboardArguments.readCommandLine(); - Assert.fail("The argument should validate missing input"); - } catch (MissingOptionException ex) { - // pass - } - } - - @Test - public void testParseArgument_duplicateOptions_coordinates_file() throws ParseException { - try { - DashboardArguments.readCommandLine( - "-c", "com.google.cloud:libraries-bom:1.0.0", "-f", "../pom.xml"); - Assert.fail("The argument should validate duplicate input"); - } catch (AlreadySelectedException ex) { - // pass - } - } - - @Test - public void testParseArgument_duplicateOptions_coordinates_allVersions() throws ParseException { - try { - DashboardArguments.readCommandLine( - "-c", "com.google.cloud:libraries-bom:1.0.0", "-a", "com.google.cloud:libraries-bom"); - Assert.fail("The argument should validate duplicate input"); - } catch (AlreadySelectedException ex) { - // pass - } - } - - @Test - public void testParseArgument_dependencyMediation_valid() throws ParseException { - DashboardArguments dashboardArguments = - DashboardArguments.readCommandLine("-f", "../pom.xml", "-m", "gradle"); - - assertEquals(dashboardArguments.getDependencyMediation(), DependencyMediationAlgorithm.GRADLE); - } - - @Test - public void testParseArgument_dependencyMediation_invalid() { - try { - DashboardArguments dashboardArguments = - DashboardArguments.readCommandLine("-f", "../pom.xml", "-m", "ant"); - Assert.fail("The argument should validate invalid dependency mediation value"); - } catch (ParseException ex) { - // pass - Truth.assertThat(ex.getMessage()).isEqualTo("Valid values for '-m' are [maven, gradle]"); - } - } -} diff --git a/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/DashboardTest.java b/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/DashboardTest.java deleted file mode 100644 index ffeba49324..0000000000 --- a/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/DashboardTest.java +++ /dev/null @@ -1,491 +0,0 @@ -/* - * 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 - * - * 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.tools.opensource.dashboard; - -import static com.google.common.collect.ImmutableList.toImmutableList; -import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; - -import com.google.cloud.tools.opensource.dashboard.DashboardArguments.DependencyMediationAlgorithm; -import com.google.cloud.tools.opensource.dependencies.Artifacts; -import com.google.cloud.tools.opensource.dependencies.Bom; -import com.google.common.base.CharMatcher; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Streams; -import com.google.common.io.MoreFiles; -import com.google.common.io.RecursiveDeleteOption; -import com.google.common.truth.Correspondence; -import java.io.IOException; -import java.io.InputStream; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import nu.xom.Builder; -import nu.xom.Document; -import nu.xom.Element; -import nu.xom.Node; -import nu.xom.Nodes; -import nu.xom.ParsingException; -import nu.xom.XPathContext; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.resolution.ArtifactDescriptorException; -import org.hamcrest.core.StringStartsWith; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.BeforeClass; -import org.junit.Test; - -public class DashboardTest { - - private static final Correspondence NODE_VALUES = - Correspondence.transforming(node -> trimAndCollapseWhiteSpace(node.getValue()), "has value"); - - private static String trimAndCollapseWhiteSpace(String value) { - return CharMatcher.whitespace().trimAndCollapseFrom(value, ' '); - } - - private static Path outputDirectory; - private static Builder builder = new Builder(); - private static Document dashboard; - private static Document details; - private static Document unstable; - - @BeforeClass - public static void setUp() throws IOException, ParsingException { - // Creates "index.html" and artifact reports in outputDirectory - try { - outputDirectory = - DashboardMain.generate( - "com.google.cloud:libraries-bom:1.0.0", DependencyMediationAlgorithm.MAVEN); - } catch (Throwable t) { - t.printStackTrace(); - Assert.fail("Could not generate dashboard"); - } - - dashboard = parseOutputFile("index.html"); - details = parseOutputFile("artifact_details.html"); - unstable = parseOutputFile("unstable_artifacts.html"); - } - - @AfterClass - public static void cleanUp() { - try { - // Mac's APFS fails with InsecureRecursiveDeleteException without ALLOW_INSECURE. - // Still safe as this test does not use symbolic links - if (outputDirectory != null) { - MoreFiles.deleteRecursively(outputDirectory, RecursiveDeleteOption.ALLOW_INSECURE); - } - } catch (IOException ex) { - // no big deal - } - } - - @Test // https://github.com/GoogleCloudPlatform/cloud-opensource-java/issues/617 - public void testPlural() { - Nodes statisticItems = dashboard.query("//section[@class='statistics']/div/div"); - for (Node node : statisticItems) { - Node h2 = node.query("h2").get(0); - Node span = node.query("span").get(0); - int errorCount = Integer.parseInt(h2.getValue()); - if (errorCount == 1) { - String message = span.getValue(); - Assert.assertEquals("Has Linkage Errors", message); - } - } - - Assert.assertFalse(dashboard.toXML().contains("1 HAVE")); - } - - @Test - public void testHeader() { - Nodes h1 = dashboard.query("//h1"); - assertThat(h1).hasSize(1); - Assert.assertEquals("com.google.cloud:libraries-bom:1.0.0 Dependency Status", - h1.get(0).getValue()); - } - - @Test - public void testSvg() { - XPathContext context = new XPathContext("svg", "http://www.w3.org/2000/svg"); - Nodes svg = dashboard.query("//svg:svg", context); - assertThat(svg).hasSize(4); - } - - @Test - public void testCss() { - Path dashboardCss = outputDirectory.resolve("dashboard.css"); - Assert.assertTrue(Files.exists(dashboardCss)); - Assert.assertTrue(Files.isRegularFile(dashboardCss)); - } - - private static Document parseOutputFile(String fileName) - throws IOException, ParsingException { - Path html = outputDirectory.resolve(fileName); - Assert.assertTrue("Could not find a regular file for " + fileName, - Files.isRegularFile(html)); - Assert.assertTrue("The file is not readable: " + fileName, Files.isReadable(html)); - - try (InputStream source = Files.newInputStream(html)) { - return builder.build(source); - } - } - - @Test - public void testArtifactDetails() throws IOException, ArtifactDescriptorException { - List artifacts = Bom.readBom("com.google.cloud:libraries-bom:1.0.0") - .getManagedDependencies(); - Assert.assertTrue("Not enough artifacts found", artifacts.size() > 1); - - Assert.assertEquals("en-US", dashboard.getRootElement().getAttribute("lang").getValue()); - - Nodes tr = details.query("//tr"); - Assert.assertEquals(artifacts.size() + 1, tr.size()); // header row adds 1 - for (int i = 1; i < tr.size(); i++) { // start at 1 to skip header row - Nodes td = tr.get(i).query("td"); - Assert.assertEquals(Artifacts.toCoordinates(artifacts.get(i - 1)), td.get(0).getValue()); - for (int j = 1; j < 5; ++j) { // start at 1 to skip the leftmost artifact coordinates column - assertValidCellValue((Element) td.get(j)); - } - } - Nodes href = details.query("//tr/td[@class='artifact-name']/a/@href"); - for (int i = 0; i < href.size(); i++) { - String fileName = href.get(i).getValue(); - Artifact artifact = artifacts.get(i); - Assert.assertEquals( - Artifacts.toCoordinates(artifact).replace(':', '_') + ".html", - URLDecoder.decode(fileName, "UTF-8")); - Path componentReport = outputDirectory.resolve(fileName); - Assert.assertTrue(fileName + " is missing", Files.isRegularFile(componentReport)); - try { - Document report = builder.build(componentReport.toFile()); - Assert.assertEquals("en-US", report.getRootElement().getAttribute("lang").getValue()); - } catch (ParsingException ex) { - byte[] data = Files.readAllBytes(componentReport); - String message = "Could not parse " + componentReport + " at line " + - ex.getLineNumber() + ", column " + ex.getColumnNumber() + "\r\n"; - message += ex.getMessage() + "\r\n"; - message += new String(data, StandardCharsets.UTF_8); - Assert.fail(message); - } - } - } - - private static void assertValidCellValue(Element cellElement) { - String cellValue = cellElement.getValue().replaceAll("\\s", ""); - assertThat(cellValue).containsMatch("PASS|\\d+FAILURES?"); - assertWithMessage("It should not use plural for 1 item") - .that(cellValue) - .doesNotContainMatch("1 FAILURES"); - assertThat(cellElement.getAttributeValue("class")).isAnyOf("pass", "fail"); - } - - @Test - public void testDashboard_statisticBox() { - Nodes artifactCount = - dashboard.query("//div[@class='statistic-item statistic-item-green']/h2"); - Assert.assertTrue(artifactCount.size() > 0); - for (Node artifactCountElement : artifactCount) { - String value = artifactCountElement.getValue().trim(); - Assert.assertTrue(value, Integer.parseInt(value) > 0); - } - } - - @Test - public void testLinkageReports() { - Nodes dependencyPaths = details.query("//p[@class='linkage-check-dependency-paths']"); - Node dependencyPathMessageOnProblem = dependencyPaths.get(dependencyPaths.size() - 1); - Assert.assertEquals( - "The following paths contain com.google.guava:guava-jdk5:13.0: ▶", - trimAndCollapseWhiteSpace(dependencyPathMessageOnProblem.getValue())); - - Node dependencyPathMessageOnSource = dependencyPaths.get(dependencyPaths.size() - 2); - Assert.assertEquals( - "The following paths contain com.google.guava:guava:27.1-android:", - trimAndCollapseWhiteSpace(dependencyPathMessageOnSource.getValue())); - } - - @Test - public void testDashboard_recommendedCoordinates() { - Nodes recommendedListItem = dashboard.query("//ul[@id='recommended']/li"); - Assert.assertTrue(recommendedListItem.size() > 100); - - // fails if these are not valid Maven coordinates - for (Node node : recommendedListItem) { - new DefaultArtifact(node.getValue()); - } - - ImmutableList coordinateList = - Streams.stream(recommendedListItem).map(Node::getValue).collect(toImmutableList()); - - ArrayList sorted = new ArrayList<>(coordinateList); - Comparator comparator = new SortWithoutVersion(); - Collections.sort(sorted, comparator); - - for (int i = 0; i < sorted.size(); i++) { - Assert.assertEquals( - "Coordinates are not sorted: ", sorted.get(i), coordinateList.get(i)); - } - } - - private static class SortWithoutVersion implements Comparator { - @Override - public int compare(String s1, String s2) { - s1 = s1.substring(0, s1.lastIndexOf(':')); - s2 = s2.substring(0, s2.lastIndexOf(':')); - return s1.compareTo(s2); - } - } - - @Test - public void testDashboard_unstableDependencies() { - // Pre 1.0 version section - Nodes li = unstable.query("//ul[@id='unstable']/li"); - Assert.assertTrue(li.size() > 1); - for (int i = 0; i < li.size(); i++) { - String value = li.get(i).getValue(); - Assert.assertTrue(value, value.contains(":0")); - } - - // This element appears only when every dependency becomes stable - Nodes stable = dashboard.query("//p[@id='stable-notice']"); - assertThat(stable).isEmpty(); - } - - @Test - public void testDashboard_lastUpdatedField() { - Nodes updated = dashboard.query("//p[@id='updated']"); - Assert.assertEquals( - "Could not find updated field: " + dashboard.toXML(), 1, updated.size()); - } - - @Test - public void testComponent_linkageCheckResult_java8() throws IOException, ParsingException { - Assume.assumeThat(System.getProperty("java.version"), StringStartsWith.startsWith("1.8.")); - // The version used in libraries-bom 1.0.0 - Document document = parseOutputFile( - "com.google.http-client_google-http-client-appengine_1.29.1.html"); - Nodes reports = document.query("//p[@class='jar-linkage-report']"); - assertThat(reports).hasSize(1); - assertThat(trimAndCollapseWhiteSpace(reports.get(0).getValue())) - .isEqualTo("100 target classes causing linkage errors referenced from 540 source classes."); - - - Nodes artifactDetailsReports = details.query("//p[@class='jar-linkage-report']"); - // appengine-api-sdk, shown as first item in linkage errors, has these errors - assertThat(trimAndCollapseWhiteSpace(artifactDetailsReports.get(0).getValue())) - .isEqualTo("4 target classes causing linkage errors referenced from 4 source classes."); - - Nodes causes = document.query("//p[@class='jar-linkage-report-cause']"); - assertWithMessage( - "google-http-client-appengine should show linkage errors for RpcStubDescriptor") - .that(causes) - .comparingElementsUsing(NODE_VALUES) - .contains( - "Class com.google.net.rpc3.client.RpcStubDescriptor is not found," - + " referenced from 21 classes ▶"); // '▶' is the toggle button - } - - @Test - public void testComponent_linkageCheckResult_java11() throws IOException, ParsingException { - String javaVersion = System.getProperty("java.version"); - // javaMajorVersion is 1 when we use Java 8. Still good indicator to ensure Java 11 or higher. - int javaMajorVersion = Integer.parseInt(javaVersion.split("\\.")[0]); - Assume.assumeTrue(javaMajorVersion >= 11); - - Nodes artifactDetailsReports = details.query("//p[@class='jar-linkage-report']"); - // appengine-api-sdk, shown as first item in linkage errors, has these errors - assertThat(trimAndCollapseWhiteSpace(artifactDetailsReports.get(0).getValue())) - .isEqualTo("5 target classes causing linkage errors referenced from 5 source classes."); - - // The version used in libraries-bom 1.0.0. The google-http-client-appengine has been known to - // have linkage errors in its dependency appengine-api-1.0-sdk:1.9.71. - Document document = - parseOutputFile("com.google.http-client_google-http-client-appengine_1.29.1.html"); - Nodes reports = document.query("//p[@class='jar-linkage-report']"); - assertThat(reports).hasSize(1); - - // This number of linkage errors differs between Java 8 and Java 11 for the javax.activation - // package removal (JEP 320: Remove the Java EE and CORBA Modules). For the detail, see - // https://github.com/GoogleCloudPlatform/cloud-opensource-java/issues/1849. - assertThat(trimAndCollapseWhiteSpace(reports.get(0).getValue())) - .isEqualTo("105 target classes causing linkage errors referenced from 562 source classes."); - - Nodes causes = document.query("//p[@class='jar-linkage-report-cause']"); - assertWithMessage( - "google-http-client-appengine should show linkage errors for RpcStubDescriptor") - .that(causes) - .comparingElementsUsing(NODE_VALUES) - .contains( - "Class com.google.net.rpc3.client.RpcStubDescriptor is not found," - + " referenced from 21 classes ▶"); // '▶' is the toggle button - } - - @Test - public void testComponent_success() throws IOException, ParsingException { - Document document = parseOutputFile( - "com.google.api.grpc_proto-google-common-protos_1.14.0.html"); - Nodes greens = document.query("//h3[@style='color: green']"); - Assert.assertTrue(greens.size() >= 2); - Nodes presDependencyMediation = - document.query("//pre[@class='suggested-dependency-mediation']"); - // There's a pre tag for dependency - assertThat(presDependencyMediation).hasSize(1); - - Nodes presDependencyTree = document.query("//p[@class='dependency-tree-node']"); - Assert.assertTrue( - "Dependency Tree should be shown in dashboard", presDependencyTree.size() > 0); - } - - @Test - public void testComponent_failure() throws IOException, ParsingException { - Document document = parseOutputFile( - "com.google.api.grpc_grpc-google-common-protos_1.14.0.html"); - - // com.google.api.grpc:grpc-google-common-protos:1.14.0 has no green section - Nodes greens = document.query("//h3[@style='color: green']"); - assertThat(greens).isEmpty(); - - // "Global Upper Bounds Fixes", "Upper Bounds Fixes", and "Suggested Dependency Updates" are red - Nodes reds = document.query("//h3[@style='color: red']"); - assertThat(reds).hasSize(3); - Nodes presDependencyMediation = - document.query("//pre[@class='suggested-dependency-mediation']"); - Assert.assertTrue( - "For failed component, suggested dependency should be shown", - presDependencyMediation.size() >= 1); - Nodes dependencyTree = document.query("//p[@class='dependency-tree-node']"); - Assert.assertTrue( - "Dependency Tree should be shown in dashboard even when FAILED", - dependencyTree.size() > 0); - } - - @Test - public void testLinkageErrorsInProvidedDependency() throws IOException, ParsingException { - // google-http-client-appengine has provided dependency to (problematic) appengine-api-1.0-sdk - Document document = parseOutputFile( - "com.google.http-client_google-http-client-appengine_1.29.1.html"); - Nodes linkageCheckMessages = document.query("//ul[@class='jar-linkage-report-cause']/li"); - assertThat(linkageCheckMessages.size()).isGreaterThan(0); - assertThat(linkageCheckMessages.get(0).getValue()) - .contains("com.google.appengine.api.appidentity.AppIdentityServicePb"); - } - - @Test - public void testLinkageErrors_ensureNoDuplicateSymbols() throws IOException, ParsingException { - Document document = - parseOutputFile("com.google.http-client_google-http-client-appengine_1.29.1.html"); - Nodes linkageCheckMessages = document.query("//p[@class='jar-linkage-report-cause']"); - assertThat(linkageCheckMessages.size()).isGreaterThan(0); - - List messages = new ArrayList<>(); - for (int i = 0; i < linkageCheckMessages.size(); ++i) { - messages.add(linkageCheckMessages.get(i).getValue()); - } - - // When uniqueness of SymbolProblem and Symbol classes are incorrect, dashboard has duplicates. - assertThat(messages).containsNoDuplicates(); - } - - @Test - public void testZeroLinkageErrorShowsZero() throws IOException, ParsingException { - // grpc-auth does not have a linkage error, and it should show zero in the section - Document document = parseOutputFile("io.grpc_grpc-auth_1.20.0.html"); - Nodes linkageErrorsTotal = document.query("//p[@id='linkage-errors-total']"); - assertThat(linkageErrorsTotal).hasSize(1); - assertThat(linkageErrorsTotal.get(0).getValue()).contains("0 linkage error(s)"); - } - - @Test - public void testGlobalUpperBoundUpgradeMessage() throws IOException, ParsingException { - // Case 1: BOM needs to be updated - Document document = parseOutputFile("com.google.protobuf_protobuf-java-util_3.6.1.html"); - Nodes globalUpperBoundBomUpgradeNodes = - document.query("//li[@class='global-upper-bound-bom-upgrade']"); - assertThat(globalUpperBoundBomUpgradeNodes).hasSize(1); - String bomUpgradeMessage = globalUpperBoundBomUpgradeNodes.get(0).getValue(); - assertThat(bomUpgradeMessage) - .contains( - "Upgrade com.google.protobuf:protobuf-java-util:jar:3.6.1 in the BOM to version" - + " \"3.7.1\""); - - // Case 2: Dependency needs to be updated - Nodes globalUpperBoundDependencyUpgradeNodes = - document.query("//li[@class='global-upper-bound-dependency-upgrade']"); - - // The artifact report should contain the following 6 global upper bound dependency upgrades: - // Upgrade com.google.guava:guava:jar:19.0 to version "27.1-android" - // Upgrade com.google.protobuf:protobuf-java:jar:3.6.1 to version "3.7.1" - assertThat(globalUpperBoundDependencyUpgradeNodes.size()).isEqualTo(2); - String dependencyUpgradeMessage = globalUpperBoundDependencyUpgradeNodes.get(0).getValue(); - assertThat(dependencyUpgradeMessage) - .contains("Upgrade com.google.guava:guava:jar:19.0 to version \"27.1-android\""); - } - - @Test - public void testBomCoordinatesInComponent() throws IOException, ParsingException { - Document document = parseOutputFile("com.google.protobuf_protobuf-java-util_3.6.1.html"); - Nodes bomCoordinatesNodes = document.query("//p[@class='bom-coordinates']"); - assertThat(bomCoordinatesNodes).hasSize(1); - Assert.assertEquals( - "BOM: com.google.cloud:libraries-bom:1.0.0", bomCoordinatesNodes.get(0).getValue()); - } - - @Test - public void testBomCoordinatesInArtifactDetails() throws IOException, ParsingException { - Document document = parseOutputFile("artifact_details.html"); - Nodes bomCoordinatesNodes = document.query("//p[@class='bom-coordinates']"); - assertThat(bomCoordinatesNodes).hasSize(1); - Assert.assertEquals( - "BOM: com.google.cloud:libraries-bom:1.0.0", bomCoordinatesNodes.get(0).getValue()); - } - - @Test - public void testBomCoordinatesInUnstableArtifacts() throws IOException, ParsingException { - Document document = parseOutputFile("unstable_artifacts.html"); - Nodes bomCoordinatesNodes = document.query("//p[@class='bom-coordinates']"); - assertThat(bomCoordinatesNodes).hasSize(1); - Assert.assertEquals( - "BOM: com.google.cloud:libraries-bom:1.0.0", bomCoordinatesNodes.get(0).getValue()); - } - - @Test - public void testDependencyTrees() throws IOException, ParsingException { - Document document = parseOutputFile("dependency_trees.html"); - Nodes dependencyTreeParagraph = document.query("//p[@class='dependency-tree-node']"); - - // characterization test - assertThat(dependencyTreeParagraph).hasSize(39649); - Assert.assertEquals( - "com.google.protobuf:protobuf-java:jar:3.6.1", dependencyTreeParagraph.get(0).getValue()); - } - - @Test - public void testOutputDirectory() { - Assert.assertTrue( - "The dashboard should be created at target/com.google.cloud/libraries-bom/1.0.0", - outputDirectory.endsWith( - Paths.get("target", "com.google.cloud", "libraries-bom", "1.0.0"))); - } -} diff --git a/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/DashboardUnavailableArtifactTest.java b/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/DashboardUnavailableArtifactTest.java deleted file mode 100644 index 1d8f8998bf..0000000000 --- a/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/DashboardUnavailableArtifactTest.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * 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 - * - * 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.tools.opensource.dashboard; - -import com.google.cloud.tools.opensource.classpath.AnnotatedClassPath; -import com.google.cloud.tools.opensource.classpath.ClassPathResult; -import com.google.cloud.tools.opensource.dependencies.Artifacts; -import com.google.cloud.tools.opensource.dependencies.Bom; -import com.google.cloud.tools.opensource.dependencies.DependencyGraph; -import com.google.cloud.tools.opensource.dependencies.DependencyGraphBuilder; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.io.MoreFiles; -import com.google.common.io.RecursiveDeleteOption; -import com.google.common.truth.Truth; -import freemarker.template.Configuration; -import freemarker.template.TemplateException; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import nu.xom.Builder; -import nu.xom.Document; -import nu.xom.Element; -import nu.xom.Nodes; -import nu.xom.ParsingException; -import org.eclipse.aether.RepositoryException; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.graph.Dependency; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -public class DashboardUnavailableArtifactTest { - - private static Path outputDirectory; - private Bom bom = new Bom("test:test:1.2.4", null); - private Builder builder = new Builder(); - - @BeforeClass - public static void setUp() throws IOException { - outputDirectory = Files.createDirectories(Paths.get("target", "dashboard")); - } - - @AfterClass - public static void cleanUp() throws IOException { - // Mac's APFS fails with InsecureRecursiveDeleteException without ALLOW_INSECURE. - // Still safe as this test does not use symbolic links - MoreFiles.deleteRecursively(outputDirectory, RecursiveDeleteOption.ALLOW_INSECURE); - } - - @Test - public void testDashboardForRepositoryException() throws TemplateException { - Configuration configuration = DashboardMain.configureFreemarker(); - Artifact validArtifact = new DefaultArtifact("io.grpc:grpc-context:1.15.0"); - Artifact nonExistentArtifact = new DefaultArtifact("io.grpc:nonexistent:jar:1.15.0"); - DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(); - Map map = new LinkedHashMap<>(); - DependencyGraph graph1 = - graphBuilder.buildMavenDependencyGraph(new Dependency(validArtifact, "compile")); - DependencyGraph graph2 = - graphBuilder.buildMavenDependencyGraph(new Dependency(nonExistentArtifact, "compile")); - map.put(validArtifact, new ArtifactInfo(graph1, graph2)); - map.put(nonExistentArtifact, new ArtifactInfo(new RepositoryException("foo"))); - - ArtifactCache cache = new ArtifactCache(); - cache.setInfoMap(map); - List artifactResults = - DashboardMain.generateReports( - configuration, - outputDirectory, - cache, - ImmutableMap.of(), - new ClassPathResult(new AnnotatedClassPath(), ImmutableList.of()), - bom); - - Assert.assertEquals( - "The length of the ArtifactResults should match the length of artifacts", - 2, - artifactResults.size()); - Assert.assertEquals( - "The first artifact result should be valid", - true, - artifactResults.get(0).getResult(DashboardMain.TEST_NAME_UPPER_BOUND)); - ArtifactResults errorArtifactResult = artifactResults.get(1); - Assert.assertNull( - "The second artifact result should be null", - errorArtifactResult.getResult(DashboardMain.TEST_NAME_UPPER_BOUND)); - Assert.assertEquals( - "The error artifact result should contain error message", - "foo", - errorArtifactResult.getExceptionMessage()); - } - - @Test - public void testDashboardWithRepositoryException() - throws IOException, TemplateException, ParsingException { - Configuration configuration = DashboardMain.configureFreemarker(); - - Artifact validArtifact = new DefaultArtifact("io.grpc:grpc-context:1.15.0"); - ArtifactResults validArtifactResult = new ArtifactResults(validArtifact); - validArtifactResult.addResult(DashboardMain.TEST_NAME_UPPER_BOUND, 0); - validArtifactResult.addResult(DashboardMain.TEST_NAME_DEPENDENCY_CONVERGENCE, 0); - validArtifactResult.addResult(DashboardMain.TEST_NAME_GLOBAL_UPPER_BOUND, 0); - - Artifact invalidArtifact = new DefaultArtifact("io.grpc:nonexistent:jar:1.15.0"); - ArtifactResults errorArtifactResult = new ArtifactResults(invalidArtifact); - errorArtifactResult.setExceptionMessage( - "Could not find artifact io.grpc:nonexistent:jar:1.15.0 in central" - + " (https://repo1.maven.org/maven2/)"); - - List table = new ArrayList<>(); - table.add(validArtifactResult); - table.add(errorArtifactResult); - - DashboardMain.generateDashboard( - configuration, - outputDirectory, - table, - ImmutableList.of(), - ImmutableMap.of(), - new ClassPathResult(new AnnotatedClassPath(), ImmutableList.of()), - bom); - - Path generatedHtml = outputDirectory.resolve("artifact_details.html"); - Assert.assertTrue(Files.isRegularFile(generatedHtml)); - Document document = builder.build(generatedHtml.toFile()); - Assert.assertEquals("en-US", document.getRootElement().getAttribute("lang").getValue()); - Nodes tr = document.query("//tr"); - - Assert.assertEquals( - "The size of rows in table should match the number of artifacts + 1 (header)", - tr.size(),table.size() + 1); - - Nodes tdForValidArtifact = tr.get(1).query("td"); - Assert.assertEquals( - Artifacts.toCoordinates(validArtifact), tdForValidArtifact.get(0).getValue()); - Element firstResult = (Element) (tdForValidArtifact.get(2)); - Truth.assertThat(firstResult.getValue().trim()).isEqualTo("PASS"); - Truth.assertThat(firstResult.getAttributeValue("class")).isEqualTo("pass"); - - Nodes tdForErrorArtifact = tr.get(2).query("td"); - Assert.assertEquals( - Artifacts.toCoordinates(invalidArtifact), tdForErrorArtifact.get(0).getValue()); - Element secondResult = (Element) (tdForErrorArtifact.get(2)); - Truth.assertThat(secondResult.getValue().trim()).isEqualTo("UNAVAILABLE"); - Truth.assertThat(secondResult.getAttributeValue("class")).isEqualTo("unavailable"); - } -} diff --git a/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/FreemarkerTest.java b/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/FreemarkerTest.java deleted file mode 100644 index a499fa0552..0000000000 --- a/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/FreemarkerTest.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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.tools.opensource.dashboard; - -import com.google.cloud.tools.opensource.classpath.AnnotatedClassPath; -import com.google.cloud.tools.opensource.classpath.ClassFile; -import com.google.cloud.tools.opensource.classpath.ClassNotFoundProblem; -import com.google.cloud.tools.opensource.classpath.ClassPathEntry; -import com.google.cloud.tools.opensource.classpath.ClassPathResult; -import com.google.cloud.tools.opensource.classpath.ClassSymbol; -import com.google.cloud.tools.opensource.classpath.LinkageProblem; -import com.google.cloud.tools.opensource.dependencies.Bom; -import com.google.cloud.tools.opensource.dependencies.DependencyGraph; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.io.MoreFiles; -import com.google.common.io.RecursiveDeleteOption; -import com.google.common.truth.Truth; -import freemarker.template.Configuration; -import freemarker.template.TemplateException; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; -import nu.xom.Builder; -import nu.xom.Document; -import nu.xom.Node; -import nu.xom.Nodes; -import nu.xom.ParsingException; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.artifact.DefaultArtifact; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -/** - * Unit tests for FreeMarker logic without reading any JAR files. - */ -public class FreemarkerTest { - - private static Path outputDirectory; - private static ImmutableMap> symbolProblemTable; - - private Builder builder = new Builder(); - - @BeforeClass - public static void setUpDirectory() throws IOException { - outputDirectory = Files.createDirectories(Paths.get("target", "dashboard")); - } - - @Before - public void setUp() { - Artifact artifact = new DefaultArtifact("com.google:foo:1.0.0") - .setFile(new File("foo/bar-1.2.3.jar")); - ClassPathEntry entry = new ClassPathEntry(artifact); - ImmutableSet dummyProblems = - ImmutableSet.of( - new ClassNotFoundProblem( - new ClassFile(entry, "abc.def.G"), new ClassSymbol("com.foo.Bar"))); - symbolProblemTable = ImmutableMap.of(entry, dummyProblems); - } - - @AfterClass - public static void cleanUp() throws IOException { - // Mac's APFS fails with InsecureRecursiveDeleteException without ALLOW_INSECURE. - // Still safe as this test does not use symbolic links - MoreFiles.deleteRecursively(outputDirectory, RecursiveDeleteOption.ALLOW_INSECURE); - } - - @Test - public void testCountFailures() throws IOException, TemplateException, ParsingException { - Configuration configuration = DashboardMain.configureFreemarker(); - - Artifact artifact1 = new DefaultArtifact("io.grpc:grpc-context:1.15.0"); - ArtifactResults results1 = new ArtifactResults(artifact1); - results1.addResult("Linkage Errors", 56); - - Artifact artifact2 = new DefaultArtifact("grpc:grpc:1.15.0"); - ArtifactResults results2 = new ArtifactResults(artifact2); - results2.addResult("Linkage Errors", 0); - - List table = ImmutableList.of(results1, results2); - List globalDependencies = ImmutableList.of(); - DashboardMain.generateDashboard( - configuration, - outputDirectory, - table, - globalDependencies, - symbolProblemTable, - new ClassPathResult(new AnnotatedClassPath(), ImmutableList.of()), - new Bom("mock:artifact:1.6.7", null)); - - Path dashboardHtml = outputDirectory.resolve("index.html"); - Assert.assertTrue(Files.isRegularFile(dashboardHtml)); - Document document = builder.build(dashboardHtml.toFile()); - - // xom's query cannot specify partial class field, e.g., 'statistic-item' - Nodes counts = document.query("//div[@class='container']/div/h2"); - Assert.assertTrue(counts.size() > 0); - for (int i = 0; i < counts.size(); i++) { - Integer.parseInt(counts.get(i).getValue().trim()); - } - // Linkage Errors - Truth.assertThat(counts.get(1).getValue().trim()).isEqualTo("1"); - } - - @Test - public void testVersionIndex() - throws IOException, TemplateException, URISyntaxException, ParsingException { - Path output = - DashboardMain.generateVersionIndex( - "com.google.cloud", - "libraries-bom", - ImmutableList.of("1.0.0", "2.0.0", "2.1.0-SNAPSHOT")); - Assert.assertTrue( - output.endsWith(Paths.get("target", "com.google.cloud", "libraries-bom", "index.html"))); - Assert.assertTrue(Files.isRegularFile(output)); - - Document document = builder.build(output.toFile()); - Nodes links = document.query("//a/@href"); - Assert.assertEquals(3, links.size()); - Node snapshotLink = links.get(2); - // 2.1.0-SNAPSHOT has directory 'snapshot' - Assert.assertEquals("snapshot/index.html", snapshotLink.getValue()); - } -} diff --git a/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/PieChartTest.java b/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/PieChartTest.java deleted file mode 100644 index 177f4243c9..0000000000 --- a/dashboard/src/test/java/com/google/cloud/tools/opensource/dashboard/PieChartTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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.tools.opensource.dashboard; - -import java.awt.geom.Point2D; -import org.junit.Assert; -import org.junit.Test; - -public class PieChartTest { - - private static final double TOLERANCE = 0.0001; - - @Test - public void testRightAngle() { - Point2D actual = PieChart.calculateEndPoint(100, 100, 100, .25); - Point2D expected = new Point2D.Double(200, 100); - Assert.assertEquals(expected.getX(), actual.getX(), TOLERANCE); - Assert.assertEquals(expected.getY(), actual.getY(), TOLERANCE); - } - - @Test - public void testZero() { - Point2D actual = PieChart.calculateEndPoint(100, 100, 100, 0); - Point2D expected = new Point2D.Double(100, 0); - Assert.assertEquals(expected.getX(), actual.getX(), TOLERANCE); - Assert.assertEquals(expected.getY(), actual.getY(), TOLERANCE); - } - - @Test - public void testOneEighth() { - int radius = 100; - double ratio = 1.0/8.0; - Point2D actual = PieChart.calculateEndPoint(radius, 100, 100, ratio); - Point2D expected = new Point2D.Double(100 + 100 / Math.sqrt(2), 100 - 100 / Math.sqrt(2)); - Assert.assertEquals(expected.getX(), actual.getX(), TOLERANCE); - Assert.assertEquals(expected.getY(), actual.getY(), TOLERANCE); - } - - @Test - public void testHalf() { - Point2D actual = PieChart.calculateEndPoint(100, 100, 100, 0.5); - Point2D expected = new Point2D.Double(100, 200); - Assert.assertEquals(expected.getX(), actual.getX(), TOLERANCE); - Assert.assertEquals(expected.getY(), actual.getY(), TOLERANCE); - } - - @Test - public void testOffCenter() { - Point2D actual = PieChart.calculateEndPoint(150, 150, 100, 0.5); - Point2D expected = new Point2D.Double(150, 250); - Assert.assertEquals(expected.getX(), actual.getX(), TOLERANCE); - Assert.assertEquals(expected.getY(), actual.getY(), TOLERANCE); - } - - @Test - public void testFull() { - Point2D actual = PieChart.calculateEndPoint(100, 100, 100, 1.0); - Point2D expected = new Point2D.Double(100, 0); - Assert.assertEquals(expected.getX(), actual.getX(), TOLERANCE); - Assert.assertEquals(expected.getY(), actual.getY(), TOLERANCE); - } - - @Test - public void testMoreThanFull() { - Point2D actual = PieChart.calculateEndPoint(100, 100, 100, 5.5); - Point2D expected = new Point2D.Double(100, 0); - Assert.assertEquals(expected.getX(), actual.getX(), TOLERANCE); - Assert.assertEquals(expected.getY(), actual.getY(), TOLERANCE); - } - -} - - - diff --git a/dependencies/pom.xml b/dependencies/pom.xml index 2296ec7d84..69bd85b9af 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -150,23 +150,5 @@ - - java8-incompatible-reference-check - - - - org.codehaus.mojo - exec-maven-plugin - - false - com.google.cloud.tools.opensource.dependencies.Java8IncompatibleReferenceCheck - - ../boms/cloud-oss-bom/pom.xml - - - - - - diff --git a/enforcer-rules/pom.xml b/enforcer-rules/pom.xml index af2abf7020..6f4147ac24 100644 --- a/enforcer-rules/pom.xml +++ b/enforcer-rules/pom.xml @@ -145,24 +145,38 @@ - - maven-invoker-plugin - 3.2.2 - - ${project.build.directory}/it - ${project.build.directory}/local-repo - verify - - - - integration-test - - install - run - - - - + + + invoker-integration-test + + + !performRelease + + + + + + maven-invoker-plugin + 3.2.2 + + ${project.build.directory}/it + ${project.build.directory}/local-repo + verify + + + + integration-test + + install + run + + + + + + + + diff --git a/gradle-plugin/build.gradle b/gradle-plugin/build.gradle index 2e53631137..d921ff18da 100644 --- a/gradle-plugin/build.gradle +++ b/gradle-plugin/build.gradle @@ -27,7 +27,7 @@ group = 'com.google.cloud.tools' sourceCompatibility = 1.8 -version = '1.5.15' // {x-version-update:dependencies:current} +version = '1.5.16-SNAPSHOT' // {x-version-update:dependencies:current} dependencies { implementation "com.google.cloud.tools:dependencies:$version" diff --git a/kokoro/ubuntu/java8-incompatible-reference-check.sh b/kokoro/ubuntu/java8-incompatible-reference-check.sh deleted file mode 100644 index f2bd70480c..0000000000 --- a/kokoro/ubuntu/java8-incompatible-reference-check.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# Fail on any error. -set -e -# Display commands being run. -set -x - -cd github/cloud-opensource-java/dependencies -mvn -V -B clean install - -mvn exec:java -e -Pjava8-incompatible-reference-check \ No newline at end of file diff --git a/kokoro/ubuntu/periodic.cfg b/kokoro/ubuntu/periodic.cfg deleted file mode 100644 index cf6d39fd94..0000000000 --- a/kokoro/ubuntu/periodic.cfg +++ /dev/null @@ -1,13 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Location of the periodic build bash script in git. -build_file: "cloud-opensource-java/kokoro/ubuntu/periodic.sh" - -timeout_mins: 240 - -action { - define_artifacts { - regex: "**/target/com.google.cloud/**" - strip_prefix: "github/cloud-opensource-java/dashboard/target" - } -} diff --git a/kokoro/ubuntu/periodic.sh b/kokoro/ubuntu/periodic.sh deleted file mode 100755 index c7f5d71901..0000000000 --- a/kokoro/ubuntu/periodic.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -# Fail on any error. -set -e -# Display commands being run. -set -x - -cd github/cloud-opensource-java -# No need to run tests -./mvnw -V -B -ntp clean install -DskipTests -Denforcer.skip -Dinvoker.skip - -# Running target of dashboard submodule -# https://stackoverflow.com/questions/3459928/running-a-specific-maven-plugin-goal-from-the-command-line-in-a-sub-module-of-a/26448447#26448447 -# https://stackoverflow.com/questions/11091311/maven-execjava-goal-on-a-multi-module-project -cd dashboard - -# For all versions available in Maven Central and local repository -../mvnw -V -B -ntp exec:java -Dexec.mainClass="com.google.cloud.tools.opensource.dashboard.DashboardMain" \ - -Dexec.arguments="-a com.google.cloud:libraries-bom" - -../mvnw -V -B -ntp exec:java -Dexec.mainClass="com.google.cloud.tools.opensource.dashboard.DashboardMain" \ - -Dexec.arguments="-a com.google.cloud:gcp-lts-bom" diff --git a/pom.xml b/pom.xml index 25a32f6222..215bbe8486 100644 --- a/pom.xml +++ b/pom.xml @@ -54,11 +54,8 @@ - boms dependencies - dashboard enforcer-rules - linkage-monitor