Skip to content

Commit

Permalink
Env support (#77)
Browse files Browse the repository at this point in the history
* Secrets support in Orchestra

* CLI secrets support

* Secrets -> Env

* Renaming methods and adding escape character
  • Loading branch information
dmitry-zaitsev authored Aug 18, 2022
1 parent 6979d5c commit 5c8d794
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 33 deletions.
7 changes: 5 additions & 2 deletions maestro-cli/src/main/java/maestro/cli/command/TestCommand.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ class TestCommand : Callable<Int> {
@Option(names = ["-c", "--continuous"])
private var continuous: Boolean = false

@Option(names = ["-e", "--env"])
private var env: Map<String, String> = emptyMap()

@CommandLine.Spec
lateinit var commandSpec: CommandLine.Model.CommandSpec

Expand All @@ -54,8 +57,8 @@ class TestCommand : Callable<Int> {

val maestro = MaestroFactory.createMaestro(parent?.platform, parent?.host, parent?.port)

if (!continuous) return TestRunner.runSingle(maestro, flowFile)
if (!continuous) return TestRunner.runSingle(maestro, flowFile, env)

TestRunner.runContinuous(maestro, flowFile)
TestRunner.runContinuous(maestro, flowFile, env)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,9 @@ package maestro.cli.runner

import maestro.Maestro
import maestro.orchestra.MaestroCommand
import maestro.orchestra.MaestroInitFlow
import maestro.orchestra.Orchestra
import maestro.orchestra.OrchestraAppState
import maestro.orchestra.yaml.YamlCommandReader
import java.io.File
import java.util.IdentityHashMap

object MaestroCommandRunner {
Expand All @@ -34,6 +32,7 @@ object MaestroCommandRunner {
maestro: Maestro,
view: ResultView,
commands: List<MaestroCommand>,
env: Map<String, String>,
cachedAppState: OrchestraAppState?,
): Result {
val initFlow = YamlCommandReader.getConfig(commands)?.initFlow
Expand Down Expand Up @@ -84,14 +83,14 @@ object MaestroCommandRunner {

val cachedState = if (cachedAppState == null) {
initFlow?.let {
orchestra.runInitFlow(it) ?: return Result(flowSuccess = false, cachedAppState = null)
orchestra.runInitFlow(it, env = env) ?: return Result(flowSuccess = false, cachedAppState = null)
}
} else {
initFlow?.commands?.forEach { commandStatuses[it] = CommandStatus.COMPLETED }
cachedAppState
}

val flowSuccess = orchestra.runFlow(commands, cachedState)
val flowSuccess = orchestra.runFlow(commands, cachedState, env = env)

return Result(flowSuccess = flowSuccess, cachedAppState = cachedState)
}
Expand Down
11 changes: 10 additions & 1 deletion maestro-cli/src/main/java/maestro/cli/runner/TestRunner.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,26 @@ object TestRunner {
fun runSingle(
maestro: Maestro,
flowFile: File,
env: Map<String, String>,
): Int {
val view = ResultView()
val result = runCatching(view) {
val commands = YamlCommandReader.readCommands(flowFile.toPath())
MaestroCommandRunner.runCommands(maestro, view, commands, cachedAppState = null)
MaestroCommandRunner.runCommands(
maestro,
view,
commands,
env,
cachedAppState = null
)
}
return if (result?.flowSuccess == true) 0 else 1
}

fun runContinuous(
maestro: Maestro,
flowFile: File,
env: Map<String, String>,
): Nothing {
val view = ResultView("> Press [ENTER] to restart the Flow\n\n")

Expand Down Expand Up @@ -67,6 +75,7 @@ object TestRunner {
maestro,
view,
commands,
env,
cachedAppState = cachedAppState,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@
package maestro.orchestra

import maestro.Point
import maestro.orchestra.util.Env.injectEnv

interface Command {

fun description(): String

fun injectEnv(env: Map<String, String>): Command

}

data class SwipeCommand(
Expand All @@ -36,6 +39,10 @@ data class SwipeCommand(
return "Swipe from (${startPoint.x},${startPoint.y}) to (${endPoint.x},${endPoint.y})"
}

override fun injectEnv(env: Map<String, String>): SwipeCommand {
return this
}

}

class ScrollCommand : Command {
Expand All @@ -58,6 +65,10 @@ class ScrollCommand : Command {
return "Scroll vertically"
}

override fun injectEnv(env: Map<String, String>): ScrollCommand {
return this
}

}

class BackPressCommand : Command {
Expand All @@ -80,6 +91,9 @@ class BackPressCommand : Command {
return "Press back"
}

override fun injectEnv(env: Map<String, String>): BackPressCommand {
return this
}
}

data class TapOnElementCommand(
Expand All @@ -92,6 +106,11 @@ data class TapOnElementCommand(
return "Tap on ${selector.description()}"
}

override fun injectEnv(env: Map<String, String>): TapOnElementCommand {
return copy(
selector = selector.injectSecrets(env),
)
}
}

data class TapOnPointCommand(
Expand All @@ -104,6 +123,10 @@ data class TapOnPointCommand(
override fun description(): String {
return "Tap on point ($x, $y)"
}

override fun injectEnv(env: Map<String, String>): TapOnPointCommand {
return this
}
}

data class AssertCommand(
Expand All @@ -123,6 +146,12 @@ data class AssertCommand(
return "No op"
}

override fun injectEnv(env: Map<String, String>): AssertCommand {
return copy(
visible = visible?.injectSecrets(env),
notVisible = notVisible?.injectSecrets(env),
)
}
}

data class InputTextCommand(
Expand All @@ -133,6 +162,11 @@ data class InputTextCommand(
return "Input text $text"
}

override fun injectEnv(env: Map<String, String>): InputTextCommand {
return copy(
text = text.injectEnv(env)
)
}
}

data class LaunchAppCommand(
Expand All @@ -148,6 +182,9 @@ data class LaunchAppCommand(
}
}

override fun injectEnv(env: Map<String, String>): LaunchAppCommand {
return this
}
}

data class ApplyConfigurationCommand(
Expand All @@ -157,6 +194,10 @@ data class ApplyConfigurationCommand(
override fun description(): String {
return "Apply configuration"
}

override fun injectEnv(env: Map<String, String>): ApplyConfigurationCommand {
return this
}
}

data class OpenLinkCommand(
Expand All @@ -166,4 +207,10 @@ data class OpenLinkCommand(
override fun description(): String {
return "Open $link"
}

override fun injectEnv(env: Map<String, String>): OpenLinkCommand {
return copy(
link = link.injectEnv(env),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

package maestro.orchestra

import maestro.orchestra.util.Env.injectEnv

data class ElementSelector(
val textRegex: String? = null,
val idRegex: String? = null,
Expand All @@ -37,6 +39,22 @@ data class ElementSelector(
val tolerance: Int? = null,
)

fun injectSecrets(env: Map<String, String>): ElementSelector {
if (env.isEmpty()) {
return this
}

return copy(
textRegex = textRegex?.injectEnv(env),
idRegex = idRegex?.injectEnv(env),
below = below?.injectSecrets(env),
above = above?.injectSecrets(env),
leftOf = leftOf?.injectSecrets(env),
rightOf = rightOf?.injectSecrets(env),
containsChild = containsChild?.injectSecrets(env),
)
}

fun description(): String {
val descriptions = mutableListOf<String>()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package maestro.orchestra.util

object Env {

fun String.injectEnv(env: Map<String, String>): String {
if (env.isEmpty()) {
return this
}

return env
.entries
.fold(this) { acc, (key, value) ->
acc.replace("(?<!\\\\)\\$\\{$key}".toRegex(), value)
}
.replace("\\\\\\$\\{.*}".toRegex()) { match ->
match.value.substringAfter('\\')
}
}

}
83 changes: 57 additions & 26 deletions maestro-orchestra/src/main/java/maestro/orchestra/Orchestra.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,14 @@ class Orchestra(
* If initState is provided, initialize app disk state with the provided OrchestraAppState and skip
* any initFlow execution. Otherwise, initialize app state with initFlow if defined.
*/
fun runFlow(commands: List<MaestroCommand>, initState: OrchestraAppState? = null): Boolean {
fun runFlow(
commands: List<MaestroCommand>,
initState: OrchestraAppState? = null,
env: Map<String, String> = emptyMap(),
): Boolean {
val config = YamlCommandReader.getConfig(commands)
val state = initState ?: config?.initFlow?.let {
runInitFlow(it) ?: return false
runInitFlow(it, env = env) ?: return false
}

if (state != null) {
Expand All @@ -56,15 +60,22 @@ class Orchestra(
}

onFlowStart(commands)
return executeCommands(commands)
return executeCommands(commands, env)
}

/**
* Run the initFlow and return the resulting app OrchestraAppState which can be used to initialize
* app disk state when past into Orchestra.runFlow.
*/
fun runInitFlow(initFlow: MaestroInitFlow): OrchestraAppState? {
val success = runFlow(initFlow.commands, initState = null)
fun runInitFlow(
initFlow: MaestroInitFlow,
env: Map<String, String> = emptyMap(),
): OrchestraAppState? {
val success = runFlow(
initFlow.commands,
initState = null,
env = env,
)
if (!success) return null

maestro.stopApp(initFlow.appId)
Expand All @@ -82,11 +93,14 @@ class Orchestra(
)
}

private fun executeCommands(commands: List<MaestroCommand>): Boolean {
private fun executeCommands(
commands: List<MaestroCommand>,
env: Map<String, String>
): Boolean {
commands.forEachIndexed { index, command ->
onCommandStart(index, command)
try {
executeCommand(command)
executeCommand(command, env)
onCommandComplete(index, command)
} catch (e: Throwable) {
onCommandFailed(index, command, e)
Expand All @@ -96,28 +110,45 @@ class Orchestra(
return true
}

private fun executeCommand(command: MaestroCommand) {
private fun executeCommand(
command: MaestroCommand,
env: Map<String, String>
) {
when {
command.tapOnElement != null -> command.tapOnElement?.let {
tapOnElement(
it,
it.retryIfNoChange ?: true,
it.waitUntilVisible ?: true,
)
}
command.tapOnPoint != null -> command.tapOnPoint?.let {
tapOnPoint(
it,
it.retryIfNoChange ?: true,
)
}
command.tapOnElement != null -> command.tapOnElement
?.injectEnv(env)
?.let {
tapOnElement(
it,
it.retryIfNoChange ?: true,
it.waitUntilVisible ?: true,
)
}
command.tapOnPoint != null -> command.tapOnPoint
?.injectEnv(env)
?.let {
tapOnPoint(
it,
it.retryIfNoChange ?: true,
)
}
command.backPressCommand != null -> maestro.backPress()
command.scrollCommand != null -> maestro.scrollVertical()
command.swipeCommand != null -> command.swipeCommand?.let { swipeCommand(it) }
command.assertCommand != null -> command.assertCommand?.let { assertCommand(it) }
command.inputTextCommand != null -> command.inputTextCommand?.let { inputTextCommand(it) }
command.launchAppCommand != null -> command.launchAppCommand?.let { launchAppCommand(it) }
command.openLinkCommand != null -> command.openLinkCommand?.let { openLinkCommand(it) }
command.swipeCommand != null -> command.swipeCommand
?.injectEnv(env)
?.let { swipeCommand(it) }
command.assertCommand != null -> command.assertCommand
?.injectEnv(env)
?.let { assertCommand(it) }
command.inputTextCommand != null -> command.inputTextCommand
?.injectEnv(env)
?.let { inputTextCommand(it) }
command.launchAppCommand != null -> command.launchAppCommand
?.injectEnv(env)
?.let { launchAppCommand(it) }
command.openLinkCommand != null -> command.openLinkCommand
?.injectEnv(env)
?.let { openLinkCommand(it) }
}
}

Expand Down
Loading

0 comments on commit 5c8d794

Please sign in to comment.