Repository: runningcode/fladle
Pull request #97 (2020-04-24 22:41:00)

Fix ability to specify flank version.
We need to specify the version inside the `afterEvaluate` block
otherwise the extension isn't set yet.

This also uses the new property api.

This avoids touching the filesystem during the configuration phase of
Gradle.

More information on working with files can be found here:
https://docs.gradle.org/current/userguide/working_with_files.html


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 99d29ac..5c6e5cc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
 # Changelog
 
+## 0.9.1
+* Bugfix: ability to set flank version.
+* Breaking API change: serviceAccountCredentials now uses [Lazy  Property API](https://docs.gradle.org/current/userguide/lazy_configuration.html#working_with_files_in_lazy_properties). See README for details on how to set it.
+* Minimum required Gradle Version is now 5.1.
+* Dropped support for Flank 7.X and lower.
+
 ## 0.9.0
 * Do not add flank maven repo. [PR](https://github.com/runningcode/fladle/pull/94)
 * Allow specifying custom flank coordinates. [PR](https://github.com/runningcode/fladle/pull/94)
diff --git a/README.md b/README.md
index 93b5744..030958e 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@ apply plugin: "com.osacky.fladle"
 2. Configure the Fladle extension.
 ``` groovy
 fladle {
-    serviceAccountCredentials("${project.file("flank-gradle-service-account.json")}")
+    serviceAccountCredentials = project.layout.projectDirectory.file("flank-gradle-service-account.json")
 }
 ```
 3. Run the flank gradle task.
@@ -56,7 +56,7 @@ Instructions on how to create this account can be found [here](https://firebase.
 ``` groovy
 fladle {
     // Required parameters
-    serviceAccountCredentials("${project.file("flank-gradle-5cf02dc90531.json")}")
+    serviceAccountCredentials = project.layout.projectDirectory.file("flank-gradle-5cf02dc90531.json")
 
     // Optional parameters
     useOrchestrator = false
@@ -118,12 +118,12 @@ The projectId is a unique identifier which can be found in the project's URL: `h
 This is automatically discovered based on the service credential by default.
 
 ### flankVersion
-`flankVersion("flank_snapshot")` to specify a Flank snapshot.
+`flankVersion = "flank_snapshot"` to specify a Flank snapshot.
 
-`flankVersion("8.1.0")` to specify a specific Flank version.
+`flankVersion = "8.1.0"` to specify a specific Flank version.
 
 ### flankCoordinates
-`flankCoordinates("com.github.flank:flank")` to specify custom flank coordinates.
+`flankCoordinates = "com.github.flank:flank"` to specify custom flank coordinates.
 
 ### debugApk
 This is the path to the app's debug apk.
diff --git a/buildSrc/src/main/java/com/osacky/flank/gradle/FladleConfig.kt b/buildSrc/src/main/java/com/osacky/flank/gradle/FladleConfig.kt
index f4e7e7a..fe10ec9 100644
--- a/buildSrc/src/main/java/com/osacky/flank/gradle/FladleConfig.kt
+++ b/buildSrc/src/main/java/com/osacky/flank/gradle/FladleConfig.kt
@@ -1,11 +1,11 @@
 package com.osacky.flank.gradle
 
+import org.gradle.api.file.RegularFileProperty
+
 interface FladleConfig {
-  var flankCoordinates: String
-  var flankVersion: String
   // Project id is automatically discovered by default. Use this to override the project id.
   var projectId: String?
-  var serviceAccountCredentials: String?
+  val serviceAccountCredentials: RegularFileProperty
   var useOrchestrator: Boolean
   var autoGoogleLogin: Boolean
   var devices: List<Map<String, String>>
diff --git a/buildSrc/src/main/java/com/osacky/flank/gradle/FladleConfigImpl.kt b/buildSrc/src/main/java/com/osacky/flank/gradle/FladleConfigImpl.kt
index c0edb99..38ea583 100644
--- a/buildSrc/src/main/java/com/osacky/flank/gradle/FladleConfigImpl.kt
+++ b/buildSrc/src/main/java/com/osacky/flank/gradle/FladleConfigImpl.kt
@@ -1,11 +1,11 @@
 package com.osacky.flank.gradle
 
+import org.gradle.api.file.RegularFileProperty
+
 data class FladleConfigImpl(
   internal val name: String,
-  override var flankCoordinates: String,
-  override var flankVersion: String,
   override var projectId: String?,
-  override var serviceAccountCredentials: String?,
+  override val serviceAccountCredentials: RegularFileProperty,
   override var useOrchestrator: Boolean,
   override var autoGoogleLogin: Boolean,
   override var devices: List<Map<String, String>>,
diff --git a/buildSrc/src/main/java/com/osacky/flank/gradle/FlankGradleExtension.kt b/buildSrc/src/main/java/com/osacky/flank/gradle/FlankGradleExtension.kt
index 689235b..1048a07 100644
--- a/buildSrc/src/main/java/com/osacky/flank/gradle/FlankGradleExtension.kt
+++ b/buildSrc/src/main/java/com/osacky/flank/gradle/FlankGradleExtension.kt
@@ -3,13 +3,16 @@ package com.osacky.flank.gradle
 import groovy.lang.Closure
 import org.gradle.api.NamedDomainObjectContainer
 import org.gradle.api.Project
+import org.gradle.api.file.RegularFileProperty
+import org.gradle.api.provider.Property
+import org.gradle.kotlin.dsl.property
 
 open class FlankGradleExtension(project: Project) : FladleConfig {
-  override var flankCoordinates: String = "flank:flank"
-  override var flankVersion: String = "8.1.0"
+  val flankCoordinates: Property<String> = project.objects.property(String::class.java).convention("flank:flank")
+  val flankVersion: Property<String> = project.objects.property(String::class.java).convention("8.1.0")
   // Project id is automatically discovered by default. Use this to override the project id.
   override var projectId: String? = null
-  override var serviceAccountCredentials: String? = null
+  override val serviceAccountCredentials: RegularFileProperty = project.objects.fileProperty()
   override var useOrchestrator: Boolean = false
   override var autoGoogleLogin: Boolean = false
   override var devices: List<Map<String, String>> = listOf(mapOf("model" to "NexusLowRes", "version" to "28"))
@@ -57,8 +60,6 @@ open class FlankGradleExtension(project: Project) : FladleConfig {
   val configs: NamedDomainObjectContainer<FladleConfigImpl> = project.container(FladleConfigImpl::class.java) {
     FladleConfigImpl(
       name = it,
-      flankCoordinates = flankCoordinates,
-      flankVersion = flankVersion,
       projectId = projectId,
       serviceAccountCredentials = serviceAccountCredentials,
       useOrchestrator = useOrchestrator,
diff --git a/buildSrc/src/main/java/com/osacky/flank/gradle/FlankGradlePlugin.kt b/buildSrc/src/main/java/com/osacky/flank/gradle/FlankGradlePlugin.kt
index 198564b..76f99c4 100644
--- a/buildSrc/src/main/java/com/osacky/flank/gradle/FlankGradlePlugin.kt
+++ b/buildSrc/src/main/java/com/osacky/flank/gradle/FlankGradlePlugin.kt
@@ -31,9 +31,15 @@ class FlankGradlePlugin : Plugin<Project> {
   }
 
   private fun configureTasks(project: Project, base: FlankGradleExtension) {
-    // Add Flank dependency to Fladle Configuration
-    project.dependencies.add(FLADLE_CONFIG, "${base.flankCoordinates}:${base.flankVersion}")
+    if (GradleVersion.current() > GradleVersion.version("6.1")) {
+      base.flankVersion.finalizeValueOnRead()
+      base.flankCoordinates.finalizeValueOnRead()
+      base.serviceAccountCredentials.finalizeValueOnRead()
+    }
     project.afterEvaluate {
+      // Add Flank dependency to Fladle Configuration
+      // Must be done afterEvaluate otherwise extension values will not be set.
+      project.dependencies.add(FLADLE_CONFIG, "${base.flankCoordinates.get()}:${base.flankVersion.get()}")
 
       // Only use automatic apk path detection for 'com.android.application' projects.
       project.pluginManager.withPlugin("com.android.application") {
@@ -79,8 +85,8 @@ class FlankGradlePlugin : Plugin<Project> {
       classpath = project.fladleConfig
       main = "ftl.Main"
       args = listOf("firebase", "test", "android", "run")
-      if (config.serviceAccountCredentials != null) {
-        environment(mapOf("GOOGLE_APPLICATION_CREDENTIALS" to "${config.serviceAccountCredentials}"))
+      if (config.serviceAccountCredentials.isPresent) {
+        environment(mapOf("GOOGLE_APPLICATION_CREDENTIALS" to config.serviceAccountCredentials.get()))
       }
       dependsOn(named("writeConfigProps$name"))
       doFirst {
@@ -94,8 +100,8 @@ class FlankGradlePlugin : Plugin<Project> {
   }
 
   private fun checkFilesExist(base: FlankGradleExtension, project: Project) {
-    if (base.serviceAccountCredentials != null) {
-      check(project.file(base.serviceAccountCredentials!!).exists()) { "serviceAccountCredential file doesn't exist ${base.serviceAccountCredentials}" }
+    if (base.serviceAccountCredentials.isPresent) {
+      check(project.file(base.serviceAccountCredentials.get()).exists()) { "serviceAccountCredential file doesn't exist ${base.serviceAccountCredentials.get()}" }
     }
     checkNotNull(base.debugApk!!) { "debugApk file cannot be null ${base.debugApk}" }
     checkNotNull(base.instrumentationApk!!) { "instrumentationApk file cannot be null ${base.instrumentationApk}" }
@@ -137,7 +143,7 @@ class FlankGradlePlugin : Plugin<Project> {
     get() = configurations.getByName(FLADLE_CONFIG)
 
   companion object {
-    val GRADLE_MIN_VERSION = GradleVersion.version("4.9")
+    val GRADLE_MIN_VERSION = GradleVersion.version("5.1")
     const val TASK_GROUP = "fladle"
     const val FLADLE_CONFIG = "fladle"
     fun Project.log(message: String) {
diff --git a/buildSrc/src/main/java/com/osacky/flank/gradle/YamlWriter.kt b/buildSrc/src/main/java/com/osacky/flank/gradle/YamlWriter.kt
index fc1632a..fcf29ac 100644
--- a/buildSrc/src/main/java/com/osacky/flank/gradle/YamlWriter.kt
+++ b/buildSrc/src/main/java/com/osacky/flank/gradle/YamlWriter.kt
@@ -1,13 +1,12 @@
 package com.osacky.flank.gradle
 
 import org.gradle.internal.impldep.com.google.common.annotations.VisibleForTesting
-import org.gradle.util.VersionNumber
 
 internal class YamlWriter {
 
   internal fun createConfigProps(config: FladleConfig, base: FlankGradleExtension): String {
     if (base.projectId == null) {
-      checkNotNull(base.serviceAccountCredentials) { "ServiceAccountCredentials in fladle extension not set. https://github.com/runningcode/fladle#serviceaccountcredentials" }
+      check(base.serviceAccountCredentials.isPresent) { "ServiceAccountCredentials in fladle extension not set. https://github.com/runningcode/fladle#serviceaccountcredentials" }
     }
     checkNotNull(base.debugApk) { "debugApk cannot be null" }
     checkNotNull(base.instrumentationApk) { "instrumentationApk cannot be null" }
@@ -41,7 +40,7 @@ internal class YamlWriter {
       appendln("  shard-time: $shardTime")
     }
     repeatTests?.let {
-      appendln(repeatTestsLine(config.flankVersion, repeatTests))
+      appendln(repeatTestsLine(repeatTests))
     }
     smartFlankGcsPath?.let {
       appendln("  smart-flank-gcs-path: $it")
@@ -103,19 +102,19 @@ internal class YamlWriter {
         appendln("  - $dir")
       }
     }
-    appendln(flakyTestAttemptsLine(config.flankVersion, config.flakyTestAttempts))
+    appendln(flakyTestAttemptsLine(config.flakyTestAttempts))
     config.resultsDir?.let {
       appendln("  results-dir: $it")
     }
   }
 
-  private fun flakyTestAttemptsLine(flankVersion: String, flakyTestAttempts: Int): String {
-    val label = if (isFlankVersionAtLeast(flankVersion, 8)) "num-flaky-test-attempts" else "flaky-test-attempts"
+  private fun flakyTestAttemptsLine(flakyTestAttempts: Int): String {
+    val label = "num-flaky-test-attempts"
     return "  $label: $flakyTestAttempts"
   }
 
-  private fun repeatTestsLine(flankVersion: String, repeatTests: Int): String {
-    val label = if (isFlankVersionAtLeast(flankVersion, 8)) "num-test-runs" else "repeat-tests"
+  private fun repeatTestsLine(repeatTests: Int): String {
+    val label = "num-test-runs"
     return "  $label: $repeatTests"
   }
 
@@ -139,8 +138,4 @@ internal class YamlWriter {
       }
     }
   }
-
-  private fun isFlankVersionAtLeast(flankVersion: String, major: Int): Boolean {
-    return VersionNumber.parse(flankVersion).major >= major
-  }
 }
diff --git a/sample/build.gradle b/sample/build.gradle
index b89dec8..9ee200a 100644
--- a/sample/build.gradle
+++ b/sample/build.gradle
@@ -23,7 +23,8 @@ android {
 }
 
 fladle {
-    serviceAccountCredentials("${project.file("flank-gradle-5cf02dc90531.json")}")
+    flankVersion = "flank_snapshot"
+    serviceAccountCredentials = project.layout.projectDirectory.file("flank-gradle-5cf02dc90531.json")
     // Project Id is not needed if serviceAccountCredentials are set.
 //    projectId("flank-gradle")
     useOrchestrator = true


Test patch:
diff --git a/buildSrc/src/test/java/com/osacky/flank/gradle/MultipleConfigsTest.kt b/buildSrc/src/test/java/com/osacky/flank/gradle/MultipleConfigsTest.kt
index 94d81d0..b83c26d 100644
--- a/buildSrc/src/test/java/com/osacky/flank/gradle/MultipleConfigsTest.kt
+++ b/buildSrc/src/test/java/com/osacky/flank/gradle/MultipleConfigsTest.kt
@@ -19,7 +19,7 @@ class MultipleConfigsTest {
       |}
       |
       |fladle {
-      |  serviceAccountCredentials("flank-gradle-service.json")
+      |  serviceAccountCredentials = layout.projectDirectory.file("flank-gradle-service.json")
       |  debugApk("foo.apk")
       |  instrumentationApk("instrument.apk")
       |
diff --git a/buildSrc/src/test/java/com/osacky/flank/gradle/YamlWriterTest.kt b/buildSrc/src/test/java/com/osacky/flank/gradle/YamlWriterTest.kt
index c66c802..83cc27b 100644
--- a/buildSrc/src/test/java/com/osacky/flank/gradle/YamlWriterTest.kt
+++ b/buildSrc/src/test/java/com/osacky/flank/gradle/YamlWriterTest.kt
@@ -162,7 +162,7 @@ class YamlWriterTest {
   @Test
   fun verifyDebugApkThrowsError() {
     val extension = FlankGradleExtension(project).apply {
-      serviceAccountCredentials = "fake.json"
+      serviceAccountCredentials.set(project.layout.projectDirectory.file("fake.json"))
     }
     try {
       yamlWriter.createConfigProps(extension, extension)
@@ -175,7 +175,7 @@ class YamlWriterTest {
   @Test
   fun verifyInstrumentationApkThrowsError() {
     val extension = FlankGradleExtension(project).apply {
-      serviceAccountCredentials = "fake.json"
+      serviceAccountCredentials.set(project.layout.projectDirectory.file("fake.json"))
       debugApk = "path"
     }
     try {
@@ -253,18 +253,6 @@ class YamlWriterTest {
         "  keep-file-path: false\n", yamlWriter.writeFlankProperties(extension))
   }
 
-  @Test
-  fun writeTestRepeatsForOlderFlankVersions() {
-    val extension = FlankGradleExtension(project).apply {
-      flankVersion = "7.0.2"
-      repeatTests = 5
-    }
-
-    assertEquals("flank:\n" +
-        "  repeat-tests: 5\n" +
-        "  keep-file-path: false\n", yamlWriter.writeFlankProperties(extension))
-  }
-
   @Test
   fun writeTestShardAndRepeatOption() {
     val extension = FlankGradleExtension(project).apply {
@@ -552,21 +540,6 @@ class YamlWriterTest {
       yamlWriter.writeAdditionalProperties(extension))
   }
 
-  @Test
-  fun writeFlakyTestAttemptsForOldFlankVersion() {
-    val extension = FlankGradleExtension(project).apply {
-      flankVersion = "7.0.2"
-      flakyTestAttempts = 3
-    }
-    assertEquals("  use-orchestrator: false\n" +
-        "  auto-google-login: false\n" +
-        "  record-video: true\n" +
-        "  performance-metrics: true\n" +
-        "  timeout: 15m\n" +
-        "  flaky-test-attempts: 3\n",
-      yamlWriter.writeAdditionalProperties(extension))
-  }
-
   @Test
   fun writeNoKeepFilePath() {
     val extension = FlankGradleExtension(project)
diff --git a/buildSrc/src/test/java/com/osacky/flank/gradle/integration/FlankGradlePluginIntegrationTest.kt b/buildSrc/src/test/java/com/osacky/flank/gradle/integration/FlankGradlePluginIntegrationTest.kt
index 4b6f9b8..d2eccf9 100644
--- a/buildSrc/src/test/java/com/osacky/flank/gradle/integration/FlankGradlePluginIntegrationTest.kt
+++ b/buildSrc/src/test/java/com/osacky/flank/gradle/integration/FlankGradlePluginIntegrationTest.kt
@@ -28,13 +28,29 @@ class FlankGradlePluginIntegrationTest {
             GradleRunner.create()
                 .withProjectDir(testProjectRoot.root)
                 .withPluginClasspath()
-                .withGradleVersion("4.8")
+                .withGradleVersion("5.0")
                 .build()
         } catch (expected: UnexpectedBuildFailure) {
-            assertThat(expected).hasMessageThat().contains("Fladle requires at minimum version Gradle 4.9. Detected version Gradle 4.8")
+            assertThat(expected).hasMessageThat().contains("Fladle requires at minimum version Gradle 5.1. Detected version Gradle 5.0")
         }
     }
 
+    @Test
+    fun testGradleSixZero() {
+        writeBuildGradle(
+                """plugins {
+             |  id "com.osacky.fladle"
+             |}""".trimMargin()
+        )
+        val result = GradleRunner.create()
+                .withProjectDir(testProjectRoot.root)
+                .withPluginClasspath()
+                .withGradleVersion("6.0")
+                .build()
+
+        assertThat(result.output).contains("SUCCESS")
+    }
+
     @Test
     fun testMinSupportedGradleVersionWorks() {
         writeBuildGradle(
@@ -45,7 +61,7 @@ class FlankGradlePluginIntegrationTest {
         GradleRunner.create()
             .withProjectDir(testProjectRoot.root)
             .withPluginClasspath()
-            .withGradleVersion("4.9")
+            .withGradleVersion("5.1")
             .build()
     }
 
@@ -101,7 +117,7 @@ class FlankGradlePluginIntegrationTest {
              |  id "com.osacky.fladle"
              |}
              |fladle {
-             |  serviceAccountCredentials = "foo"
+             |  serviceAccountCredentials = project.layout.projectDirectory.file("foo")
              |}
              |""".trimMargin()
         )