Get Things Done with Gradle Custom Tasks Daily workflow 1. Merpay: ⌨ Code and Verify 2. Merpay: Git Push 3. Merpay: Build and Deploy the artifact 4. Mercari: Update the Merpay artifact for integration Shibuya.apk #36 3
Get Things Done with Gradle Custom Tasks Mainstream Workflow ▸ Install dependencies ▸ Test ▸ Assemble / Collect test coverage ▸ Deploy the artifacts Shibuya.apk #36 9
Get Things Done with Gradle Custom Tasks Branches Workflow ▸ Install dependencies ▸ Assemble and test debug and release variants ▸ Collect test coverage / Static code analysis Shibuya.apk #36 10
Get Things Done with Gradle Custom Tasks Tags Workflow ▸ Install dependencies ▸ Test ▸ Assemble ▸ Deploy ▸ Execute a Gradle Custom Task: Open a pull request in Mercari repository Shibuya.apk #36 11
Get Things Done with Gradle Custom Tasks Protobuf Update Workflow ▸ Execute a Gradle Custom Task: Overwrite the version with the latest one Shibuya.apk #36 12
Get Things Done with Gradle Custom Tasks Release Branch Merge Workflow ▸ Execute a Gradle Custom Task: git merge and push to create a pull request Shibuya.apk #36 13
Get Things Done with Gradle Custom Tasks Gradle Custom Tasks ▸ A step for a workflow ▸ Open a pull request in Mercari repository ▸ Overwrite the version with the latest one ▸ git merge and push to create a pull request ▸ Static code analysis result aggregation Shibuya.apk #36 14
Get Things Done with Gradle Custom Tasks Steps to make Gradle Custom Tasks work 1. Put a custom task implementation under buildSrc 2. Register the custom task in build.gradle of project root 3. Run the Gradle command! Shibuya.apk #36 15
Get Things Done with Gradle Custom Tasks Implement your Gradle custom task in Kotlin open class MyCustomTask : DefaultTask() { @Input lateinit var parameter: String @TaskAction fun execute() { println(parameter) } } 18 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Class needs to be open open class MyCustomTask : DefaultTask() { @Input lateinit var parameter: String @TaskAction fun execute() { println(parameter) } } 19 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Extends DefaultTask open class MyCustomTask : DefaultTask() { @Input lateinit var parameter: String @TaskAction fun execute() { println(parameter) } } 20 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Task parameter with @Input annotation open class MyCustomTask : DefaultTask() { @Input lateinit var parameter: String @TaskAction fun execute() { println(parameter) } } 21 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Task body with @TaskAction open class MyCustomTask : DefaultTask() { @Input lateinit var parameter: String @TaskAction fun execute() { println(parameter) } } 22 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Registering the custom task // build.gradle.kts in the project root tasks.register(“myTask”) { parameter = “Hello, World!” } 23 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Have a name of your custom task: “myTask” // build.gradle.kts in the project root tasks.register(“myTask”) { parameter = “Hello, World!” } 24 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Set the parameter values // build.gradle.kts in the project root tasks.register(“myTask”) { parameter = “Hello, World!” } 25 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Registering the custom task // build.gradle.kts in the project root tasks.register(“myTask”) { group = “Greeting” description = “Print a greeting message” parameter = “Hello, World!” } 27 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Example: aggregateLintReport ▸ Premise: ▸ Multiple Android modules inside the project ▸ Requirements: ▸ Collect all the Lint report and unify them ▸ Usage: ▸ $ ./gradlew lint aggregateLintReport Shibuya.apk #36 30
Get Things Done with Gradle Custom Tasks Example: aggregateLintReport ▸ Dependencies: ▸ Writers in java.io package ▸ XML utilities in groovy.util package Shibuya.apk #36 31
Get Things Done with Gradle Custom Tasks Example: aggregateLintReport open class AndroidLintReportAggregation : DefaultTask() { @TaskAction fun aggregate() { // 1. Collect all Lint report files // 2. Create a file for aggregation // 3. Copy nodes in each file to aggregated file // 4. Print the aggregated file path } } 32 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Example: aggregateLintReport @TaskAction fun aggregate() { // 2. Create a file for aggregation val aggregatedFile = File(“${project.rootDir}/result.xml”) if (aggregatedFile.exists().not()) { aggregatedFile.createNewFile())( } } 34 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Example: aggregateLintReport @TaskAction fun aggregate() { // 3. Copy nodes in each file to aggregated file val printer = XmlNodePrinter( PrintWriter(FileWriter(aggregatedFile)) ).apply { write(“\n”) } printer.isExpandEmptyElements = true } 35 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Example: aggregateLintReport @TaskAction fun aggregate() { // 3. Copy nodes in each file to aggregated file val rootNode = Node( null, “issues”, mapOf(“format” to “5”, “by” to “lint 3.4.0”) ) } 36 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Example: aggregateLintReport @TaskAction fun aggregate() { // 3. Copy nodes in each file to aggregated file val rootNode = // …… reports.forEach { report -> val elements = XmlParser().parse(report).children() if (elements.isEmpty()) { return@forEach } } } 37 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Example: aggregateLintReport @TaskAction fun aggregate() { // 3. Copy nodes in each file to aggregated file val rootNode = // …… reports.forEach { report -> val elements = // …… elements.map { element -> if (element !is Node) { return@map } rootNode.append(element) } } } 38 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Example: aggregateLintReport @TaskAction fun aggregate() { // 3. Copy nodes in each file to aggregated file val rootNode = // …… // …… printer.print(rootNode) } 39 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Example: aggregateLintReport @TaskAction fun aggregate() { // 4. Print the aggregated file path println(“Aggregated to ${aggregatedFile.absolutePath}”) } 40 Shibuya.apk #36
Get Things Done with Gradle Custom Tasks Example: aggregateLintReport - What’s good? ▸ No change on static code analysis configuration when you have a new module ▸ e.g. Danger to report the Lint issues Shibuya.apk #36 41 android_lint.report_file = “./reports.xml” android_lint.filtering = true android_lint.lint(inline_mode: true)
Get Things Done with Gradle Custom Tasks Steps to make Gradle Custom Tasks work 1. Put a custom task implementation under buildSrc 2. Register the custom task in build.gradle of project root 3. Run the Gradle command! Shibuya.apk #36 42
Get Things Done with Gradle Custom Tasks Some Discussions ▸ Is it OK to do some Network I/O? ▸ Definitely! ▸ You can enhance your task with Web APIs (e.g. GitHub API, CircleCI API) ▸ Can I use Git commands from the task? ▸ Yes! ▸ Use org.eclipse.jgit library to make it easier Shibuya.apk #36 43