/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.gradle.plugins.baseline; import com.liferay.gradle.plugins.baseline.internal.util.GradleUtil; import com.liferay.gradle.util.Validator; import java.io.File; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import org.gradle.api.Action; import org.gradle.api.GradleException; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.artifacts.ComponentSelection; import org.gradle.api.artifacts.ComponentSelectionRules; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.ConfigurationContainer; import org.gradle.api.artifacts.DependencySet; import org.gradle.api.artifacts.ResolutionStrategy; import org.gradle.api.artifacts.component.ModuleComponentIdentifier; import org.gradle.api.file.FileCollection; import org.gradle.api.plugins.JavaBasePlugin; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.PluginContainer; import org.gradle.api.plugins.ReportingBasePlugin; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.TaskContainer; import org.gradle.api.tasks.bundling.AbstractArchiveTask; import org.gradle.api.tasks.bundling.Jar; import org.gradle.util.VersionNumber; /** * @author Andrea Di Giorgi */ public class BaselinePlugin implements Plugin<Project> { public static final String BASELINE_CONFIGURATION_NAME = "baseline"; public static final String BASELINE_TASK_NAME = "baseline"; public static final String EXTENSION_NAME = "baselineConfiguration"; @Override public void apply(Project project) { GradleUtil.applyPlugin(project, JavaPlugin.class); GradleUtil.applyPlugin(project, ReportingBasePlugin.class); final BaselineConfigurationExtension baselineConfigurationExtension = GradleUtil.addExtension( project, EXTENSION_NAME, BaselineConfigurationExtension.class); final Jar jar = (Jar)GradleUtil.getTask( project, JavaPlugin.JAR_TASK_NAME); final Configuration baselineConfiguration = _addConfigurationBaseline( jar); final BaselineTask baselineTask = _addTaskBaseline( jar, baselineConfigurationExtension); _configureTasksBaseline(project); project.afterEvaluate( new Action<Project>() { @Override public void execute(Project project) { _configureTaskBaseline( baselineTask, jar, baselineConfiguration, baselineConfigurationExtension); } }); } private Configuration _addConfigurationBaseline( final AbstractArchiveTask newJarTask) { Project project = newJarTask.getProject(); ConfigurationContainer configurationContainer = project.getConfigurations(); Configuration configuration = configurationContainer.maybeCreate( BASELINE_CONFIGURATION_NAME); configuration.defaultDependencies( new Action<DependencySet>() { @Override public void execute(DependencySet dependencySet) { _addDependenciesBaseline(newJarTask); } }); configuration.setDescription( "Configures the previous released version of this project for " + "baselining."); configuration.setVisible(false); ResolutionStrategy resolutionStrategy = configuration.getResolutionStrategy(); ComponentSelectionRules componentSelectionRules = resolutionStrategy.getComponentSelection(); componentSelectionRules.all( new Action<ComponentSelection>() { @Override public void execute(ComponentSelection componentSelection) { ModuleComponentIdentifier moduleComponentIdentifier = componentSelection.getCandidate(); String version = moduleComponentIdentifier.getVersion(); if (version.endsWith("-SNAPSHOT")) { componentSelection.reject("no snapshots are allowed"); } } }); resolutionStrategy.cacheChangingModulesFor(0, TimeUnit.SECONDS); resolutionStrategy.cacheDynamicVersionsFor(0, TimeUnit.SECONDS); return configuration; } private void _addDependenciesBaseline(AbstractArchiveTask newJarTask) { Project project = newJarTask.getProject(); GradleUtil.addDependency( project, BASELINE_CONFIGURATION_NAME, String.valueOf(project.getGroup()), newJarTask.getBaseName(), "(," + newJarTask.getVersion() + ")", false); } @SuppressWarnings("rawtypes") private BaselineTask _addTaskBaseline( final AbstractArchiveTask newJarTask, final BaselineConfigurationExtension baselineConfigurationExtension) { final Project project = newJarTask.getProject(); final BaselineTask baselineTask = GradleUtil.addTask( project, BASELINE_TASK_NAME, BaselineTask.class, true); baselineTask.doFirst( new Action<Task>() { @Override public void execute(Task task) { if (baselineConfigurationExtension.isAllowMavenLocal()) { return; } BaselineTask baselineTask = (BaselineTask)task; File oldJarFile = baselineTask.getOldJarFile(); if ((oldJarFile != null) && GradleUtil.isFromMavenLocal(project, oldJarFile)) { throw new GradleException( "Please delete " + oldJarFile.getParent() + " and try again"); } } }); File bndFile = project.file("bnd.bnd"); if (bndFile.exists()) { baselineTask.setBndFile(bndFile); } baselineTask.setDescription( "Compares the public API of this project with the public API of " + "the previous released version, if found."); baselineTask.setGroup(JavaBasePlugin.VERIFICATION_GROUP); baselineTask.setNewJarFile( new Callable<File>() { @Override public File call() throws Exception { return newJarTask.getArchivePath(); } }); baselineTask.setSourceDir( new Callable<File>() { @Override public File call() throws Exception { SourceSet sourceSet = GradleUtil.getSourceSet( project, SourceSet.MAIN_SOURCE_SET_NAME); return GradleUtil.getSrcDir(sourceSet.getResources()); } }); PluginContainer pluginContainer = project.getPlugins(); pluginContainer.withId( "biz.aQute.bnd.builder", new Action<Plugin>() { @Override public void execute(Plugin plugin) { _configureTaskBaselineForBndBuilderPlugin(baselineTask); } }); return baselineTask; } private void _configureTaskBaseline(BaselineTask baselineTask) { String ignoreFailures = GradleUtil.getTaskPrefixedProperty( baselineTask, "ignoreFailures"); if (Validator.isNotNull(ignoreFailures)) { baselineTask.setIgnoreFailures( Boolean.parseBoolean(ignoreFailures)); } } private void _configureTaskBaseline( BaselineTask baselineTask, final AbstractArchiveTask newJarTask, final FileCollection oldJarFileCollection, BaselineConfigurationExtension baselineConfigurationExtension) { VersionNumber lowestBaselineVersionNumber = VersionNumber.parse( baselineConfigurationExtension.getLowestBaselineVersion()); VersionNumber versionNumber = VersionNumber.parse( newJarTask.getVersion()); if (lowestBaselineVersionNumber.compareTo(versionNumber) >= 0) { baselineTask.setEnabled(false); return; } baselineTask.dependsOn(newJarTask); baselineTask.setOldJarFile( new Callable<File>() { @Override public File call() throws Exception { return oldJarFileCollection.getSingleFile(); } }); } private void _configureTaskBaselineForBndBuilderPlugin( BaselineTask baselineTask) { GradleUtil.setProperty(baselineTask, "bundleTask", null); } private void _configureTasksBaseline(Project project) { TaskContainer taskContainer = project.getTasks(); taskContainer.withType( BaselineTask.class, new Action<BaselineTask>() { @Override public void execute(BaselineTask baselineTask) { _configureTaskBaseline(baselineTask); } }); } }