All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ru.vyarus.gradle.plugin.animalsniffer.AnimalSnifferPlugin.groovy Maven / Gradle / Ivy

package ru.vyarus.gradle.plugin.animalsniffer

import groovy.transform.CompileStatic
import groovy.transform.Memoized
import groovy.transform.TypeCheckingMode
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.Dependency
import org.gradle.api.file.FileCollection
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.ReportingBasePlugin
import org.gradle.api.reporting.ReportingExtension
import org.gradle.api.specs.NotSpec
import org.gradle.api.tasks.SourceSet
import org.gradle.util.GradleVersion
import ru.vyarus.gradle.plugin.animalsniffer.signature.AnimalSnifferSignatureExtension
import ru.vyarus.gradle.plugin.animalsniffer.signature.BuildSignatureTask
import ru.vyarus.gradle.plugin.animalsniffer.util.ContainFilesSpec
import ru.vyarus.gradle.plugin.animalsniffer.util.ExcludeFilePatternSpec

/**
 * AnimalSniffer plugin. Implemented the same way as gradle quality plugins (checkstyle, pmd, findbugs):
 * main configuration 'animalsniffer' used to configure custom tasks, registered for each source set.
 * 

* Signatures are expected to be defined with 'signature' configuration. Multiple signatures may be set. * If no signatures defined - no check will be performed. *

* Reports configuration is performed with reports section. Only text report supported. All violations * are always printed to console. *

* To support signature configuration, plugin registered 'animalsnifferSignature' configuration. * If this configuration used then 'animalsnifferSignature' task will be registered to build signature file. * * @author Vyacheslav Rusakov * @since 13.12.2015 */ @CompileStatic class AnimalSnifferPlugin implements Plugin { public static final String SIGNATURE_CONF = 'signature' public static final String ANIMALSNIFFER_CACHE = 'animalsnifferCache' private static final String CHECK_SIGNATURE = 'animalsniffer' private static final String BUILD_SIGNATURE = 'animalsnifferSignature' private Project project private AnimalSnifferExtension extension private AnimalSnifferSignatureExtension buildExtension @Override void apply(Project project) { // activated only when java plugin is enabled project.plugins.withType(JavaPlugin) { this.project = project project.plugins.apply(ReportingBasePlugin) checkGradleCompatibility() registerConfigurations() registerExtensions() registerCheckTasks() registerBuildTasks() } } private void checkGradleCompatibility() { // due to base class refactor from groovy to java in gradle 2.14 // plugin can't be launched on prior gradle versions GradleVersion version = GradleVersion.current() if (version < GradleVersion.version('2.14')) { throw new GradleException('Animalsniffer plugin requires gradle 2.14 or above, ' + "but your gradle version is: $version.version. Use plugin version 1.0.1.") } } @CompileStatic(TypeCheckingMode.SKIP) private void registerConfigurations() { project.configurations.create(CHECK_SIGNATURE).with { visible = false transitive = true description = 'The AnimalSniffer libraries to be used for this project.' defaultDependencies { dependencies -> dependencies.add(this.project.dependencies .create("org.codehaus.mojo:animal-sniffer-ant-tasks:${this.extension.toolVersion}")) } } project.configurations.create(SIGNATURE_CONF).with { visible = false transitive = true description = 'AnimalSniffer signatures' } } @CompileStatic(TypeCheckingMode.SKIP) private void registerExtensions() { extension = project.extensions.create(CHECK_SIGNATURE, AnimalSnifferExtension, project) extension.conventionMapping.with { reportsDir = { project.extensions.getByType(ReportingExtension).file(CHECK_SIGNATURE) } sourceSets = { project.sourceSets } } buildExtension = project.extensions.create(BUILD_SIGNATURE, AnimalSnifferSignatureExtension) } @CompileStatic(TypeCheckingMode.SKIP) private void registerCheckTasks() { // create tasks for each source set project.sourceSets.all { SourceSet sourceSet -> AnimalSniffer task = project.tasks .create(sourceSet.getTaskName(CHECK_SIGNATURE, null), AnimalSniffer) task.description = "Run AnimalSniffer checks for ${sourceSet.name} classes" // task operates on classes instead of sources task.setSource(sourceSet.output) configureCheckTask(task, sourceSet) task.reports.all { report -> report.conventionMapping.with { enabled = { true } destination = { new File(extension.reportsDir, "${sourceSet.name}.${report.name}") } } } } // include required animalsniffer tasks in check lifecycle project.tasks.check.dependsOn { extension.sourceSets*.getTaskName(CHECK_SIGNATURE, null) } } @CompileStatic(TypeCheckingMode.SKIP) private void configureCheckTask(AnimalSniffer task, SourceSet sourceSet) { Configuration animalsnifferConfiguration = project.configurations[CHECK_SIGNATURE] // build special signature from provided signatures and all jars to be able to cache it // and perform much faster checks after the first run BuildSignatureTask signatureTask = project.tasks .create(sourceSet.getTaskName(ANIMALSNIFFER_CACHE, null), BuildSignatureTask) { // this special task can be skipped if animalsniffer check supposed to be skipped // note that task is still created because signatures could be registered dynamically onlyIf { !extension.signatures.empty && extension.cache.enabled } conventionMapping.with { animalsnifferClasspath = { animalsnifferConfiguration } signatures = { extension.signatures } files = { excludeJars(getClasspathWithoutModules(sourceSet)) } exclude = { extension.cache.exclude as Set } mergeSignatures = { extension.cache.mergeSignatures } } } task.dependsOn(sourceSet.classesTaskName) task.conventionMapping.with { classpath = { extension.cache.enabled ? getModulesFromClasspath(sourceSet) : excludeJars(sourceSet.compileClasspath) } animalsnifferSignatures = { extension.cache.enabled ? signatureTask.outputFiles : extension.signatures } animalsnifferClasspath = { animalsnifferConfiguration } sourcesDirs = { sourceSet.allJava } ignoreFailures = { extension.ignoreFailures } annotation = { extension.annotation } ignoreClasses = { extension.ignore } } project.afterEvaluate { if (extension.cache.enabled) { // dependency must not be added earlier to avoid cache task appearance in log task.dependsOn(signatureTask) } else { // cache task should be always registered to simplify usage, but, by default, it is not enabled and // it's better to remove it to avoid confusion (task will not appear in the tasks list) project.tasks.remove(signatureTask) } } } @CompileStatic(TypeCheckingMode.SKIP) private void registerBuildTasks() { project.afterEvaluate { // register build signature task if files specified for signature creation if (buildExtension.configured) { BuildSignatureTask task = project.tasks.create(BUILD_SIGNATURE, BuildSignatureTask) buildExtension.files.each { task.files(it) } buildExtension.signatures.each { task.signatures(it) } task.include = buildExtension.include task.exclude = buildExtension.exclude // project name by default to be compatible with maven artifacts task.outputName = buildExtension.outputName ?: project.name // for project signature use hardcoded 'signature' folder instead of task name task.outputDirectory = new File(project.buildDir, '/animalsniffer/signature/') } // defaults applied to all tasks (including manually created) project.tasks.withType(BuildSignatureTask) { BuildSignatureTask task -> if (task.animalsnifferClasspath == null) { task.animalsnifferClasspath = project.configurations[CHECK_SIGNATURE] } if (task.outputName == null) { task.outputName = task.name } } } } /** * In multi-module projects there is high probability that modules could change, so its safer to exclude them * from project specific signature to rebuild it less often (and speed up overall build time). * * @param sourceSet source set * @return source set classpath with excluded other module jars */ @Memoized @CompileStatic(TypeCheckingMode.SKIP) private FileCollection getClasspathWithoutModules(SourceSet sourceSet) { Set excludeJars = moduleJars if (excludeJars.empty) { return sourceSet.compileClasspath } sourceSet.compileClasspath.filter new NotSpec(new ContainFilesSpec(excludeJars)) } /** * As other module dependencies removed from project specific signature, they must be added to check task * classpath. * * @param sourceSet source set * @return file collection containing only module jars or null if no dependency on other modules */ @Memoized @CompileStatic(TypeCheckingMode.SKIP) private FileCollection getModulesFromClasspath(SourceSet sourceSet) { Set includeJars = moduleJars if (includeJars.empty) { return null } sourceSet.compileClasspath.filter new ContainFilesSpec(includeJars) } /** * @return list of all project modules jars as a set of patterns */ @Memoized private Set getModuleJars() { Set patterns = [] project.rootProject.allprojects.each { it.configurations.findByName(Dependency.DEFAULT_CONFIGURATION)?.allArtifacts?.each { patterns << it.file } } patterns } /** * Exclude some jars from the classpath. Required to support small 3rd party library signatures. * * @param classpath classpath file collection * @return filtered or original classpath if nothing configured to exclude */ private FileCollection excludeJars(FileCollection classpath) { return extension.excludeJars ? classpath.filter(new ExcludeFilePatternSpec(extension.excludeJars)) : classpath } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy