Repository: runningcode/fladle (kotlin)

Issue:
Duplicate status messages
**Describe the bug**
Running flank using fladle gives duplicated messages on output. 

**Details**
Flank provides 3 different types of output style [single, multi, verbose]. `--output-style=multi` is default when flank is running more than one execution. It is using ANSI codes to overwrite multiple lines in output. Some consoles may not supports ANSI codes so it can results with duplicated messages. Also running flank through gradle may give same results.

**To reproduce**
Run fladle with `max-test-shards`  > 1. It's important to have more than one shard. The expected result was pasted in issue https://github.com/Flank/flank/issues/841.

**Additional context**
* `--output-style=multi` displays separated status for each shard execution in separated line, lines are updated over time. Similar to gradle output when running multiple tasks in parallel. Requires ANSI codes support.
* `--output-style=single` displays shortened status of all executions in single line. Similar to gcloud output when running with sharding. Should work on any console.

**Possible solutions**
* Add option `output-style` to fladle so users can specify which one they want.
* Add `output-style=single` to executions under the hood so all executions on fladle will display single output.

Pull request:
Closes #140

Patch:
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 479f1a7e..10ff45cd 100644
--- a/buildSrc/src/main/java/com/osacky/flank/gradle/FladleConfig.kt
+++ b/buildSrc/src/main/java/com/osacky/flank/gradle/FladleConfig.kt
@@ -161,4 +161,12 @@ interface FladleConfig {
    * * 100  -> 100 seconds
    */
   var testTimeout: String
+
+  /**
+   * Output style of execution status. May be one of [verbose, multi, single].
+   * For runs with only one test execution the default value is 'verbose', in other cases
+   * 'multi' is used as the default. The output style 'multi' is not displayed correctly on consoles
+   * which don't support ansi codes, to avoid corrupted output use single or verbose.
+   */
+  var outputStyle: Property<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 d210a6dc..36498e07 100644
--- a/buildSrc/src/main/java/com/osacky/flank/gradle/FladleConfigImpl.kt
+++ b/buildSrc/src/main/java/com/osacky/flank/gradle/FladleConfigImpl.kt
@@ -40,5 +40,6 @@ data class FladleConfigImpl(
   override var networkProfile: String?,
   override var roboScript: String?,
   override var roboDirectives: List<List<String>>,
-  override var testTimeout: String
+  override var testTimeout: String,
+  override var outputStyle: Property<String>
 ) : FladleConfig
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 cd376415..f58e0434 100644
--- a/buildSrc/src/main/java/com/osacky/flank/gradle/FlankGradleExtension.kt
+++ b/buildSrc/src/main/java/com/osacky/flank/gradle/FlankGradleExtension.kt
@@ -89,6 +89,8 @@ open class FlankGradleExtension @Inject constructor(objects: ObjectFactory) : Fl
 
   override var testTimeout: String = "15m"
 
+  override var outputStyle: Property<String> = objects.property<String>().convention("single")
+
   val configs: NamedDomainObjectContainer<FladleConfigImpl> = objects.domainObjectContainer(FladleConfigImpl::class.java) {
     FladleConfigImpl(
       name = it,
@@ -126,7 +128,8 @@ open class FlankGradleExtension @Inject constructor(objects: ObjectFactory) : Fl
       networkProfile = networkProfile,
       roboScript = roboScript,
       roboDirectives = roboDirectives,
-      testTimeout = testTimeout
+      testTimeout = testTimeout,
+      outputStyle = outputStyle
     )
   }
 
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 1e5f566f..50bd860a 100644
--- a/buildSrc/src/main/java/com/osacky/flank/gradle/YamlWriter.kt
+++ b/buildSrc/src/main/java/com/osacky/flank/gradle/YamlWriter.kt
@@ -93,6 +93,8 @@ internal class YamlWriter {
         appendln("  - class $it")
       }
     }
+
+    appendln("  output-style: ${config.outputStyle.get()}")
   }
 
   internal fun writeAdditionalProperties(config: FladleConfig): String = buildString {


Test patch:
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 c05c8786..227e80fa 100644
--- a/buildSrc/src/test/java/com/osacky/flank/gradle/YamlWriterTest.kt
+++ b/buildSrc/src/test/java/com/osacky/flank/gradle/YamlWriterTest.kt
@@ -161,6 +161,7 @@ class YamlWriterTest {
                ignore-failed-tests: false
                disable-sharding: false
                smart-flank-disable-upload: false
+               output-style: single
              """.trimIndent() + '\n' // Dunno why this needs to be here to make the tests pass.
     )
   }
@@ -244,6 +245,7 @@ class YamlWriterTest {
       ignore-failed-tests: false
       disable-sharding: false
       smart-flank-disable-upload: false
+      output-style: single
     """.trimIndent() + '\n')
   }
 
@@ -256,7 +258,8 @@ class YamlWriterTest {
             "  keep-file-path: false\n" +
             "  ignore-failed-tests: false\n" +
             "  disable-sharding: false\n" +
-            "  smart-flank-disable-upload: false\n",
+            "  smart-flank-disable-upload: false\n" +
+            "  output-style: single\n",
       yamlWriter.writeFlankProperties(extension))
   }
 
@@ -271,7 +274,8 @@ class YamlWriterTest {
             "  keep-file-path: false\n" +
             "  ignore-failed-tests: false\n" +
             "  disable-sharding: false\n" +
-            "  smart-flank-disable-upload: false\n",
+            "  smart-flank-disable-upload: false\n" +
+            "  output-style: single\n",
       yamlWriter.writeFlankProperties(extension))
   }
 
@@ -286,7 +290,8 @@ class YamlWriterTest {
             "  keep-file-path: false\n" +
             "  ignore-failed-tests: false\n" +
             "  disable-sharding: false\n" +
-            "  smart-flank-disable-upload: false\n",
+            "  smart-flank-disable-upload: false\n" +
+            "  output-style: single\n",
             yamlWriter.writeFlankProperties(extension))
   }
 
@@ -301,7 +306,8 @@ class YamlWriterTest {
             "  keep-file-path: false\n" +
             "  ignore-failed-tests: false\n" +
             "  disable-sharding: false\n" +
-            "  smart-flank-disable-upload: false\n",
+            "  smart-flank-disable-upload: false\n" +
+            "  output-style: single\n",
       yamlWriter.writeFlankProperties(extension))
   }
 
@@ -315,7 +321,8 @@ class YamlWriterTest {
             "  keep-file-path: false\n" +
             "  ignore-failed-tests: false\n" +
             "  disable-sharding: false\n" +
-            "  smart-flank-disable-upload: false\n",
+            "  smart-flank-disable-upload: false\n" +
+            "  output-style: single\n",
       yamlWriter.writeFlankProperties(extension))
   }
 
@@ -330,7 +337,8 @@ class YamlWriterTest {
             "  keep-file-path: false\n" +
             "  ignore-failed-tests: false\n" +
             "  disable-sharding: false\n" +
-            "  smart-flank-disable-upload: false\n",
+            "  smart-flank-disable-upload: false\n" +
+            "  output-style: single\n",
             yamlWriter.writeFlankProperties(extension))
   }
 
@@ -348,7 +356,8 @@ class YamlWriterTest {
                     "  keep-file-path: false\n" +
                     "  ignore-failed-tests: false\n" +
                     "  disable-sharding: false\n" +
-                    "  smart-flank-disable-upload: false\n",
+                    "  smart-flank-disable-upload: false\n" +
+                    "  output-style: single\n",
             yamlWriter.writeFlankProperties(extension))
   }
 
@@ -479,7 +488,8 @@ class YamlWriterTest {
             "  keep-file-path: false\n" +
             "  ignore-failed-tests: false\n" +
             "  disable-sharding: false\n" +
-            "  smart-flank-disable-upload: false\n",
+            "  smart-flank-disable-upload: false\n" +
+            "  output-style: single\n",
         yamlWriter.writeFlankProperties(extension))
   }
 
@@ -542,7 +552,8 @@ class YamlWriterTest {
             "  keep-file-path: false\n" +
             "  ignore-failed-tests: false\n" +
             "  disable-sharding: false\n" +
-            "  smart-flank-disable-upload: false\n",
+            "  smart-flank-disable-upload: false\n" +
+            "  output-style: single\n",
       yamlWriter.writeFlankProperties(extension))
   }
 
@@ -558,7 +569,8 @@ class YamlWriterTest {
             "  - .*/screenshots/.*\n" +
             "  ignore-failed-tests: false\n" +
             "  disable-sharding: false\n" +
-            "  smart-flank-disable-upload: false\n",
+            "  smart-flank-disable-upload: false\n" +
+            "  output-style: single\n",
       yamlWriter.writeFlankProperties(extension))
   }
 
@@ -575,7 +587,8 @@ class YamlWriterTest {
         "  - .*/reports/.*\n" +
         "  ignore-failed-tests: false\n" +
         "  disable-sharding: false\n" +
-        "  smart-flank-disable-upload: false\n",
+        "  smart-flank-disable-upload: false\n" +
+        "  output-style: single\n",
       yamlWriter.writeFlankProperties(extension))
   }
 
@@ -646,7 +659,8 @@ class YamlWriterTest {
             "  keep-file-path: false\n" +
             "  ignore-failed-tests: false\n" +
             "  disable-sharding: false\n" +
-            "  smart-flank-disable-upload: false\n",
+            "  smart-flank-disable-upload: false\n" +
+            "  output-style: single\n",
       yamlWriter.writeFlankProperties(extension))
   }
 
@@ -661,7 +675,8 @@ class YamlWriterTest {
             "  keep-file-path: true\n" +
             "  ignore-failed-tests: false\n" +
             "  disable-sharding: false\n" +
-            "  smart-flank-disable-upload: false\n"
+            "  smart-flank-disable-upload: false\n" +
+            "  output-style: single\n"
       )
   }
 
@@ -697,6 +712,7 @@ class YamlWriterTest {
                ignore-failed-tests: false
                disable-sharding: false
                smart-flank-disable-upload: false
+               output-style: single
           """.trimIndent() + '\n'
     )
   }
@@ -712,6 +728,7 @@ class YamlWriterTest {
         ignore-failed-tests: false
         disable-sharding: false
         smart-flank-disable-upload: false
+        output-style: single
     """.trimIndent()
 
     val expectedAdditional = """
@@ -790,6 +807,22 @@ class YamlWriterTest {
     assertTrue(properties.contains("  num-uniform-shards: 20"))
   }
 
+  @Test
+  fun writeOutputStyle() {
+    val properties = emptyExtension {
+      outputStyle.set("anyString")
+    }.toFlankProperties()
+
+    assertTrue(properties.contains("  output-style: anyString"))
+  }
+
+  @Test
+  fun missingOutputStyle() {
+    val properties = emptyExtension().toFlankProperties()
+
+    assertTrue(properties.contains("  output-style: single"))
+  }
+
   @Test
   fun writeClientDetails() {
     val properties = emptyExtension {