Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Get Things Done with Gradle Custom Tasks

Get Things Done with Gradle Custom Tasks

Get the job done automatically with Gradle Custom Tasks on the CI.

Keishin Yokomaku

August 01, 2019
Tweet

More Decks by Keishin Yokomaku

Other Decks in Technology

Transcript

  1. Get Things Done with Gradle Custom Tasks About Me ▸

    Keishin Yokomaku ▸ @KeithYokoma: GitHub / Twitter / Qiita / Stack Overflow ▸ Merpay, Inc. / Engineer ▸ Fun: Gymnastics / Cycling / Photography / Motorsport / Camping Shibuya.apk #36 2
  2. 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
  3. Get Things Done with Gradle Custom Tasks Daily workflow 1.

    Feature Development ▸ Merging feature branches into master 2. QA ▸ Merging bugfix branches into release/* Shibuya.apk #36 4 master release/*
  4. Get Things Done with Gradle Custom Tasks Continuous Integration ▸

    CircleCI 2.1 ▸ Docker: the first-class citizen ▸ Configuration as a Code ▸ Flexible workflow definitions ▸ Git triggers ▸ Nightly Shibuya.apk #36 6
  5. Get Things Done with Gradle Custom Tasks Continuous Integration ▸

    CircleCI 2.1 - Workflow with git triggers ▸ Mainstream: master and release/* ▸ Branches: feature / topic branches ▸ Tags: git tags Shibuya.apk #36 7
  6. Get Things Done with Gradle Custom Tasks Continuous Integration ▸

    CircleCI 2.1 - Nightly Workflow ▸ Protobuf update: 12:00 and 19:00 JST every weekdays ▸ Release branch merge: 12:00 and 19:00 JST every weekdays Shibuya.apk #36 8
  7. Get Things Done with Gradle Custom Tasks Mainstream Workflow ▸

    Install dependencies ▸ Test ▸ Assemble / Collect test coverage ▸ Deploy the artifacts Shibuya.apk #36 9
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. Get Things Done with Gradle Custom Tasks Prep for buildSrc

    ▸ Project Root/buildSrc ▸ build.gradle.kts ▸ src ▸ main ▸ java ▸ com.your.package Shibuya.apk #36 16
  15. Get Things Done with Gradle Custom Tasks Prep for buildSrc

    // build.gradle.kts under buildSrc directory repositories { jcenter() } plugins { `kotlin-dsl` `java-gradle-plugin` } dependencies { implementation(gradleApi()) } 17 Shibuya.apk #36
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. Get Things Done with Gradle Custom Tasks Registering the custom

    task // build.gradle.kts in the project root tasks.register<MyCustomTask>(“myTask”) { parameter = “Hello, World!” } 23 Shibuya.apk #36
  22. Get Things Done with Gradle Custom Tasks Have a name

    of your custom task: “myTask” // build.gradle.kts in the project root tasks.register<MyCustomTask>(“myTask”) { parameter = “Hello, World!” } 24 Shibuya.apk #36
  23. Get Things Done with Gradle Custom Tasks Set the parameter

    values // build.gradle.kts in the project root tasks.register<MyCustomTask>(“myTask”) { parameter = “Hello, World!” } 25 Shibuya.apk #36
  24. Get Things Done with Gradle Custom Tasks Check your task

    $ ./gradlew tasks …… Android Tasks ————— …… Build Tasks ————— …… BUILD SUCCESSFUL in 7s 1 actionable task: 1 executed 26 Shibuya.apk #36
  25. Get Things Done with Gradle Custom Tasks Registering the custom

    task // build.gradle.kts in the project root tasks.register<MyCustomTask>(“myTask”) { group = “Greeting” description = “Print a greeting message” parameter = “Hello, World!” } 27 Shibuya.apk #36
  26. Get Things Done with Gradle Custom Tasks Check your task

    $ ./gradlew tasks …… Android Tasks ————— …… Greeting Tasks ————— myTask - Print a greeting message …… BUILD SUCCESSFUL in 7s 1 actionable task: 1 executed 28 Shibuya.apk #36
  27. Get Things Done with Gradle Custom Tasks Run! $ ./gradlew

    myTask > Task: myTask Hello, World! BUILD SUCCESSFUL in 1s 1 actionable task: 1 executed 29 Shibuya.apk #36
  28. 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
  29. 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
  30. 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 <issue> nodes in each file to aggregated file // 4. Print the aggregated file path } } 32 Shibuya.apk #36
  31. Get Things Done with Gradle Custom Tasks Example: aggregateLintReport @TaskAction

    fun aggregate() { // 1. Collect all Lint report files val reports = project.subprojects.map { subproject -> File(“${subproject.buildDir.absolutePath}/reports”) }.map { dir -> dir.walk().find { file -> file.name == “lint-results.xml” } }.filterNotNull() } 33 Shibuya.apk #36
  32. 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
  33. Get Things Done with Gradle Custom Tasks Example: aggregateLintReport @TaskAction

    fun aggregate() { // 3. Copy <issue> nodes in each file to aggregated file val printer = XmlNodePrinter( PrintWriter(FileWriter(aggregatedFile)) ).apply { write(“<?xml version=‘1.0’ encoding=‘UTF-8’ ?>\n”) } printer.isExpandEmptyElements = true } 35 Shibuya.apk #36
  34. Get Things Done with Gradle Custom Tasks Example: aggregateLintReport @TaskAction

    fun aggregate() { // 3. Copy <issue> 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
  35. Get Things Done with Gradle Custom Tasks Example: aggregateLintReport @TaskAction

    fun aggregate() { // 3. Copy <issue> 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
  36. Get Things Done with Gradle Custom Tasks Example: aggregateLintReport @TaskAction

    fun aggregate() { // 3. Copy <issue> 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
  37. Get Things Done with Gradle Custom Tasks Example: aggregateLintReport @TaskAction

    fun aggregate() { // 3. Copy <issue> nodes in each file to aggregated file val rootNode = // …… // …… printer.print(rootNode) } 39 Shibuya.apk #36
  38. 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
  39. 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)
  40. 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
  41. 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