Skip to content
This repository has been archived by the owner on Feb 11, 2022. It is now read-only.

PT-429: input scripting #121

Merged
merged 9 commits into from
Jan 25, 2018
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 55 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# gradle-android-command-plugin
gradle-android-command-plugin
=============================
[![](https://ci.novoda.com/buildStatus/icon?job=gradle-android-command-plugin)](https://ci.novoda.com/job/gradle-android-command-plugin/lastSuccessfulBuild/console) [![](https://raw.githubusercontent.com/novoda/novoda/master/assets/btn_apache_lisence.png)](LICENSE.txt) [![Bintray](https://api.bintray.com/packages/novoda/maven/gradle-android-command-plugin/images/download.svg) ](https://bintray.com/novoda/maven/gradle-android-command-plugin/_latestVersion)

Use gradle tasks to run specific `adb` commands.


## Description
Description
-----------

You can use this plugin to do things such as:

Expand All @@ -18,7 +20,8 @@ You can use this plugin to do things such as:
This is particularly useful for CI servers but could be used to speed up development as well.


## Adding to your project
Adding to your project
----------------------

To start using this library, add these lines to the `build.gradle` of your project:

Expand All @@ -37,7 +40,8 @@ buildscript {
```


## Simple usage
Simple usage
------------

The plugin creates new tasks that you can use:

Expand All @@ -53,7 +57,53 @@ The plugin creates new tasks that you can use:

For advanced usage please take a look into the sample project [build.gradle](sample/app/build.gradle) file.

## Links
Configuration
-------------

### Input Scripting

The plugin has a extension called `script` which allows you to do simple scripting automation in a connected device.
Here is an example called `autoLogin` which will input the test username and password into the sample app.

```groovy
scripts {
autoLogin {
execute {
2.times {
text 'bob'
enter()
}
enter()
}
}
}
```

This config will create a gradle task called `autoLogin`. Running `./gradlew autoLogin` will try to input `bob` then press `enter`. This will be done 2 times and then another `enter` will be pressed.

You may have a custom groovy closure to do scripting as you like. The following input methods are available:

```
text(String value)
tap(int x, int y)
swipe(int startX, int startY, int endX, int endY)
key(int code)
home()
back()
up()
down()
left()
right()
clear()
tab()
enter()
power()
unlock()
```


Links
-----

Here are a list of useful links:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public class AndroidCommandPlugin implements Plugin<Project> {
conventionMapping.monkey = { extension.monkey }
}

configureInputScripts(extension, project)

defaultTask (project, 'enableSystemAnimations', 'enables system animations on the connected device', SystemAnimations) {
enable = true
}
Expand All @@ -38,7 +40,17 @@ public class AndroidCommandPlugin implements Plugin<Project> {
}
}

static def defaultTask(Project project, String taskName, String description, Class<? extends AdbTask> taskType, Closure configuration) {
private configureInputScripts(AndroidCommandPluginExtension extension, Project project) {
extension.scripts.all { input ->
project.tasks.create(input.name, Input) {
group = 'adb script'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to have a brand new group called adb script. Suggestions are welcome.

description = "Runs $input.name script on the specified device"
inputSpec = input
}
}
}

static defaultTask(Project project, String taskName, String description, Class<? extends AdbTask> taskType, Closure configuration) {
AdbTask task = project.tasks.create(taskName, taskType)
task.configure configuration
task.group = TASK_GROUP
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.novoda.gradle.command

import groovy.transform.Memoized
import org.gradle.api.Action
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project

public class AndroidCommandPluginExtension {
Expand All @@ -14,6 +15,7 @@ public class AndroidCommandPluginExtension {
private final Project project
private final String androidHome
private final MonkeySpec monkey
private final NamedDomainObjectContainer<InputSpec> scripts

AndroidCommandPluginExtension(Project project) {
this(project, findAndroidHomeFrom(project.android))
Expand All @@ -23,6 +25,7 @@ public class AndroidCommandPluginExtension {
this.project = project
this.androidHome = androidHome
this.monkey = new MonkeySpec()
this.scripts = project.container(InputSpec)
}

def task(String name, Class<? extends AdbTask> type, Closure configuration) {
Expand Down Expand Up @@ -83,6 +86,14 @@ public class AndroidCommandPluginExtension {
monkey
}

void scripts(Closure script) {
scripts.configure(script)
}

NamedDomainObjectContainer<InputSpec> getScripts() {
scripts
}

void attachDefaults(AdbTask task) {
task.conventionMapping.adb = { getAdb() }
task.conventionMapping.aapt = { getAapt() }
Expand Down
35 changes: 25 additions & 10 deletions plugin/src/main/groovy/com/novoda/gradle/command/Input.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,23 @@ import org.gradle.api.tasks.TaskAction

class Input extends AdbTask {

Closure script
InputSpec inputSpec

/**
* Manual creation of Input task is deprecated.
* Please refer to scripting documentation for details:
* https://github.com/novoda/gradle-android-command-plugin#input-scripting
*/
@Deprecated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method has been just added and already deprecated: what's the point of it? 😕
If you want to introduce this change without breaking any public API you should keep all the public methods deleted, mark them as @Deprecated and delegate to the InputSpec instead. Other choice will be to annotate the script field as @Delegate and let Groovy do its magic, but then the users won't have any notion of deprecation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to deprecate the field script because now it is a proper input that I use. It is now used when the task is created in the plugin.

Before we had Closure script. With gradle magic, when the user creates a new task with type Input, they could use script like below (which looks like a method call)

This method is now introduced to support that the old behavior.

task autoLogin(type: com.novoda.gradle.command.Input) {
     script {
    }
}

I didn't want to keep all the methods because that would cause a lot of duplication. I know that it is not ideal but with this we are 100% backward compatible.

I will look into @Delegate. I guess with that I can just remove this method. I would have to remove deprecation but it is not really super visible anyways.

Copy link
Contributor

@mr-archano mr-archano Feb 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're talking from the perspective of the sample we provide, not the real public API: if you remove public methods you're introducing breaking changes, right? Duplication in this case is not correct, because you will not duplicate the implementation, will just be tedious to make those method to use delegation instead. I feel we can bare with that as long as we have a proper strategy to move forward :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's very true :)
Then Delegate seems to be a logical way to do it.

void setScript(Closure script) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a new method deprecated but it really is the existing property being converted to write-only property and deprecated. Here is what I want to achieve.

Existing implementations will mark it as deprecated.

screen shot 2018-01-08 at 11 25 27 am

logger.warn """\
Manual creation of Input task is deprecated.
Please refer to scripting documentation to modify your task '$name'
https://github.com/novoda/gradle-android-command-plugin#input-scripting
""".stripIndent()
inputSpec = new InputSpec()
inputSpec.script = script
}

void text(String value) {
input('text', "$value")
Expand All @@ -21,11 +37,11 @@ class Input extends AdbTask {
void key(int code) {
input('keyevent', code)
}

void home() {
key 3
}

void back() {
key 4
}
Expand All @@ -37,7 +53,7 @@ class Input extends AdbTask {
void down() {
key 20
}

void left() {
key 21
}
Expand All @@ -49,15 +65,15 @@ class Input extends AdbTask {
void power() {
key 26
}

void clear() {
key 28
}

void tab() {
key 61
}

void enter() {
key 66
}
Expand All @@ -67,14 +83,13 @@ class Input extends AdbTask {
}

private input(... values) {
def command = ["shell", "input"]
command.addAll(values)
runCommand(command)
runCommand(['shell', 'input', *values])
}

@TaskAction
void exec() {
assertDeviceConnected()
script.call()
inputSpec.script.delegate = this
inputSpec.script.call()
}
}
16 changes: 16 additions & 0 deletions plugin/src/main/groovy/com/novoda/gradle/command/InputSpec.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.novoda.gradle.command

class InputSpec {

String name
Closure script

InputSpec(name) {
this.name = name
}

void execute(script) {
this.script = script
}

}
16 changes: 11 additions & 5 deletions sample/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,19 @@ android {
}
}

task autoLogin(type: com.novoda.gradle.command.Input) {
script {
2.times {
text 'bob'
scripts {
autoLogin {
execute {
2.times {
text 'bob'
enter()
}
enter()
}
enter()
}

pressBack.execute {
back()
}
}

Expand Down