Skip to content

Commit 3efc074

Browse files
refactor: Structural output refresh last run (#2139)
1 parent 14126f5 commit 3efc074

File tree

28 files changed

+217
-62
lines changed

28 files changed

+217
-62
lines changed

buildSrc/src/main/kotlin/Dependencies.kt

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ object Dependencies {
5656
const val SYSTEM_RULES = "com.github.stefanbirkner:system-rules:${Versions.SYSTEM_RULES}"
5757
const val TRUTH = "com.google.truth:truth:${Versions.TRUTH}"
5858
const val MOCKK = "io.mockk:mockk:${Versions.MOCKK}"
59+
const val KOTLIN_COROUTINES_TEST = "org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.KOTLIN_COROUTINES}"
5960
//endregion
6061

6162
const val COMMON_TEXT = "org.apache.commons:commons-text:${Versions.COMMON_TEXT}"

check_version_updated/src/main/kotlin/com/github/flank/gradle/CheckVersionUpdatedTask.kt

+8-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ open class CheckVersionUpdatedTask : DefaultTask() {
1111
@TaskAction
1212
fun action() {
1313
project.execAndGetStdout("git", "fetch", "--no-tags")
14-
val changedFiles = project.execAndGetStdout("git", "diff", "origin/master", "HEAD", "--name-only").split("\n") +
15-
project.execAndGetStdout("git", "diff", "origin/master", "--name-only").split("\n")
14+
val changedFiles = (project.execAndGetStdout("git", "diff", "origin/master", "HEAD", "--name-only").split("\n") +
15+
project.execAndGetStdout("git", "diff", "origin/master", "--name-only").split("\n"))
16+
.toSet()
17+
.filterNot { file -> ignoredFiles.any { ignoredFile -> file.endsWith(ignoredFile) } }
18+
19+
1620
val isVersionChanged = changedFiles.any { it.startsWith(project.name) }.not() ||
1721
(changedFiles.contains("${project.name}/build.gradle.kts") && project.isVersionChangedInBuildGradle())
1822

@@ -44,4 +48,6 @@ open class CheckVersionUpdatedTask : DefaultTask() {
4448
return (commitedResultsStream + localResultsStream)
4549
.any { it.startsWith("-version = ") || it.startsWith("+version = ") }
4650
}
51+
52+
private val ignoredFiles = listOf("gradle-wrapper.properties", "main/resources/version.txt")
4753
}

flank_wrapper/.gitignore

-2
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,3 @@
33

44
# Ignore Gradle build output directory
55
build
6-
7-
src/main/resources/version.txt

flank_wrapper/build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ shadowJar.apply {
2424
}
2525
}
2626
// <breaking change>.<feature added>.<fix/minor change>
27-
version = "1.2.4"
27+
version = "1.2.5"
2828
group = "com.github.flank"
2929

3030
repositories {
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.2.3
1+
1.2.4

test_runner/build.gradle.kts

+5
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ dependencies {
217217
testImplementation(Dependencies.SYSTEM_RULES)
218218
testImplementation(Dependencies.TRUTH)
219219
testImplementation(Dependencies.MOCKK)
220+
testImplementation(Dependencies.KOTLIN_COROUTINES_TEST)
220221
}
221222

222223
buildscript {
@@ -231,6 +232,10 @@ buildscript {
231232

232233
tasks.withType<KotlinCompile> {
233234
kotlinOptions.jvmTarget = "1.8"
235+
kotlinOptions.freeCompilerArgs += listOf(
236+
"-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
237+
"-Xopt-in=kotlinx.coroutines.FlowPreview",
238+
)
234239
}
235240

236241
// https://github.com/gradle/kotlin-dsl/blob/master/samples/task-dependencies/build.gradle.kts#L41

test_runner/src/main/kotlin/ftl/client/google/AndroidCatalog.kt

+5-16
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,9 @@ import com.google.testing.model.AndroidDevice
44
import com.google.testing.model.AndroidDeviceCatalog
55
import com.google.testing.model.AndroidModel
66
import com.google.testing.model.Orientation
7-
import flank.common.logLn
8-
import ftl.api.fetchAndroidOsVersion
9-
import ftl.environment.android.getDescription
10-
import ftl.environment.getLocaleDescription
117
import ftl.http.executeWithRetry
12-
import ftl.presentation.cli.firebase.test.android.versions.toCliTable
8+
import ftl.presentation.cli.firebase.test.reportmanager.ReportManagerState
9+
import ftl.presentation.publish
1310

1411
/**
1512
* Contains lists of possible Android device and version ids, as well as checks
@@ -34,19 +31,9 @@ object AndroidCatalog {
3431

3532
fun getModels(projectId: String): List<AndroidModel> = deviceCatalog(projectId).models.orEmpty()
3633

37-
fun supportedVersionsAsTable(projectId: String) = fetchAndroidOsVersion(projectId).toCliTable()
38-
39-
fun describeSoftwareVersion(projectId: String, versionId: String) =
40-
fetchAndroidOsVersion(projectId).getDescription(versionId)
41-
42-
private fun getVersionsList(projectId: String) = deviceCatalog(projectId).versions
43-
4434
fun supportedOrientations(projectId: String): List<Orientation> =
4535
deviceCatalog(projectId).runtimeConfiguration.orientations
4636

47-
private fun getLocaleDescription(projectId: String, locale: String) =
48-
getLocales(projectId).getLocaleDescription(locale)
49-
5037
internal fun getLocales(projectId: String) = deviceCatalog(projectId).runtimeConfiguration.locales
5138

5239
fun androidModelIds(projectId: String) =
@@ -64,7 +51,9 @@ object AndroidCatalog {
6451
val form = deviceCatalog(projectId).models
6552
.find { it.id.equals(modelId, ignoreCase = true) }?.form
6653
?: DeviceType.PHYSICAL.name.also {
67-
logLn("Unable to find device type for $modelId. PHYSICAL used as fallback in cost calculations")
54+
ReportManagerState.Log(
55+
"Unable to find device type for $modelId. PHYSICAL used as fallback in cost calculations"
56+
).publish()
6857
}
6958

7059
return form.equals(DeviceType.VIRTUAL.name, ignoreCase = true) || form.equals(

test_runner/src/main/kotlin/ftl/client/google/GcStorage.kt

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ object GcStorage {
106106
path: String,
107107
name: String
108108
) {
109+
// TODO #2136 handle messages with state
109110
runWithProgress(
110111
startMessage = "Uploading [$name] to ${GCS_STORAGE_LINK + join(bucket, path).replace(name, "")}..",
111112
action = { storage.create(BlobInfo.newBuilder(bucket, path).build(), this) },
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
package ftl.domain
22

33
import ftl.args.AndroidArgs
4+
import ftl.presentation.Output
5+
import ftl.presentation.RunState
6+
import ftl.presentation.runBlockingWithObservingRunState
47
import ftl.run.refreshLastRun
58

6-
interface RefreshLastRun
9+
interface RefreshLastRun : Output
710

8-
suspend operator fun RefreshLastRun.invoke() {
9-
refreshLastRun(
10-
currentArgs = AndroidArgs.default(),
11-
testShardChunks = emptyList()
12-
)
11+
operator fun RefreshLastRun.invoke() {
12+
runBlockingWithObservingRunState {
13+
refreshLastRun(
14+
currentArgs = AndroidArgs.default(),
15+
testShardChunks = emptyList()
16+
)
17+
}
18+
}
19+
20+
sealed interface RefreshLastRunState : RunState {
21+
data class LoadingRun(val lastRun: String) : RefreshLastRunState
22+
object RefreshMatricesStarted : RefreshLastRunState
23+
data class RefreshMatrices(val matrixCount: Int) : RefreshLastRunState
24+
data class RefreshMatrix(val matrixState: String, val matrixId: String) : RefreshLastRunState
25+
object UpdatingMatrixFile : RefreshLastRunState
1326
}

test_runner/src/main/kotlin/ftl/domain/RunTestAndroid.kt

+4-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import ftl.config.defaultAndroidConfig
1010
import ftl.config.loadAndroidConfig
1111
import ftl.config.plus
1212
import ftl.mock.MockServer
13+
import ftl.presentation.Output
14+
import ftl.presentation.runBlockingWithObservingRunState
1315
import ftl.reports.addStepTime
1416
import ftl.reports.output.configure
1517
import ftl.reports.output.log
@@ -24,10 +26,9 @@ import ftl.util.TEST_TYPE
2426
import ftl.util.loadFile
2527
import ftl.util.printVersionInfo
2628
import ftl.util.setCrashReportTag
27-
import kotlinx.coroutines.runBlocking
2829
import java.nio.file.Paths
2930

30-
interface RunTestAndroid {
31+
interface RunTestAndroid : Output {
3132
val configPath: String
3233
val config: AndroidConfig
3334
val dryRun: Boolean
@@ -59,7 +60,7 @@ operator fun RunTestAndroid.invoke() {
5960
)
6061
reportConfiguration()
6162
}.validate().also { args ->
62-
runBlocking {
63+
runBlockingWithObservingRunState {
6364
if (dumpShards)
6465
args.dumpShards()
6566
else {

test_runner/src/main/kotlin/ftl/domain/RunTestIos.kt

+4-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import ftl.config.defaultIosConfig
1010
import ftl.config.loadIosConfig
1111
import ftl.config.plus
1212
import ftl.mock.MockServer
13+
import ftl.presentation.Output
14+
import ftl.presentation.runBlockingWithObservingRunState
1315
import ftl.reports.addStepTime
1416
import ftl.reports.output.configure
1517
import ftl.reports.output.log
@@ -24,10 +26,9 @@ import ftl.util.TEST_TYPE
2426
import ftl.util.loadFile
2527
import ftl.util.printVersionInfo
2628
import ftl.util.setCrashReportTag
27-
import kotlinx.coroutines.runBlocking
2829
import java.nio.file.Paths
2930

30-
interface RunIosTest {
31+
interface RunIosTest : Output {
3132
val configPath: String
3233
val config: IosConfig
3334
val dryRun: Boolean
@@ -63,7 +64,7 @@ operator fun RunIosTest.invoke() {
6364
if (dumpShards.not()) logLn(this)
6465
}.validate().run {
6566
if (dumpShards) dumpShards()
66-
else runBlocking {
67+
else runBlockingWithObservingRunState {
6768
addStepTime("Preparation", prepareStopWatch.check())
6869
newTestRun()
6970
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package ftl.presentation
2+
3+
import com.google.common.annotations.VisibleForTesting
4+
import kotlinx.coroutines.flow.MutableSharedFlow
5+
import kotlinx.coroutines.flow.collect
6+
import kotlinx.coroutines.launch
7+
import kotlinx.coroutines.runBlocking
8+
9+
interface RunState
10+
11+
@VisibleForTesting
12+
internal val runSharedFlow by lazy {
13+
MutableSharedFlow<RunState>(extraBufferCapacity = 1)
14+
}
15+
16+
internal fun Output.runBlockingWithObservingRunState(block: suspend () -> Unit) {
17+
runBlocking {
18+
val runStateCollectJob = launch {
19+
runSharedFlow.collect { runState -> runState.out() }
20+
}
21+
block()
22+
runStateCollectJob.cancel()
23+
}
24+
}
25+
26+
internal fun RunState.publish() {
27+
runSharedFlow.tryEmit(this)
28+
}

test_runner/src/main/kotlin/ftl/presentation/cli/FirebaseCommand.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package ftl.presentation.cli
22

33
import ftl.presentation.cli.firebase.CancelCommand
4-
import ftl.presentation.cli.firebase.RefreshCommand
54
import ftl.presentation.cli.firebase.TestCommand
5+
import ftl.presentation.cli.firebase.test.refresh.RefreshCommand
66
import ftl.util.PrintHelpCommand
77
import picocli.CommandLine.Command
88

test_runner/src/main/kotlin/ftl/presentation/cli/MainCommand.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ package ftl.presentation.cli
22

33
import ftl.log.setDebugLogging
44
import ftl.presentation.cli.firebase.CancelCommand
5-
import ftl.presentation.cli.firebase.RefreshCommand
65
import ftl.presentation.cli.firebase.test.AndroidCommand
76
import ftl.presentation.cli.firebase.test.IPBlocksCommand
87
import ftl.presentation.cli.firebase.test.IosCommand
98
import ftl.presentation.cli.firebase.test.NetworkProfilesCommand
109
import ftl.presentation.cli.firebase.test.ProvidedSoftwareCommand
10+
import ftl.presentation.cli.firebase.test.refresh.RefreshCommand
1111
import ftl.util.PrintHelpCommand
1212
import ftl.util.printVersionInfo
1313
import picocli.CommandLine

test_runner/src/main/kotlin/ftl/presentation/cli/firebase/test/android/AndroidRunCommand.kt

+12
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import ftl.config.createConfiguration
77
import ftl.domain.RunTestAndroid
88
import ftl.domain.invoke
99
import ftl.presentation.cli.firebase.test.CommonRunCommand
10+
import ftl.presentation.cli.firebase.test.reportmanager.ReportManagerState
11+
import ftl.presentation.cli.firebase.test.reportmanager.handleReportManagerState
12+
import ftl.presentation.outputLogger
13+
import ftl.presentation.throwUnknownType
1014
import ftl.run.ANDROID_SHARD_FILE
1115
import picocli.CommandLine
1216
import picocli.CommandLine.Command
@@ -52,4 +56,12 @@ class AndroidRunCommand :
5256
}
5357

5458
override fun run() = invoke()
59+
60+
override val out = outputLogger {
61+
// TODO add more types in #1870
62+
when (this) {
63+
is ReportManagerState -> handleReportManagerState(this)
64+
else -> throwUnknownType()
65+
}
66+
}
5567
}

test_runner/src/main/kotlin/ftl/presentation/cli/firebase/test/ios/IosRunCommand.kt

+12
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import ftl.config.ios.IosGcloudConfig
77
import ftl.domain.RunIosTest
88
import ftl.domain.invoke
99
import ftl.presentation.cli.firebase.test.CommonRunCommand
10+
import ftl.presentation.cli.firebase.test.reportmanager.ReportManagerState
11+
import ftl.presentation.cli.firebase.test.reportmanager.handleReportManagerState
12+
import ftl.presentation.outputLogger
13+
import ftl.presentation.throwUnknownType
1014
import ftl.run.IOS_SHARD_FILE
1115
import picocli.CommandLine
1216
import picocli.CommandLine.Command
@@ -52,4 +56,12 @@ class IosRunCommand :
5256
}
5357

5458
override fun run() = invoke()
59+
60+
override val out = outputLogger {
61+
// TODO add more types in #1871
62+
when (this) {
63+
is ReportManagerState -> handleReportManagerState(this)
64+
else -> throwUnknownType()
65+
}
66+
}
5567
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package ftl.presentation.cli.firebase.test.refresh
2+
3+
import ftl.config.FtlConstants
4+
import ftl.domain.RefreshLastRunState
5+
6+
internal fun handleRefreshLastRunState(state: RefreshLastRunState): String = when (state) {
7+
is RefreshLastRunState.LoadingRun -> "Loading run ${state.lastRun}"
8+
is RefreshLastRunState.RefreshMatrices -> "${FtlConstants.indent}Refreshing ${state.matrixCount}x matrices"
9+
RefreshLastRunState.RefreshMatricesStarted -> "RefreshMatrices"
10+
is RefreshLastRunState.RefreshMatrix -> "${FtlConstants.indent} ${state.matrixState} ${state.matrixId}"
11+
RefreshLastRunState.UpdatingMatrixFile -> "${FtlConstants.indent}Updating matrix file"
12+
}

test_runner/src/main/kotlin/ftl/presentation/cli/firebase/RefreshCommand.kt test_runner/src/main/kotlin/ftl/presentation/cli/firebase/test/refresh/RefreshCommand.kt

+16-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
package ftl.presentation.cli.firebase
1+
package ftl.presentation.cli.firebase.test.refresh
22

33
import ftl.domain.RefreshLastRun
4+
import ftl.domain.RefreshLastRunState
45
import ftl.domain.invoke
6+
import ftl.presentation.cli.firebase.test.reportmanager.ReportManagerState
7+
import ftl.presentation.cli.firebase.test.reportmanager.handleReportManagerState
8+
import ftl.presentation.outputLogger
9+
import ftl.presentation.throwUnknownType
510
import ftl.util.PrintHelpCommand
6-
import kotlinx.coroutines.runBlocking
711
import picocli.CommandLine.Command
812

913
@Command(
@@ -26,5 +30,14 @@ class RefreshCommand :
2630
PrintHelpCommand(),
2731
RefreshLastRun {
2832

29-
override fun run() = runBlocking { invoke() }
33+
override fun run() = invoke()
34+
35+
override val out = outputLogger {
36+
when (this) {
37+
is RefreshLastRunState -> handleRefreshLastRunState(this)
38+
is ReportManagerState -> handleReportManagerState(this)
39+
// TODO #2136 handle uploading file here
40+
else -> throwUnknownType()
41+
}
42+
}
3043
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package ftl.presentation.cli.firebase.test.reportmanager
2+
3+
import flank.common.newLine
4+
import flank.common.withNewLineAtTheEnd
5+
import ftl.presentation.RunState
6+
import ftl.reports.util.ReportManager
7+
import kotlin.math.roundToInt
8+
9+
sealed interface ReportManagerState : RunState {
10+
data class Log(val message: String) : ReportManagerState
11+
data class Warning(val message: String) : ReportManagerState
12+
data class ShardTimes(val shards: List<ReportManager.ShardEfficiency>) : ReportManagerState
13+
}
14+
15+
internal fun handleReportManagerState(state: ReportManagerState): String = when (state) {
16+
is ReportManagerState.Log -> state.message
17+
is ReportManagerState.Warning -> "WARNING: ${state.message}"
18+
is ReportManagerState.ShardTimes -> "Actual shard times:$newLine" + state.shards.joinToString(newLine) {
19+
" ${it.shard}: Expected: ${it.expectedTime.roundToInt()}s, Actual: ${it.finalTime.roundToInt()}s, Diff: ${it.timeDiff.roundToInt()}s"
20+
}.withNewLineAtTheEnd()
21+
}

test_runner/src/main/kotlin/ftl/reports/MatrixResultsReport.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import ftl.config.FtlConstants.indent
1010
import ftl.json.MatrixMap
1111
import ftl.json.asPrintableTable
1212
import ftl.json.isFailed
13+
import ftl.presentation.cli.firebase.test.reportmanager.ReportManagerState
14+
import ftl.presentation.publish
1315
import ftl.reports.output.log
1416
import ftl.reports.output.outputReport
1517
import ftl.reports.util.IReport
@@ -36,7 +38,7 @@ object MatrixResultsReport : IReport {
3638

3739
override fun run(matrices: MatrixMap, result: JUnitTest.Result?, printToStdout: Boolean, args: IArgs) {
3840
val output = generate(matrices)
39-
if (printToStdout) log(output)
41+
if (printToStdout) ReportManagerState.Log(output).publish()
4042
write(matrices, output, args)
4143
ReportManager.uploadReportResult(output, args, fileName())
4244
}

0 commit comments

Comments
 (0)