diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fe332c..004ea42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,8 @@ * Add new properties to AnimalSniffer task to simplify detailed configuration: - targetType: type of task (SourceSet, MultiplatformTarget, AndroidVariant) - targetName: name of target (used in animalsniffer task name) -* Call animalsniffer directly instead of ant tasks +* Call animalsniffer directly instead of ant tasks +* Configuration cache compatibility ### 1.7.2 (2024-11-18) * Update animalsniffer 1.23 -> 1.24 diff --git a/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/AnimalSnifferPlugin.groovy b/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/AnimalSnifferPlugin.groovy index 4ec99d7..e09f501 100644 --- a/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/AnimalSnifferPlugin.groovy +++ b/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/AnimalSnifferPlugin.groovy @@ -294,7 +294,7 @@ class AnimalSnifferPlugin implements Plugin { } checkTask.configure { // skip if no signatures configured or no sources to check - onlyIf { !getAnimalsnifferSignatures().empty && getSource().size() > 0 } + onlyIf { !it.getAnimalsnifferSignatures().empty && it.getSource().size() > 0 } conventionMapping.with { classpath = { extension.cache.enabled ? diff --git a/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/PrintAnimalsnifferSourceInfoTask.groovy b/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/PrintAnimalsnifferSourceInfoTask.groovy index c70e97b..41d2a37 100644 --- a/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/PrintAnimalsnifferSourceInfoTask.groovy +++ b/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/PrintAnimalsnifferSourceInfoTask.groovy @@ -4,6 +4,7 @@ import groovy.transform.CompileStatic import groovy.transform.TypeCheckingMode import org.gradle.api.DefaultTask import org.gradle.api.Project +import org.gradle.api.provider.Provider import org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskAction import org.gradle.work.DisableCachingByDefault @@ -57,9 +58,17 @@ class PrintAnimalsnifferSourceInfoTask extends DefaultTask { @Input boolean printClasspath = true + private final File rootProjectDir + private final Provider modelProvider + + PrintAnimalsnifferSourceInfoTask() { + rootProjectDir = project.rootProject.rootDir + modelProvider = project.provider { createModel(project, printClasspath) } + } + @TaskAction void action() { - DebugModel model = createModel() + DebugModel model = modelProvider.get() if (printPlugins) { println '\n\n== [Plugins] ===============================================================' @@ -68,27 +77,27 @@ class PrintAnimalsnifferSourceInfoTask extends DefaultTask { if (printCompileTasks) { println '\n\n== [Compile Tasks] ===============================================================' - printCompileTasks(project, model.compileTasks) + printCompileTasks(rootProjectDir, model.compileTasks) } if (printSourceSets) { println '\n\n== [SourceSets] ===============================================================' - printSourceSets(project, model) + printSourceSets(rootProjectDir, model) } if (printKotlinTargets && model.kotlinTargets) { - printTargets(project, model.kotlinTargets) + printTargets(rootProjectDir, model.kotlinTargets) } if (printAndroidVariants && model.androidVariants) { - printVariants(project, model.androidVariants) + printVariants(rootProjectDir, model.androidVariants) } println '\n\\===========================================================================================\n' } - private DebugModel createModel() { + static DebugModel createModel(Project project, boolean printClasspath) { DebugModel model = new DebugModel() model.plugins = new PluginsCollector().collect(project) @@ -134,7 +143,7 @@ class PrintAnimalsnifferSourceInfoTask extends DefaultTask { } @CompileStatic(TypeCheckingMode.SKIP) - private static void printCompileTasks(Project project, CompileTasksModel model) { + private static void printCompileTasks(File rootProjectDir, CompileTasksModel model) { println title(1, "Tasks containing 'compile' in name ------------------------------------ (${model.allTasks.size()})") println() @@ -154,7 +163,7 @@ class PrintAnimalsnifferSourceInfoTask extends DefaultTask { println title(1, "Java compile tasks --------------------------------------------- (${model.javaTasks.size()})") model.javaTasks.each { - printInOutClasspath(project, 2, "[${it.name}] -----", + printInOutClasspath(rootProjectDir, 2, "[${it.name}] -----", it.sourceDirs, it.classes, it.classpath @@ -166,7 +175,7 @@ class PrintAnimalsnifferSourceInfoTask extends DefaultTask { "Kotlin compile tasks ------------------------------------------ (${model.kotlinTasks.size()})") model.kotlinTasks.each { - printInOutClasspath(project, 2, "[${it.name}] -----", + printInOutClasspath(rootProjectDir, 2, "[${it.name}] -----", it.sourceDirs, it.classes, it.classpath @@ -196,32 +205,32 @@ class PrintAnimalsnifferSourceInfoTask extends DefaultTask { } } - private static void printSourceSets(Project project, DebugModel model) { + private static void printSourceSets(File rootProjectDir, DebugModel model) { if (model.java) { - printSourceSets(project, 1, + printSourceSets(rootProjectDir, 1, 'Java Source Sets -------------------------------------------------------', model.java) } if (model.kotlin) { - printSourceSets(project, 1, + printSourceSets(rootProjectDir, 1, 'Kotlin Multiplatform Source Sets -------------------------------------------------------', model.kotlin, model.kotlinTargetSourceSetsIndex) if (model.android) { - printKotlinDifference(project, 1, 'Android sources NOT COVERED by kotlin source sets', + printKotlinDifference(rootProjectDir, 1, 'Android sources NOT COVERED by kotlin source sets', model.android, model.kotlin) } } if (model.android) { - printSourceSets(project, 1, "Android ${model.androidLibrary ? 'library' : 'application'} " + + printSourceSets(rootProjectDir, 1, "Android ${model.androidLibrary ? 'library' : 'application'} " + 'Source Sets ------------------------------------------------------', model.android, model.androidVariantsSourceSetsIndex) if (model.kotlin) { - printKotlinDifference(project, 1, 'Kotlin sources NOT COVERED by android source sets', + printKotlinDifference(rootProjectDir, 1, 'Kotlin sources NOT COVERED by android source sets', model.kotlin, model.android) } } } - private static void printKotlinDifference(Project project, int shift, String msg, + private static void printKotlinDifference(File rootProjectDir, int shift, String msg, List koltin, List android) { Map kotlinIdx = [:] koltin.each { set -> set.sourceDirs.each { file -> kotlinIdx[file] = set.name } } @@ -236,25 +245,25 @@ class PrintAnimalsnifferSourceInfoTask extends DefaultTask { println title(shift, msg) notCoveredByKotlin.each { println String.format(buildPrefix(shift + 1) + '%-70s (%s)', - project.rootProject.relativePath(it), kotlinIdx[it]) + it.canonicalPath.replace(getRootPath(rootProjectDir), ''), kotlinIdx[it]) } } } - private static void printVariants(Project project, List info) { + private static void printVariants(File rootProjectDir, List info) { println title( "== [Android Variants] ========================================================== (${info.size()})") info.each { println title(1, "${it.name} ===== (compiled by ${it.compileTaskName} task)") - printSourceSets(project, 2, 'Source sets', it.sourceSets) + printSourceSets(rootProjectDir, 2, 'Source sets', it.sourceSets) // sources rendered above (level 1 because no title and actual level would be 2) - printInOutClasspath(project, 1, null, null, it.classes, it.classpath) + printInOutClasspath(rootProjectDir, 1, null, null, it.classes, it.classpath) } } - private static void printTargets(Project project, List targets) { + private static void printTargets(File rootProjectDir, List targets) { println title( "== [Kotlin targets] ========================================================= (${targets.size()})") @@ -265,11 +274,11 @@ class PrintAnimalsnifferSourceInfoTask extends DefaultTask { println title(2, "$it.name (compiled by $it.compileTaskName task)") if (it.sourceSets) { - printSourceSets(project, 3, 'Source sets', it.sourceSets) + printSourceSets(rootProjectDir, 3, 'Source sets', it.sourceSets) } // sources rendered above - printInOutClasspath(project, 2, null, null, it.classes, it.classpath) + printInOutClasspath(rootProjectDir, 2, null, null, it.classes, it.classpath) if (it.associatedCompilations) { println title(3, "Associated compilations (${it.associatedCompilations.size()})") @@ -281,12 +290,12 @@ class PrintAnimalsnifferSourceInfoTask extends DefaultTask { } } - private static void printSourceSets(Project project, int shift, String name, List info, + private static void printSourceSets(File rootProjectDir, int shift, String name, List info, Map inclusiveIndex = null) { println title(shift, "$name (${info.size()})") info.each { - printInOutClasspath(project, shift + 1, + printInOutClasspath(rootProjectDir, shift + 1, "$it.name -----" + (inclusiveIndex?.get(it.name) ? " (${inclusiveIndex.get(it.name)})" : ''), it.sourceDirs, it.classes, it.classpath @@ -295,7 +304,7 @@ class PrintAnimalsnifferSourceInfoTask extends DefaultTask { } @SuppressWarnings('ParameterCount') - private static void printInOutClasspath(Project project, + private static void printInOutClasspath(File rootProjectDir, int shift, String msg, Collection sources, @@ -308,21 +317,21 @@ class PrintAnimalsnifferSourceInfoTask extends DefaultTask { if (sources) { if (classes || classpath) { println title(shift + 1, 'Sources') - println renderSources(shift + 2, sources, project) + println renderSources(shift + 2, sources, rootProjectDir) } else { // short notion for kotlin and android source sets - println renderSources(shift + 1, sources, project) + println renderSources(shift + 1, sources, rootProjectDir) } } if (classes) { println title(shift + 1, 'Output') - println renderClasses(shift + 2, classes, project) + println renderClasses(shift + 2, classes, rootProjectDir) } if (classpath) { println title(shift + 1, 'Classpath') - println renderClasspath(project, shift + 2, classpath) + println renderClasspath(rootProjectDir, shift + 2, classpath) } } } diff --git a/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/PrintAnimalsnifferTasksTask.groovy b/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/PrintAnimalsnifferTasksTask.groovy index f5fb8a0..cc0cd4a 100644 --- a/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/PrintAnimalsnifferTasksTask.groovy +++ b/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/PrintAnimalsnifferTasksTask.groovy @@ -57,12 +57,14 @@ class PrintAnimalsnifferTasksTask extends DefaultTask { } println "\t\tdepends on: ${tasks.sort().join(', ')}" Set sigs = (sigTask?.signatures ?: task.animalsnifferSignatures).files + File rootDir = project.rootProject.rootDir println "\t\tsignatures: ${sigTask ? '(cached signature)' : ''}\n" + - (sigs.empty ? '\t\t\t' : PrintUtils.renderClasspath(project, 3, sigs)) + (sigs.empty ? '\t\t\t' + : PrintUtils.renderClasspath(rootDir, 3, sigs)) println '\t\tclasses:\n' + (task.classesDirs.empty ? '\t\t\t' : PrintUtils.renderClasses( - 3, task.classesDirs, project)) + 3, task.classesDirs, rootDir)) println '\t\tsources:\n' + PrintUtils.renderSources( - 3, task.sourcesDirs.files, project, true) + 3, task.sourcesDirs.files, rootDir, true) } println "\n*use [$PrintAnimalsnifferSourceInfoTask.NAME] task to see project sources configuration details\n" } diff --git a/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/collector/AndroidSourceSetsInfoCollector.groovy b/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/collector/AndroidSourceSetsInfoCollector.groovy index 52d5414..19ed939 100644 --- a/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/collector/AndroidSourceSetsInfoCollector.groovy +++ b/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/collector/AndroidSourceSetsInfoCollector.groovy @@ -24,13 +24,16 @@ class AndroidSourceSetsInfoCollector { new AndroidSourceSetReactor(project).onTarget { Set classpath = [] if (collectClasspath) { - Configuration configuration = project.configurations - .create("resolve$it.implementationConfigurationName") - // not resolvable configuration (need another configuration to resolve it) - configuration.extendsFrom(project.configurations.getByName(it.implementationConfigurationName)) - configuration.canBeResolved = true - configuration.attributes { - it.attributes.attribute(Attribute.of('ui', String), 'awt') + String resolveConfName = "resolve$it.implementationConfigurationName" + Configuration configuration = project.configurations.findByName(resolveConfName) + if (configuration == null) { + configuration = project.configurations.create(resolveConfName) + // not resolvable configuration (need another configuration to resolve it) + configuration.extendsFrom(project.configurations.getByName(it.implementationConfigurationName)) + configuration.canBeResolved = true + configuration.attributes { + it.attributes.attribute(Attribute.of('ui', String), 'awt') + } } classpath = PrintUtils.resolve(configuration, "for $it.name android source set") diff --git a/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/collector/MultiplatformSourceSetsInfoCollector.groovy b/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/collector/MultiplatformSourceSetsInfoCollector.groovy index af0bdcc..e83f068 100644 --- a/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/collector/MultiplatformSourceSetsInfoCollector.groovy +++ b/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/collector/MultiplatformSourceSetsInfoCollector.groovy @@ -38,12 +38,16 @@ class MultiplatformSourceSetsInfoCollector { Set cp = [] if (collectClasspath) { // using extra configuration to specify resolution attributes - Configuration configuration = project.configurations - .create("resolve$it.implementationConfigurationName") - configuration.extendsFrom(project.configurations.getByName(it.compileDependencyConfigurationName)) - configuration.canBeResolved = true - configuration.attributes { - attributes.attribute(Attribute.of('ui', String), 'awt') + String resolveConfName = "resolve$it.implementationConfigurationName" + Configuration configuration = project.configurations.findByName(resolveConfName) + if (configuration == null) { + configuration = project.configurations.create(resolveConfName) + configuration.extendsFrom(project.configurations + .getByName(it.compileDependencyConfigurationName)) + configuration.canBeResolved = true + configuration.attributes { + attributes.attribute(Attribute.of('ui', String), 'awt') + } } cp = PrintUtils.resolve(configuration, "for kotlin compilation $it.name") diff --git a/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/util/PrintUtils.groovy b/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/util/PrintUtils.groovy index 82d2af9..1d17904 100644 --- a/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/util/PrintUtils.groovy +++ b/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/debug/util/PrintUtils.groovy @@ -98,27 +98,29 @@ class PrintUtils { return NL + buildPrefix(shift) + title } - static String renderSources(int shift, Collection sourceDirs, Project project, boolean existsMarker = true) { + static String renderSources(int shift, Collection sourceDirs, File rootDir, + boolean existsMarker = true) { String prefix = buildPrefix(shift) return sourceDirs.collect { - String path = project.rootProject.relativePath(it) + String path = it.canonicalPath.replace(getRootPath(rootDir), '') it.exists() ? "$prefix$path" : String.format("$prefix%-80s %s", path, !existsMarker || it.exists() ? '' : 'NOT EXISTS') }.unique().sort().join(NL) } - static String renderClasses(int shift, Collection classDirs, Project project) { + static String renderClasses(int shift, Collection classDirs, File rootDir) { String prefix = buildPrefix(shift) return classDirs.collect { - prefix + project.rootProject.relativePath(it) + prefix + it.canonicalPath.replace(getRootPath(rootDir), '') }.unique().sort().join(NL) } - static String renderClasspath(Project project, int shift, Collection files) { + static String renderClasspath(File rootDir, int shift, Collection files) { String prefix = buildPrefix(shift) files.collect { - prefix + (it.canonicalPath.startsWith(project.rootDir.canonicalPath) - ? project.rootProject.relativePath(it) : it.name) + String rootPath = getRootPath(rootDir) + prefix + (it.canonicalPath.startsWith(rootPath) + ? it.canonicalPath.replace(rootPath, '') : it.name) }.sort().unique().join(NL) } @@ -128,6 +130,10 @@ class PrintUtils { return res } + static String getRootPath(File dir) { + return dir.canonicalPath + File.separator + } + @CompileStatic(TypeCheckingMode.SKIP) @SuppressWarnings(['CouldBeSwitchStatement', 'BlockEndsWithBlankLine']) private static Set resolveDependentTask(Project project, Task task, Object depends) { diff --git a/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/support/task/AndroidTaskConfigurationProvider.groovy b/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/support/task/AndroidTaskConfigurationProvider.groovy index e0fa7f3..449dc01 100644 --- a/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/support/task/AndroidTaskConfigurationProvider.groovy +++ b/src/main/groovy/ru/vyarus/gradle/plugin/animalsniffer/support/task/AndroidTaskConfigurationProvider.groovy @@ -21,7 +21,7 @@ class AndroidTaskConfigurationProvider implements AnimalsnifferTaskConfiguration private final String name private final String desc - private final TaskProvider classesTask + private final String classesTask private final Provider classes private final Provider classpath private final Provider sources @@ -31,7 +31,7 @@ class AndroidTaskConfigurationProvider implements AnimalsnifferTaskConfiguration TaskProvider classesTask) { name = variant.name desc = "for '$name' android ${name.containsIgnoreCase('test') ? 'test component' : 'variant'}" - this.classesTask = classesTask + this.classesTask = classesTask.name classes = providers.provider { objects.fileCollection().from(classesTask.flatMap { it.classesDirs }) } @@ -79,6 +79,6 @@ class AndroidTaskConfigurationProvider implements AnimalsnifferTaskConfiguration @Override String getCompileTaskName() { - return classesTask.name + return classesTask } } diff --git a/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamAndroidConfigurationCacheKitTest.groovy b/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamAndroidConfigurationCacheKitTest.groovy new file mode 100644 index 0000000..c57d01c --- /dev/null +++ b/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamAndroidConfigurationCacheKitTest.groovy @@ -0,0 +1,95 @@ +package ru.vyarus.gradle.plugin.animalsniffer.cache.configuration + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.TaskOutcome +import ru.vyarus.gradle.plugin.animalsniffer.UpstreamKitTest +import ru.vyarus.gradle.plugin.animalsniffer.android.AbstractAndroidKitTest +import spock.lang.IgnoreIf + +/** + * @author Vyacheslav Rusakov + * @since 12.12.2024 + */ +@IgnoreIf({ !jvm.java17Compatible }) +class UpstreamAndroidConfigurationCacheKitTest extends AbstractAndroidKitTest { + + def "Check configuration cache compatibility"() { + setup: + build """ + plugins { + id 'com.android.application' version '$UpstreamKitTest.ANDROID_PLUGIN_VERSION' + id 'org.jetbrains.kotlin.android' version '$UpstreamKitTest.KOTLIN_PLUGIN_VERSION' + id 'ru.vyarus.animalsniffer' + } + + animalsniffer { + ignoreFailures = true + } + + android { + compileSdk 33 + namespace 'com.example.namespace' + def javaVersion = JavaVersion.VERSION_17 + + defaultConfig { + minSdkVersion 21 + } + + lint { + checkReleaseBuilds false + abortOnError false + } + + compileOptions { + sourceCompatibility(javaVersion) + targetCompatibility(javaVersion) + } + + kotlinOptions { + jvmTarget = javaVersion.toString() + } + } + + repositories { mavenCentral(); google()} + dependencies { + signature 'org.codehaus.mojo.signature:java18:1.0@signature' + signature 'net.sf.androidscents.signature:android-api-level-21:5.0.1_r2@signature' + + implementation 'org.slf4j:slf4j-api:1.7.25' + } + + """ + + fileFromClasspath('src/main/java/invalid/Sample.java', '/ru/vyarus/gradle/plugin/animalsniffer/java/invalid/Sample.java') + fileFromClasspath('src/debug/java/invalid/Sample2.java', '/ru/vyarus/gradle/plugin/animalsniffer/java/invalid/Sample2.java') + generateManifest() + +// debug() + + when: "run task" + BuildResult result = runVer(UpstreamKitTest.GRADLE_VERSION, 'check', '--configuration-cache', '--configuration-cache-problems=warn') + + then: "no configuration cache incompatibilities" + result.output.contains("1 problem was found storing the configuration cache") + result.output.contains('Gradle runtime: support for using a Java agent with TestKit') + result.output.contains('Calculating task graph as no cached configuration is available for tasks:') + + then: "task successful" + result.task(':check').outcome == TaskOutcome.SUCCESS + result.task(':animalsnifferDebug').outcome == TaskOutcome.SUCCESS + result.task(':animalsnifferRelease').outcome == TaskOutcome.SUCCESS + + + when: "run from cache" + println '\n\n------------------- FROM CACHE ----------------------------------------' + result = runVer(UpstreamKitTest.GRADLE_VERSION, 'check', '--configuration-cache', '--configuration-cache-problems=warn') + + then: "cache used" + result.output.contains('Reusing configuration cache.') + +// then: "task successful" +// result.task(':check').outcome == TaskOutcome.SUCCESS +// result.task(':animalsnifferDebug').outcome == TaskOutcome.SUCCESS +// result.task(':animalsnifferRelease').outcome == TaskOutcome.SUCCESS + } +} diff --git a/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamAndroidMultiplatformConfigurationCacheKitTest.groovy b/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamAndroidMultiplatformConfigurationCacheKitTest.groovy new file mode 100644 index 0000000..6acb139 --- /dev/null +++ b/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamAndroidMultiplatformConfigurationCacheKitTest.groovy @@ -0,0 +1,99 @@ +package ru.vyarus.gradle.plugin.animalsniffer.cache.configuration + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.TaskOutcome +import ru.vyarus.gradle.plugin.animalsniffer.UpstreamKitTest +import ru.vyarus.gradle.plugin.animalsniffer.android.AbstractAndroidKitTest +import spock.lang.IgnoreIf + +/** + * @author Vyacheslav Rusakov + * @since 12.12.2024 + */ +@IgnoreIf({ !jvm.java17Compatible }) +class UpstreamAndroidMultiplatformConfigurationCacheKitTest extends AbstractAndroidKitTest { + + def "Check kotlin multiplatform android support"() { + setup: + build """ + import org.jetbrains.kotlin.gradle.dsl.JvmTarget + + plugins { + id 'org.jetbrains.kotlin.multiplatform' version '$UpstreamKitTest.KOTLIN_PLUGIN_VERSION' + id 'com.android.application' version '$UpstreamKitTest.ANDROID_PLUGIN_VERSION' + id 'ru.vyarus.animalsniffer' + } + + kotlin { + androidTarget { + compilerOptions { + jvmTarget = JvmTarget.JVM_11 + } + } + } + + android { + namespace = "org.example.project" + compileSdk = 33 + + defaultConfig { + applicationId = "org.example.project" + minSdk = 24 + targetSdk = 24 + versionCode = 1 + versionName = "1.0" + } + buildTypes { + getByName("release") { + minifyEnabled = false + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + lint { + quiet true + checkReleaseBuilds false + abortOnError false + } + } + + animalsniffer { + ignoreFailures = true + } + + repositories { mavenCentral(); google()} + dependencies { + signature 'org.codehaus.mojo.signature:java16-sun:1.0@signature' + + implementation 'org.slf4j:slf4j-api:1.7.25' + } + + """ + fileFromClasspath('src/androidMain/kotlin/invalid/Sample.kt', '/ru/vyarus/gradle/plugin/animalsniffer/kotlin/invalid/Sample.kt') + generateManifest('src/androidMain/') +// debug() + + when: "run task" + BuildResult result = runVer(UpstreamKitTest.GRADLE_VERSION, 'check', '--configuration-cache', '--configuration-cache-problems=warn') + + then: "no configuration cache incompatibilities" + result.output.contains("1 problem was found storing the configuration cache") + result.output.contains('Gradle runtime: support for using a Java agent with TestKit') + result.output.contains('Calculating task graph as no cached configuration is available for tasks:') + + then: "task successful" + result.task(':check').outcome == TaskOutcome.SUCCESS + + when: "run from cache" + println '\n\n------------------- FROM CACHE ----------------------------------------' + result = runVer(UpstreamKitTest.GRADLE_VERSION, 'check', '--configuration-cache', '--configuration-cache-problems=warn') + + then: "cache used" + result.output.contains('Reusing configuration cache.') + +// then: "task successful" +// result.task(':check').outcome == TaskOutcome.SUCCESS + } +} diff --git a/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamBuildSignatureConfigurationCacheKitTest.groovy b/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamBuildSignatureConfigurationCacheKitTest.groovy new file mode 100644 index 0000000..06522cd --- /dev/null +++ b/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamBuildSignatureConfigurationCacheKitTest.groovy @@ -0,0 +1,71 @@ +package ru.vyarus.gradle.plugin.animalsniffer.cache.configuration + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.TaskOutcome +import ru.vyarus.gradle.plugin.animalsniffer.AbstractKitTest +import ru.vyarus.gradle.plugin.animalsniffer.UpstreamKitTest +import ru.vyarus.gradle.plugin.animalsniffer.info.SignatureReader + +/** + * @author Vyacheslav Rusakov + * @since 12.12.2024 + */ +class UpstreamBuildSignatureConfigurationCacheKitTest extends AbstractKitTest { + + def "Check signature build from classes"() { + setup: + build """ + plugins { + id 'java' + id 'ru.vyarus.animalsniffer' + } + + animalsnifferSignature { + files sourceSets.main.output + } + + repositories { mavenCentral()} + dependencies { + implementation "org.codehaus.mojo:animal-sniffer-annotations:1.14" + implementation 'org.slf4j:slf4j-api:1.7.25' + } + """ + fileFromClasspath('src/main/java/ann/Sample.java', '/ru/vyarus/gradle/plugin/animalsniffer/java/ann/Sample.java') + fileFromClasspath('src/main/java/valid/Sample.java', '/ru/vyarus/gradle/plugin/animalsniffer/java/valid/Sample.java') +// debug() + + when: "run task" + BuildResult result = runVer(UpstreamKitTest.GRADLE_VERSION, 'animalsnifferSignature', '--configuration-cache', '--configuration-cache-problems=warn') + + then: "no configuration cache incompatibilities" + result.output.contains("1 problem was found storing the configuration cache") + result.output.contains('Gradle runtime: support for using a Java agent with TestKit') + result.output.contains('Calculating task graph as no cached configuration is available for tasks:') + + then: "task successful" + result.task(':animalsnifferSignature').outcome == TaskOutcome.SUCCESS + + then: "validate signature" + SignatureReader.readSignature(file("build/animalsniffer/signature/${projectName()}.sig")) == [ + 'ann.Sample', + 'valid.Sample' + ] + + when: "run from cache" + println '\n\n------------------- FROM CACHE ----------------------------------------' + result = runVer(UpstreamKitTest.GRADLE_VERSION, 'animalsnifferSignature', '--configuration-cache', '--configuration-cache-problems=warn') + + then: "cache used" + result.output.contains('Reusing configuration cache.') + +// then: "task successful" +// result.task(':animalsnifferSignature').outcome == TaskOutcome.SUCCESS +// +// then: "validate signature" +// SignatureReader.readSignature(file("build/animalsniffer/signature/${projectName()}.sig")) == [ +// 'ann.Sample', +// 'valid.Sample' +// ] + } + +} diff --git a/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamDebugOptionConfigurationCacheKitTest.groovy b/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamDebugOptionConfigurationCacheKitTest.groovy new file mode 100644 index 0000000..00483b3 --- /dev/null +++ b/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamDebugOptionConfigurationCacheKitTest.groovy @@ -0,0 +1,141 @@ +package ru.vyarus.gradle.plugin.animalsniffer.cache.configuration + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.TaskOutcome +import ru.vyarus.gradle.plugin.animalsniffer.UpstreamKitTest +import ru.vyarus.gradle.plugin.animalsniffer.android.AbstractAndroidKitTest +import spock.lang.IgnoreIf + +/** + * @author Vyacheslav Rusakov + * @since 12.12.2024 + */ +@IgnoreIf({ !jvm.java17Compatible }) +class UpstreamDebugOptionConfigurationCacheKitTest extends AbstractAndroidKitTest { + + def "Check configuration cache support"() { + + setup: + build """ + plugins { + id 'java' + id 'ru.vyarus.animalsniffer' + } + + animalsniffer { + debug = true + ignoreFailures = true + } + + repositories { mavenCentral()} + dependencies { + signature 'org.codehaus.mojo.signature:java16-sun:1.0@signature' + implementation 'org.slf4j:slf4j-api:1.7.25' + } + """ + + fileFromClasspath('src/main/java/invalid/Sample.java', '/ru/vyarus/gradle/plugin/animalsniffer/java/invalid/Sample.java') + //debug() + + when: "run task" + BuildResult result = runVer(UpstreamKitTest.GRADLE_VERSION, 'check', '--configuration-cache', '--configuration-cache-problems=warn') + + then: "no configuration cache incompatibilities" + result.output.contains("1 problem was found storing the configuration cache") + result.output.contains('Gradle runtime: support for using a Java agent with TestKit') + result.output.contains('Calculating task graph as no cached configuration is available for tasks:') + + then: "task successful" + result.task(':animalsnifferMain').outcome == TaskOutcome.SUCCESS + + when: "run from cache" + println '\n\n------------------- FROM CACHE ----------------------------------------' + result = runVer(UpstreamKitTest.GRADLE_VERSION, 'check', '--configuration-cache', '--configuration-cache-problems=warn') + + then: "cache used" + result.output.contains('Reusing configuration cache.') + +// then: "task successful" +// result.task(':animalsnifferMain').outcome == TaskOutcome.SUCCESS + } + + def "Check configuration cache compatibility"() { + setup: + build """ + plugins { + id 'com.android.application' version '$UpstreamKitTest.ANDROID_PLUGIN_VERSION' + id 'org.jetbrains.kotlin.android' version '$UpstreamKitTest.KOTLIN_PLUGIN_VERSION' + id 'ru.vyarus.animalsniffer' + } + + animalsniffer { + debug = true + ignoreFailures = true + } + + android { + compileSdk 33 + namespace 'com.example.namespace' + def javaVersion = JavaVersion.VERSION_17 + + defaultConfig { + minSdkVersion 21 + } + + lint { + checkReleaseBuilds false + abortOnError false + } + + compileOptions { + sourceCompatibility(javaVersion) + targetCompatibility(javaVersion) + } + + kotlinOptions { + jvmTarget = javaVersion.toString() + } + } + + repositories { mavenCentral(); google()} + dependencies { + signature 'org.codehaus.mojo.signature:java18:1.0@signature' + signature 'net.sf.androidscents.signature:android-api-level-21:5.0.1_r2@signature' + + implementation 'org.slf4j:slf4j-api:1.7.25' + } + + """ + + fileFromClasspath('src/main/java/invalid/Sample.java', '/ru/vyarus/gradle/plugin/animalsniffer/java/invalid/Sample.java') + fileFromClasspath('src/debug/java/invalid/Sample2.java', '/ru/vyarus/gradle/plugin/animalsniffer/java/invalid/Sample2.java') + generateManifest() + +// debug() + + when: "run task" + BuildResult result = runVer(UpstreamKitTest.GRADLE_VERSION, 'check', '--configuration-cache', '--configuration-cache-problems=warn') + + then: "no configuration cache incompatibilities" + result.output.contains("1 problem was found storing the configuration cache") + result.output.contains('Gradle runtime: support for using a Java agent with TestKit') + result.output.contains('Calculating task graph as no cached configuration is available for tasks:') + + then: "task successful" + result.task(':check').outcome == TaskOutcome.SUCCESS + result.task(':animalsnifferDebug').outcome == TaskOutcome.SUCCESS + result.task(':animalsnifferRelease').outcome == TaskOutcome.SUCCESS + + when: "run from cache" + println '\n\n------------------- FROM CACHE ----------------------------------------' + result = runVer(UpstreamKitTest.GRADLE_VERSION, 'check', '--configuration-cache', '--configuration-cache-problems=warn') + + then: "cache used" + result.output.contains('Reusing configuration cache.') + +// then: "task successful" +// result.task(':check').outcome == TaskOutcome.SUCCESS +// result.task(':animalsnifferDebug').outcome == TaskOutcome.SUCCESS +// result.task(':animalsnifferRelease').outcome == TaskOutcome.SUCCESS + } +} diff --git a/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamDebugTaskConfigurationCacheKitTest.groovy b/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamDebugTaskConfigurationCacheKitTest.groovy new file mode 100644 index 0000000..dd1401a --- /dev/null +++ b/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamDebugTaskConfigurationCacheKitTest.groovy @@ -0,0 +1,173 @@ +package ru.vyarus.gradle.plugin.animalsniffer.cache.configuration + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.TaskOutcome +import ru.vyarus.gradle.plugin.animalsniffer.UpstreamKitTest +import ru.vyarus.gradle.plugin.animalsniffer.debug.PrintAnimalsnifferSourceInfoTask +import ru.vyarus.gradle.plugin.animalsniffer.debug.task.AbstractDebugKitTest +import spock.lang.IgnoreIf + +/** + * @author Vyacheslav Rusakov + * @since 12.12.2024 + */ +@IgnoreIf({ !jvm.java17Compatible }) +class UpstreamDebugTaskConfigurationCacheKitTest extends AbstractDebugKitTest { + + def "Check simple java project debug"() { + setup: + build """ + plugins { + id 'java' + id 'ru.vyarus.animalsniffer' + } + + animalsniffer { + ignoreFailures = true + } + + repositories { mavenCentral()} + dependencies { + signature 'org.codehaus.mojo.signature:java16-sun:1.0@signature' + implementation localGroovy() + implementation 'org.slf4j:slf4j-api:1.7.25' + } + + """ + fileFromClasspath('src/main/java/invalid/Sample.java', '/ru/vyarus/gradle/plugin/animalsniffer/java/invalid/Sample.java') +// debug() + + when: "run task" + BuildResult result = runFailedVer(UpstreamKitTest.GRADLE_VERSION, PrintAnimalsnifferSourceInfoTask.NAME, '--configuration-cache') + + then: "task successful" + result.task(':' + PrintAnimalsnifferSourceInfoTask.NAME).outcome == TaskOutcome.SUCCESS + + then: "configuration cache ok" + // testKit is incompatible with configuration cache, but I can check number of errors! + result.output.contains('1 problem was found storing the configuration cache.') + result.output.contains('support for using a Java agent with TestKit builds is not yet implemented with the configuration cache') + } + + def "Check java android application debug support"() { + setup: + build """ + plugins { + id 'com.android.application' version '$UpstreamKitTest.ANDROID_PLUGIN_VERSION' + id 'ru.vyarus.animalsniffer' + } + + animalsniffer { + ignoreFailures = true + } + + android { + compileSdk 33 + namespace 'com.example.namespace' + def javaVersion = JavaVersion.VERSION_1_8 + + defaultConfig { + minSdkVersion 21 + } + + lint { + checkReleaseBuilds false + abortOnError false + } + + compileOptions { + sourceCompatibility(javaVersion) + targetCompatibility(javaVersion) + } + } + + repositories { mavenCentral(); google()} + dependencies { + signature 'org.codehaus.mojo.signature:java18:1.0@signature' + signature 'net.sf.androidscents.signature:android-api-level-21:5.0.1_r2@signature' + + implementation 'org.slf4j:slf4j-api:1.7.25' + } + + """ + + fileFromClasspath('src/main/java/invalid/Sample.java', '/ru/vyarus/gradle/plugin/animalsniffer/java/invalid/Sample.java') + generateManifest() +// debug() + + when: "run task" + BuildResult result = runVer(UpstreamKitTest.GRADLE_VERSION, PrintAnimalsnifferSourceInfoTask.NAME, '--configuration-cache', '--configuration-cache-problems=warn') + + then: "no configuration cache incompatibilities" + result.output.contains("1 problem was found storing the configuration cache") + result.output.contains('Gradle runtime: support for using a Java agent with TestKit') + result.output.contains('Calculating task graph as no cached configuration is available for tasks:') + + then: "task successful" + result.task(':' + PrintAnimalsnifferSourceInfoTask.NAME).outcome == TaskOutcome.SUCCESS + + when: "run from cache" + println '\n\n------------------- FROM CACHE ----------------------------------------' + result = runVer(UpstreamKitTest.GRADLE_VERSION, PrintAnimalsnifferSourceInfoTask.NAME, '--configuration-cache', '--configuration-cache-problems=warn') + + then: "cache used" + result.output.contains('Reusing configuration cache.') + +// then: "task successful" +// result.task(':' + PrintAnimalsnifferSourceInfoTask.NAME).outcome == TaskOutcome.SUCCESS + + } + + def "Check kotlin multiplatform jvm support"() { + setup: + build """ + plugins { + id 'org.jetbrains.kotlin.multiplatform' version '$UpstreamKitTest.KOTLIN_PLUGIN_VERSION' + id 'ru.vyarus.animalsniffer' + } + + kotlin { + jvm() + + sourceSets { + commonMain.dependencies { + implementation 'org.slf4j:slf4j-api:1.7.25' + } + } + } + + animalsniffer { + ignoreFailures = true + } + + repositories { mavenCentral()} + dependencies { + signature 'org.codehaus.mojo.signature:java16-sun:1.0@signature' + } + """ + fileFromClasspath('src/jvmMain/kotlin/invalid/Sample.kt', '/ru/vyarus/gradle/plugin/animalsniffer/kotlin/invalid/Sample.kt') +// debug() + + when: "run task" + BuildResult result = runVer(UpstreamKitTest.GRADLE_VERSION, PrintAnimalsnifferSourceInfoTask.NAME, '--configuration-cache', '--configuration-cache-problems=warn') + + then: "no configuration cache incompatibilities" + result.output.contains("1 problem was found storing the configuration cache") + result.output.contains('Gradle runtime: support for using a Java agent with TestKit') + result.output.contains('Calculating task graph as no cached configuration is available for tasks:') + + then: "task successful" + result.task(':' + PrintAnimalsnifferSourceInfoTask.NAME).outcome == TaskOutcome.SUCCESS + + + when: "run from cache" + println '\n\n------------------- FROM CACHE ----------------------------------------' + result = runVer(UpstreamKitTest.GRADLE_VERSION, PrintAnimalsnifferSourceInfoTask.NAME, '--configuration-cache', '--configuration-cache-problems=warn') + + then: "cache used" + result.output.contains('Reusing configuration cache.') + +// then: "task successful" +// result.task(':' + PrintAnimalsnifferSourceInfoTask.NAME).outcome == TaskOutcome.SUCCESS + } +} diff --git a/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamJavaConfigurationCacheKitTest.groovy b/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamJavaConfigurationCacheKitTest.groovy new file mode 100644 index 0000000..764c35a --- /dev/null +++ b/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreamJavaConfigurationCacheKitTest.groovy @@ -0,0 +1,59 @@ +package ru.vyarus.gradle.plugin.animalsniffer.cache.configuration + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.TaskOutcome +import ru.vyarus.gradle.plugin.animalsniffer.AbstractKitTest +import ru.vyarus.gradle.plugin.animalsniffer.UpstreamKitTest + +/** + * @author Vyacheslav Rusakov + * @since 12.12.2024 + */ +class UpstreamJavaConfigurationCacheKitTest extends AbstractKitTest { + + def "Check configuration cache support"() { + + setup: + build """ + plugins { + id 'java' + id 'ru.vyarus.animalsniffer' + } + + animalsniffer { + ignoreFailures = true + } + + repositories { mavenCentral()} + dependencies { + signature 'org.codehaus.mojo.signature:java16-sun:1.0@signature' + implementation 'org.slf4j:slf4j-api:1.7.25' + } + """ + + fileFromClasspath('src/main/java/invalid/Sample.java', '/ru/vyarus/gradle/plugin/animalsniffer/java/invalid/Sample.java') + //debug() + + when: "run task" + BuildResult result = runVer(UpstreamKitTest.GRADLE_VERSION, 'check', '--configuration-cache', '--configuration-cache-problems=warn') + + then: "no configuration cache incompatibilities" + result.output.contains("1 problem was found storing the configuration cache") + result.output.contains('Gradle runtime: support for using a Java agent with TestKit') + result.output.contains('Calculating task graph as no cached configuration is available for tasks:') + + then: "task successful" + result.task(':animalsnifferMain').outcome == TaskOutcome.SUCCESS + + when: "run from cache" + println '\n\n------------------- FROM CACHE ----------------------------------------' + result = runVer(UpstreamKitTest.GRADLE_VERSION, 'check', '--configuration-cache', '--configuration-cache-problems=warn') + + then: "cache used" + result.output.contains('Reusing configuration cache.') + +// then: "task successful" +// result.task(':animalsnifferMain').outcome == TaskOutcome.SUCCESS + + } +} diff --git a/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreanMultiplatformConfigurationCacheKitTest.groovy b/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreanMultiplatformConfigurationCacheKitTest.groovy new file mode 100644 index 0000000..c667233 --- /dev/null +++ b/src/test/groovy/ru/vyarus/gradle/plugin/animalsniffer/cache/configuration/UpstreanMultiplatformConfigurationCacheKitTest.groovy @@ -0,0 +1,66 @@ +package ru.vyarus.gradle.plugin.animalsniffer.cache.configuration + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.TaskOutcome +import ru.vyarus.gradle.plugin.animalsniffer.AbstractKitTest +import ru.vyarus.gradle.plugin.animalsniffer.UpstreamKitTest + +/** + * @author Vyacheslav Rusakov + * @since 12.12.2024 + */ +class UpstreanMultiplatformConfigurationCacheKitTest extends AbstractKitTest { + + def "Check configuration cache support"() { + setup: + build """ + plugins { + id 'org.jetbrains.kotlin.multiplatform' version '$UpstreamKitTest.KOTLIN_PLUGIN_VERSION' + id 'ru.vyarus.animalsniffer' + } + + kotlin { + jvm() + + sourceSets { + commonMain.dependencies { + implementation 'org.slf4j:slf4j-api:1.7.25' + } + } + } + + animalsniffer { + ignoreFailures = true + } + + repositories { mavenCentral()} + dependencies { + signature 'org.codehaus.mojo.signature:java16-sun:1.0@signature' + } + """ + fileFromClasspath('src/jvmMain/kotlin/invalid/Sample.kt', '/ru/vyarus/gradle/plugin/animalsniffer/kotlin/invalid/Sample.kt') +// debug() + + when: "run task" + BuildResult result = runVer(UpstreamKitTest.GRADLE_VERSION, 'check', '--configuration-cache', '--configuration-cache-problems=warn') + + then: "no configuration cache incompatibilities" + result.output.contains("1 problem was found storing the configuration cache") + result.output.contains('Gradle runtime: support for using a Java agent with TestKit') + result.output.contains('Calculating task graph as no cached configuration is available for tasks:') + + then: "task successful" + result.task(':check').outcome == TaskOutcome.SUCCESS + + + when: "run from cache" + println '\n\n------------------- FROM CACHE ----------------------------------------' + result = runVer(UpstreamKitTest.GRADLE_VERSION, 'check', '--configuration-cache', '--configuration-cache-problems=warn') + + then: "cache used" + result.output.contains('Reusing configuration cache.') + +// then: "task successful" +// result.task(':check').outcome == TaskOutcome.SUCCESS + } +}