From b88bbb2a8e74a7f6a79088608f8f283b91beed44 Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Mon, 9 Feb 2026 15:08:32 -0500 Subject: [PATCH 1/8] replace java version printing task with one that uses configuration avoidance --- .../gradle/src/main/kotlin/FlutterPluginUtils.kt | 8 ++++---- .../gradle/src/main/kotlin/tasks/PrintTask.kt | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 packages/flutter_tools/gradle/src/main/kotlin/tasks/PrintTask.kt diff --git a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt index d7bdc23a2e4..5778e8f5b91 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt @@ -12,12 +12,14 @@ import com.android.build.gradle.tasks.ProcessAndroidResources import com.android.builder.model.BuildType import com.flutter.gradle.plugins.PluginHandler import com.flutter.gradle.tasks.DeepLinkJsonFromManifestTask +import com.flutter.gradle.tasks.PrintTask import groovy.lang.Closure import org.gradle.api.GradleException import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.UnknownTaskException import org.gradle.api.logging.Logger +import org.gradle.kotlin.dsl.register import java.io.File import java.nio.charset.StandardCharsets import java.util.Properties @@ -708,12 +710,10 @@ object FlutterPluginUtils { @JvmStatic @JvmName("addTaskForJavaVersion") internal fun addTaskForJavaVersion(project: Project) { - project.tasks.register("javaVersion") { + project.tasks.register("javaVersion") { description = "Print the current java version used by gradle. see: " + "https://docs.gradle.org/current/javadoc/org/gradle/api/JavaVersion.html" - doLast { - println(VersionFetcher.getJavaVersion()) - } + message.set(VersionFetcher.getJavaVersion().toString()) } } diff --git a/packages/flutter_tools/gradle/src/main/kotlin/tasks/PrintTask.kt b/packages/flutter_tools/gradle/src/main/kotlin/tasks/PrintTask.kt new file mode 100644 index 00000000000..2977d5c4665 --- /dev/null +++ b/packages/flutter_tools/gradle/src/main/kotlin/tasks/PrintTask.kt @@ -0,0 +1,16 @@ +package com.flutter.gradle.tasks + +import org.gradle.api.DefaultTask +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.TaskAction + +abstract class PrintTask : DefaultTask() { + @get:Input + abstract val message: Property + + @TaskAction + fun run() { + println(message.get()) + } +} From deb898583236878112a22f08cd782ba3aec1666f Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Mon, 9 Feb 2026 15:19:32 -0500 Subject: [PATCH 2/8] migrate kgpVersion to configuration avoidance api --- .../gradle/src/main/kotlin/FlutterPluginUtils.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt index 5778e8f5b91..7292e2e81a7 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt @@ -727,11 +727,9 @@ object FlutterPluginUtils { @JvmStatic @JvmName("addTaskForKGPVersion") internal fun addTaskForKGPVersion(project: Project) { - project.tasks.register("kgpVersion") { + project.tasks.register("kgpVersion") { description = "Print the current kgp version used by the project." - doLast { - println("KGP Version: " + VersionFetcher.getKGPVersion(project).toString()) - } + message.set("KGP Version: " + VersionFetcher.getKGPVersion(project).toString()) } } From 47726558deab7fcf43eea7c0cb440cc6d4f071fe Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Mon, 9 Feb 2026 15:25:04 -0500 Subject: [PATCH 3/8] Migrate printing configurations without modifying how they are discovered --- .../gradle/src/main/kotlin/FlutterPluginUtils.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt index 7292e2e81a7..26bd9e3b00d 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt @@ -750,13 +750,14 @@ object FlutterPluginUtils { // TODO(gmackall): We should take another pass at the different types we are using in our conversion of // the groovy `flutter.android` lines. val androidExtension = project.extensions.getByType(AbstractAppExtension::class.java) - project.tasks.register("printBuildVariants") { + + project.tasks.register("printBuildVariants") { description = "Prints out all build variants for this Android project" - doLast { - androidExtension.applicationVariants.forEach { variant -> - println("BuildVariant: ${variant.name}") - } + val messageBuilder = StringBuilder() + androidExtension.applicationVariants.forEach { variant -> + messageBuilder.append("BuildVariant: ${variant.name}\n") } + message.set(messageBuilder.toString()) } } From 0c40d2a7308f097fb8db8668813e8e28add62a7c Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Mon, 9 Feb 2026 16:02:52 -0500 Subject: [PATCH 4/8] modify mocks so that javaVersion tests pass, add coverage for actually getting java version --- .../src/test/kotlin/FlutterPluginUtilsTest.kt | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt b/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt index 9e429f1dfb1..36b0fe04fa0 100644 --- a/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt +++ b/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt @@ -10,6 +10,7 @@ import com.android.build.gradle.internal.dsl.CmakeOptions import com.android.build.gradle.internal.dsl.DefaultConfig import com.android.builder.model.BuildType import com.flutter.gradle.plugins.PluginHandler +import com.flutter.gradle.tasks.PrintTask import io.mockk.called import io.mockk.every import io.mockk.mockk @@ -24,6 +25,8 @@ import org.gradle.api.UnknownTaskException import org.gradle.api.file.Directory import org.gradle.api.file.DirectoryProperty import org.gradle.api.logging.Logger +import org.gradle.api.tasks.TaskContainer +import org.gradle.api.tasks.TaskProvider import org.jetbrains.kotlin.gradle.plugin.extraProperties import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.io.TempDir @@ -34,6 +37,7 @@ import kotlin.io.path.createDirectory import kotlin.test.Test import kotlin.test.assertContains import kotlin.test.assertEquals +import kotlin.test.assertNotNull class FlutterPluginUtilsTest { companion object { @@ -1006,23 +1010,31 @@ class FlutterPluginUtilsTest { } } - // addTaskForJavaVersion @Test fun `addTaskForJavaVersion adds task for Java version`() { val project = mockk() - every { project.tasks.register(any(), any>()) } returns mockk() - val captureSlot = slot>() - FlutterPluginUtils.addTaskForJavaVersion(project) - verify { project.tasks.register("javaVersion", capture(captureSlot)) } + val taskContainer = mockk() + every { project.tasks } returns taskContainer + val mockTaskProvider = mockk>() + val mockPrintTask = mockk(relaxed = true) + val captureSlot = slot>() + + every { + project.tasks.register(eq("javaVersion"), PrintTask::class.java, capture(captureSlot)) + } returns mockTaskProvider + + FlutterPluginUtils.addTaskForJavaVersion(project) + captureSlot.captured.execute(mockPrintTask) - val mockTask = mockk() - every { mockTask.description = any() } returns Unit - every { mockTask.doLast(any>()) } returns mockk() - captureSlot.captured.execute(mockTask) verify { - mockTask.description = "Print the current java version used by gradle. see: " + + mockPrintTask.description = "Print the current java version used by gradle. see: " + "https://docs.gradle.org/current/javadoc/org/gradle/api/JavaVersion.html" } + verify { + mockPrintTask.message.set( + withArg { assertNotNull(it.toIntOrNull(), message = "$it java version is not an int") } + ) + } } // addTaskForKGPVersion From 4007ce859acc28babcc119321aab6a821a651991 Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Mon, 9 Feb 2026 16:17:23 -0500 Subject: [PATCH 5/8] modify mocks so that kgpVersion tests pass, add coverage for actually verifying kotlin version --- .../src/test/kotlin/FlutterPluginUtilsTest.kt | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt b/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt index 36b0fe04fa0..4aa0656621c 100644 --- a/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt +++ b/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt @@ -1041,17 +1041,31 @@ class FlutterPluginUtilsTest { @Test fun `addTaskForKGPVersion adds task for KGP version`() { val project = mockk() - every { project.tasks.register(any(), any>()) } returns mockk() - val captureSlot = slot>() - FlutterPluginUtils.addTaskForKGPVersion(project) - verify { project.tasks.register("kgpVersion", capture(captureSlot)) } + val taskContainer = mockk() + every { project.tasks } returns taskContainer + val mockTaskProvider = mockk>() + val mockPrintTask = mockk(relaxed = true) + val captureSlot = slot>() + + every { + project.tasks.register(eq("kgpVersion"), PrintTask::class.java, capture(captureSlot)) + } returns mockTaskProvider + + // Minimal configuration for `VersionFetcher.getKGPVersion` to return something. + every { project.hasProperty("kotlin_version") } returns true + every { project.properties["kotlin_version"] } returns "2.2.0" + + FlutterPluginUtils.addTaskForKGPVersion(project) + captureSlot.captured.execute(mockPrintTask) - val mockTask = mockk() - every { mockTask.description = any() } returns Unit - every { mockTask.doLast(any>()) } returns mockk() - captureSlot.captured.execute(mockTask) verify { - mockTask.description = "Print the current kgp version used by the project." + mockPrintTask.description = "Print the current kgp version used by the project." + } + + verify { + mockPrintTask.message.set( + withArg { assertContains(it, "2.2.0") } + ) } } From 8968dc668fb558476f5d6723e0e4407af1d4991f Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Mon, 9 Feb 2026 16:40:54 -0500 Subject: [PATCH 6/8] Add tests for printBuildVariants and expand test coverage to test output --- .../src/test/kotlin/FlutterPluginUtilsTest.kt | 46 ++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt b/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt index 4aa0656621c..5cd2fb7569a 100644 --- a/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt +++ b/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt @@ -6,6 +6,7 @@ package com.flutter.gradle import com.android.build.gradle.AbstractAppExtension import com.android.build.gradle.BaseExtension +import com.android.build.gradle.api.ApplicationVariant import com.android.build.gradle.internal.dsl.CmakeOptions import com.android.build.gradle.internal.dsl.DefaultConfig import com.android.builder.model.BuildType @@ -1073,21 +1074,44 @@ class FlutterPluginUtilsTest { @Test fun `addTaskForPrintBuildVariants adds task for printing build variants`() { val project = mockk() - every { project.extensions.getByType(AbstractAppExtension::class.java) } returns mockk() - every { project.tasks.register(any(), any>()) } returns mockk() - val captureSlot = slot>() + val taskContainer = mockk() + every { project.tasks } returns taskContainer + val mockTaskProvider = mockk>() + val mockPrintTask = mockk(relaxed = true) + val captureSlot = slot>() + val mockAbstractAppExtension = mockk() + + every { project.extensions.getByType(AbstractAppExtension::class.java) } returns mockAbstractAppExtension + val variantCollection = mockk>() + every { mockAbstractAppExtension.applicationVariants } returns variantCollection + + val variantDebug = mockk() + every { variantDebug.name } returns "debug" + val variantRelease = mockk() + every { variantRelease.name } returns "release" + val variantProfile = mockk() + every { variantProfile.name } returns "profile" + every { variantCollection.iterator() } returns + mutableSetOf(variantDebug, variantRelease, variantProfile).iterator() + + every { + project.tasks.register(eq("printBuildVariants"), PrintTask::class.java, capture(captureSlot)) + } returns mockTaskProvider FlutterPluginUtils.addTaskForPrintBuildVariants(project) - - verify { project.tasks.register("printBuildVariants", capture(captureSlot)) } - val mockTask = mockk() - every { mockTask.description = any() } returns Unit - every { mockTask.doLast(any>()) } returns mockk() - - captureSlot.captured.execute(mockTask) + captureSlot.captured.execute(mockPrintTask) verify { - mockTask.description = "Prints out all build variants for this Android project" + mockPrintTask.description = "Prints out all build variants for this Android project" + } + verify { + mockPrintTask.message.set( + withArg { + assertContains(it, "BuildVariant: debug") + assertContains(it, "BuildVariant: release") + assertContains(it, "BuildVariant: profile") + } + ) } } } From 4b475450af10069d0e19774c97ca5d29acd77aff Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Mon, 9 Feb 2026 17:07:11 -0500 Subject: [PATCH 7/8] Modify tests for FlutterPlugin.apply and add test that verifies kgpVersion --- .../gradle/src/test/kotlin/FlutterPluginTest.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginTest.kt b/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginTest.kt index 146c7b89628..7951568069d 100644 --- a/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginTest.kt +++ b/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginTest.kt @@ -10,6 +10,7 @@ import com.android.build.gradle.internal.core.InternalBaseVariant import com.android.build.gradle.tasks.MergeSourceSetFolders import com.android.build.gradle.tasks.ProcessAndroidResources import com.flutter.gradle.tasks.FlutterTask +import com.flutter.gradle.tasks.PrintTask import io.mockk.every import io.mockk.mockk import io.mockk.mockkObject @@ -28,6 +29,7 @@ import org.junit.jupiter.api.io.TempDir import java.nio.file.Path import kotlin.io.path.writeText import kotlin.test.Test +import kotlin.test.assertContains class FlutterPluginTest { @Test @@ -88,8 +90,15 @@ class FlutterPluginTest { flutterPlugin.apply(project) verify { project.tasks.register("generateLockfiles", any()) } - verify { project.tasks.register("javaVersion", any()) } - verify { project.tasks.register("printBuildVariants", any()) } + + val registeredPrintTasks = mutableListOf() + verify { + project.tasks.register(capture(registeredPrintTasks), PrintTask::class.java, any()) + } + + assertContains(registeredPrintTasks, "javaVersion") + assertContains(registeredPrintTasks, "kgpVersion") + assertContains(registeredPrintTasks, "printBuildVariants") } @Test From 81b1210adc8f5d93dade2ad119cdf30ed337422e Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Tue, 10 Feb 2026 13:49:01 -0500 Subject: [PATCH 8/8] Use project.provider and update tests to no longer check for output --- .../src/main/kotlin/FlutterPluginUtils.kt | 22 ++++++----- .../src/test/kotlin/FlutterPluginUtilsTest.kt | 38 ++----------------- 2 files changed, 16 insertions(+), 44 deletions(-) diff --git a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt index 26bd9e3b00d..02322a86a33 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt @@ -729,7 +729,7 @@ object FlutterPluginUtils { internal fun addTaskForKGPVersion(project: Project) { project.tasks.register("kgpVersion") { description = "Print the current kgp version used by the project." - message.set("KGP Version: " + VersionFetcher.getKGPVersion(project).toString()) + message.set(project.provider { "KGP Version: " + VersionFetcher.getKGPVersion(project).toString() }) } } @@ -746,18 +746,20 @@ object FlutterPluginUtils { @JvmStatic @JvmName("addTaskForPrintBuildVariants") internal fun addTaskForPrintBuildVariants(project: Project) { - // Groovy was dynamically getting a different subtype here than our Kotlin getAndroidExtension method. - // TODO(gmackall): We should take another pass at the different types we are using in our conversion of - // the groovy `flutter.android` lines. - val androidExtension = project.extensions.getByType(AbstractAppExtension::class.java) - project.tasks.register("printBuildVariants") { description = "Prints out all build variants for this Android project" - val messageBuilder = StringBuilder() - androidExtension.applicationVariants.forEach { variant -> - messageBuilder.append("BuildVariant: ${variant.name}\n") + project.provider { + // Groovy was dynamically getting a different subtype here than our Kotlin getAndroidExtension method. + // TODO(gmackall): We should take another pass at the different types we are using in our conversion of + // the groovy `flutter.android` lines. + val androidExtension = project.extensions.getByType(AbstractAppExtension::class.java) + + val messageBuilder = StringBuilder() + androidExtension.applicationVariants.forEach { variant -> + messageBuilder.append("BuildVariant: ${variant.name}\n") + } + message.set(messageBuilder.toString()) } - message.set(messageBuilder.toString()) } } diff --git a/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt b/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt index 5cd2fb7569a..1e61ee771eb 100644 --- a/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt +++ b/packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginUtilsTest.kt @@ -6,7 +6,6 @@ package com.flutter.gradle import com.android.build.gradle.AbstractAppExtension import com.android.build.gradle.BaseExtension -import com.android.build.gradle.api.ApplicationVariant import com.android.build.gradle.internal.dsl.CmakeOptions import com.android.build.gradle.internal.dsl.DefaultConfig import com.android.builder.model.BuildType @@ -1051,10 +1050,8 @@ class FlutterPluginUtilsTest { every { project.tasks.register(eq("kgpVersion"), PrintTask::class.java, capture(captureSlot)) } returns mockTaskProvider - - // Minimal configuration for `VersionFetcher.getKGPVersion` to return something. - every { project.hasProperty("kotlin_version") } returns true - every { project.properties["kotlin_version"] } returns "2.2.0" + every { project.provider(any()) } returns mockTaskProvider + every { mockTaskProvider.configure(any()).hint(PrintTask::class) } FlutterPluginUtils.addTaskForKGPVersion(project) captureSlot.captured.execute(mockPrintTask) @@ -1062,12 +1059,6 @@ class FlutterPluginUtilsTest { verify { mockPrintTask.description = "Print the current kgp version used by the project." } - - verify { - mockPrintTask.message.set( - withArg { assertContains(it, "2.2.0") } - ) - } } // addTaskForPrintBuildVariants @@ -1079,24 +1070,12 @@ class FlutterPluginUtilsTest { val mockTaskProvider = mockk>() val mockPrintTask = mockk(relaxed = true) val captureSlot = slot>() - val mockAbstractAppExtension = mockk() - - every { project.extensions.getByType(AbstractAppExtension::class.java) } returns mockAbstractAppExtension - val variantCollection = mockk>() - every { mockAbstractAppExtension.applicationVariants } returns variantCollection - - val variantDebug = mockk() - every { variantDebug.name } returns "debug" - val variantRelease = mockk() - every { variantRelease.name } returns "release" - val variantProfile = mockk() - every { variantProfile.name } returns "profile" - every { variantCollection.iterator() } returns - mutableSetOf(variantDebug, variantRelease, variantProfile).iterator() every { project.tasks.register(eq("printBuildVariants"), PrintTask::class.java, capture(captureSlot)) } returns mockTaskProvider + every { project.provider(any()) } returns mockTaskProvider + every { mockTaskProvider.configure(any()).hint(PrintTask::class) } FlutterPluginUtils.addTaskForPrintBuildVariants(project) captureSlot.captured.execute(mockPrintTask) @@ -1104,14 +1083,5 @@ class FlutterPluginUtilsTest { verify { mockPrintTask.description = "Prints out all build variants for this Android project" } - verify { - mockPrintTask.message.set( - withArg { - assertContains(it, "BuildVariant: debug") - assertContains(it, "BuildVariant: release") - assertContains(it, "BuildVariant: profile") - } - ) - } } }