com.microsoft.azure.sdk.build.tool.DependencyCheckerTool Maven / Gradle / Ivy
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.microsoft.azure.sdk.build.tool;
import com.microsoft.azure.sdk.build.tool.models.BuildErrorCode;
import com.microsoft.azure.sdk.build.tool.models.OutdatedDependency;
import com.microsoft.azure.sdk.build.tool.mojo.AzureSdkMojo;
import com.microsoft.azure.sdk.build.tool.util.MavenUtils;
import com.microsoft.azure.sdk.build.tool.util.logging.Logger;
import com.microsoft.azure.sdk.build.tool.util.MojoUtils;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.InputLocation;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* Performs the following tasks:
*
*
* - Warnings about missing BOM.
* - Warnings about not using the latest available version of BOM.
* - Warnings about explicit dependency versions.
* - Warnings about dependency clashes between Azure libraries and other dependencies.
* - Warnings about using track one libraries.
* - Warnings about out of date track two dependencies (BOM and individual libraries).
*
*/
public class DependencyCheckerTool implements Runnable {
private static final Logger LOGGER = Logger.getInstance();
private static final String AZURE_SDK_BOM_ARTIFACT_ID = "azure-sdk-bom";
private static final String COM_MICROSOFT_AZURE_GROUP_ID = "com.microsoft.azure";
/**
* Runs the dependency checker tool.
*/
public void run() {
LOGGER.info("Running Dependency Checker Tool");
checkForBom();
checkForAzureSdkTrackOneDependencies();
}
private void checkForBom() {
// we are looking for the azure-sdk-bom artifact ID listed as a dependency in the dependency management section
DependencyManagement depMgmt = AzureSdkMojo.getMojo().getProject().getDependencyManagement();
DependencyManagement originalDepMgmt =
AzureSdkMojo.getMojo().getProject().getOriginalModel().getDependencyManagement();
Optional bomDependency = Optional.empty();
Optional originalBomDependency = Optional.empty();
if (depMgmt != null) {
bomDependency = depMgmt.getDependencies().stream()
.filter(d -> d.getArtifactId().equals(AZURE_SDK_BOM_ARTIFACT_ID))
.findAny();
}
if (originalDepMgmt != null) {
originalBomDependency = originalDepMgmt.getDependencies().stream()
.filter(d -> d.getArtifactId().equals(AZURE_SDK_BOM_ARTIFACT_ID))
.findAny();
}
bomDependency = bomDependency.isPresent() ? bomDependency : originalBomDependency;
if (bomDependency.isPresent()) {
String latestAvailableBomVersion = MavenUtils.getLatestArtifactVersion("com.azure", "azure-sdk-bom");
String usedBomVersion = bomDependency.get().getVersion();
if (usedBomVersion.startsWith("${")) {
String propertyName = usedBomVersion.substring(2, usedBomVersion.indexOf("}"));
AzureSdkMojo.getMojo().getLog().info("BOM Version property name " + propertyName);
usedBomVersion = AzureSdkMojo.getMojo().getProject().getProperties().getProperty(propertyName);
}
boolean isLatestBomVersion = usedBomVersion.equals(latestAvailableBomVersion);
if (!isLatestBomVersion) {
MojoUtils.failOrWarn(AzureSdkMojo.getMojo()::isValidateLatestBomVersionUsed, BuildErrorCode.OUTDATED_DEPENDENCY, MojoUtils.getString("outdatedBomDependency") + " using"
+ " version" + usedBomVersion + " latest version: " + latestAvailableBomVersion, Arrays.asList(MavenUtils.toGAV(bomDependency.get())));
}
checkForAzureSdkDependencyVersions();
AzureSdkMojo.getMojo().getReport().setBomVersion(usedBomVersion);
} else {
MojoUtils.failOrWarn(AzureSdkMojo.getMojo()::isValidateAzureSdkBomUsed, BuildErrorCode.BOM_NOT_USED, MojoUtils.getString("missingBomDependency"));
}
}
private void checkForAzureSdkDependencyVersions() {
List dependencies = AzureSdkMojo.getMojo().getProject().getDependencies();
List dependenciesWithOverriddenVersions = dependencies.stream()
.filter(dependency -> "com.azure".equals(dependency.getGroupId()))
.filter(dependency -> {
InputLocation location = dependency.getLocation("version");
// if the version is not coming from Azure SDK BOM, filter those dependencies
return !location.getSource().getModelId().startsWith("com.azure:azure-sdk-bom");
}).collect(Collectors.toList());
dependenciesWithOverriddenVersions.forEach(dependency -> MojoUtils.failOrWarn(AzureSdkMojo.getMojo()::isValidateBomVersionsAreUsed,
BuildErrorCode.BOM_VERSION_OVERRIDDEN, dependency.getArtifactId() + " " + MojoUtils.getString("overrideBomVersion"),
Arrays.asList(MavenUtils.toGAV(dependency))));
List betaDependencies = dependencies.stream()
.filter(dependency -> "com.azure".equals(dependency.getGroupId()))
.filter(dependency -> dependency.getVersion().contains("-beta"))
.collect(Collectors.toList());
betaDependencies.forEach(dependency -> MojoUtils.failOrWarn(AzureSdkMojo.getMojo()::isValidateNoBetaLibraryUsed, BuildErrorCode.BETA_DEPENDENCY_USED,
dependency.getArtifactId() + " " + MojoUtils.getString("betaDependencyUsed"),
Arrays.asList(MavenUtils.toGAV(dependency))));
}
private void checkForAzureSdkTrackOneDependencies() {
// Check direct dependencies first for any 'com.microsoft.azure' group IDs. These are under the users direct
// control, so they could try to upgrade to a newer 'com.azure' version instead.
List outdatedDirectDependencies = MojoUtils.getDirectDependencies().stream()
.filter(a -> COM_MICROSOFT_AZURE_GROUP_ID.equals(a.getGroupId()))
.map(AzureDependencyMapping::lookupReplacement)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
// check indirect dependencies too, but filter out any dependencies we've already discovered above
List outdatedTransitiveDependencies = MojoUtils.getAllDependencies().stream()
.filter(d -> COM_MICROSOFT_AZURE_GROUP_ID.equals(d.getGroupId()))
.map(AzureDependencyMapping::lookupReplacement)
.filter(Optional::isPresent)
.map(Optional::get)
.filter(d -> !outdatedDirectDependencies.contains(d))
.collect(Collectors.toList());
// The report is only concerned with GAV, so we simplify it here
AzureSdkMojo.getMojo().getReport().setOutdatedDirectDependencies(outdatedDirectDependencies);
AzureSdkMojo.getMojo().getReport().setOutdatedTransitiveDependencies(outdatedTransitiveDependencies);
if (!outdatedDirectDependencies.isEmpty()) {
// convert each track one dependency into actionable guidance
StringBuilder message = new StringBuilder(MojoUtils.getString("deprecatedDirectDependency"));
for (OutdatedDependency outdatedDependency : outdatedDirectDependencies) {
message.append("\n - ")
.append(outdatedDependency.getOutdatedDependency())
.append(" --> ")
.append(outdatedDependency.getSuggestedReplacements());
}
List outdatedDependencyGavs = outdatedDirectDependencies
.stream()
.map(OutdatedDependency::getOutdatedDependency)
.collect(Collectors.toList());
MojoUtils.failOrWarn(AzureSdkMojo.getMojo()::isValidateNoDeprecatedMicrosoftLibraryUsed, BuildErrorCode.DEPRECATED_DEPENDENCY_USED, message.toString(), outdatedDependencyGavs);
}
if (!outdatedTransitiveDependencies.isEmpty()) {
// convert each track one dependency into actionable guidance
StringBuilder message = new StringBuilder(MojoUtils.getString("deprecatedIndirectDependency"));
for (OutdatedDependency outdatedDependency : outdatedTransitiveDependencies) {
message.append("\n - ")
.append(outdatedDependency.getOutdatedDependency());
}
List outdatedTransitiveDependencyGavs = outdatedTransitiveDependencies
.stream()
.map(OutdatedDependency::getOutdatedDependency)
.collect(Collectors.toList());
MojoUtils.failOrWarn(AzureSdkMojo.getMojo()::isValidateNoDeprecatedMicrosoftLibraryUsed, BuildErrorCode.DEPRECATED_TRANSITIVE_DEPENDENCY, message.toString(), outdatedTransitiveDependencyGavs);
}
}
}