netflix.nebula.dependency.recommender.DependencyRecommendationsPlugin Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nebula-dependency-recommender Show documentation
Show all versions of nebula-dependency-recommender Show documentation
Allows projects to leave off version numbers in dependencies section and have versions recommended by other sources
/*
* Copyright 2014-2017 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package netflix.nebula.dependency.recommender;
import com.netflix.nebula.dependencybase.DependencyBasePlugin;
import com.netflix.nebula.dependencybase.DependencyManagement;
import com.netflix.nebula.interop.ConfigurationsKt;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
import netflix.nebula.dependency.recommender.provider.RecommendationProviderContainer;
import netflix.nebula.dependency.recommender.provider.RecommendationResolver;
import netflix.nebula.dependency.recommender.publisher.MavenBomXmlGenerator;
import org.codehaus.groovy.runtime.MethodClosure;
import org.gradle.api.Action;
import org.gradle.api.GradleException;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.*;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.plugins.ExtraPropertiesExtension;
import java.util.ArrayList;
import java.util.List;
public class DependencyRecommendationsPlugin implements Plugin {
public static final String NEBULA_RECOMMENDER_BOM = "nebulaRecommenderBom";
private Logger logger = Logging.getLogger(DependencyRecommendationsPlugin.class);
private DependencyManagement dependencyInsight;
private RecommendationProviderContainer recommendationProviderContainer;
@Override
public void apply(final Project project) {
project.getPlugins().apply(DependencyBasePlugin.class);
dependencyInsight = (DependencyManagement) project.getExtensions().getExtraProperties().get("nebulaDependencyBase");
project.getConfigurations().create(NEBULA_RECOMMENDER_BOM);
recommendationProviderContainer = project.getExtensions().create("dependencyRecommendations", RecommendationProviderContainer.class, project, dependencyInsight);
applyRecommendations(project);
enhanceDependenciesWithRecommender(project);
enhancePublicationsWithBomProducer(project);
}
private void applyRecommendations(final Project project) {
project.getConfigurations().all(new Action() {
@Override
public void execute(final Configuration conf) {
final RecommendationStrategyFactory rsFactory = new RecommendationStrategyFactory(project);
if (conf.getState() == Configuration.State.UNRESOLVED) {
ConfigurationsKt.onResolve(conf, new Function1() {
@Override
public Unit invoke(ResolvableDependencies resolvableDependencies) {
for (Dependency dependency : resolvableDependencies.getDependencies()) {
applyRecommendationToDependency(rsFactory, dependency, new ArrayList());
// if project dependency, pull all first orders and apply recommendations if missing dependency versions
// dependency.getProjectConfiguration().allDependencies iterate and inspect them as well
}
conf.getResolutionStrategy().eachDependency(new Action() {
@Override
public void execute(DependencyResolveDetails details) {
ModuleVersionSelector requested = details.getTarget();
// don't interfere with the way forces trump everything
for (ModuleVersionSelector force : conf.getResolutionStrategy().getForcedModules()) {
if (requested.getGroup().equals(force.getGroup()) && requested.getName().equals(force.getName())) {
return;
}
}
RecommendationStrategy strategy = rsFactory.getRecommendationStrategy();
if (strategy.canRecommendVersion(requested)) {
String version = getRecommendedVersionRecursive(project, requested);
if (strategy.recommendVersion(details, version)) {
String coordinate = requested.getGroup() + ":" + requested.getName();
dependencyInsight.addRecommendation(conf.getName(), coordinate, version, whichStrategy(strategy), "nebula.dependency-recommender");
logger.info("Recommending version " + version + " for dependency " + coordinate);
} else {
if (recommendationProviderContainer.isStrictMode()) {
String errorMessage = "Dependency " + details.getRequested().getGroup() + ":" + details.getRequested().getName() + " omitted version with no recommended version. General causes include a dependency being removed from the recommendation source or not applying a recommendation source to a project that depends on another project using a recommender.";
project.getLogger().error(errorMessage);
throw new GradleException(errorMessage);
}
}
}
}
});
return Unit.INSTANCE;
}
});
}
}
});
}
private void applyRecommendationToDependency(final RecommendationStrategyFactory factory, Dependency dependency, List visited) {
if (dependency instanceof ExternalModuleDependency) {
factory.getRecommendationStrategy().inspectDependency(dependency);
} else if (dependency instanceof ProjectDependency) {
ProjectDependency projectDependency = (ProjectDependency) dependency;
if (!visited.contains(projectDependency)) {
visited.add(projectDependency);
Configuration configuration;
try {
ProjectDependency.class.getMethod("getTargetConfiguration");
String targetConfiguration = projectDependency.getTargetConfiguration() == null ? Dependency.DEFAULT_CONFIGURATION : projectDependency.getTargetConfiguration();
configuration = projectDependency.getDependencyProject().getConfigurations().getByName(targetConfiguration);
} catch (NoSuchMethodException e) {
//noinspection deprecation
configuration = projectDependency.getProjectConfiguration();
}
DependencySet dependencies = configuration.getAllDependencies();
for (Dependency dep : dependencies) {
applyRecommendationToDependency(factory, dep, visited);
}
}
}
}
protected String whichStrategy(RecommendationStrategy strategy) {
if (strategy instanceof RecommendationsConflictResolvedStrategy) {
return "conflict resolution recommendation";
} else if (strategy instanceof RecommendationsOverrideTransitivesStrategy) {
return "override transitive recommendation";
} else {
return "nebula.dependency-recommender";
}
}
protected void enhanceDependenciesWithRecommender(Project project) {
RecommendationResolver resolver = new RecommendationResolver(project);
project.getExtensions().getByType(ExtraPropertiesExtension.class).set("recommend",
new MethodClosure(resolver, "recommend"));
}
protected void enhancePublicationsWithBomProducer(Project project) {
project.getExtensions().create("nebulaDependencyManagement", MavenBomXmlGenerator.class, project);
}
/**
* Look for recommended versions in a project and each of its ancestors in order until one is found or the root is reached
*
* @return the recommended version or null
*/
protected String getRecommendedVersionRecursive(Project project, ModuleVersionSelector mvSelector) {
String version = project.getExtensions().getByType(RecommendationProviderContainer.class)
.getRecommendedVersion(mvSelector.getGroup(), mvSelector.getName());
if (version != null)
return version;
if (project.getParent() != null)
return getRecommendedVersionRecursive(project.getParent(), mvSelector);
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy