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.

Bbe9718bebdafbdc8dabbe3cadf1bc46?s=128

Keishin Yokomaku

August 01, 2019
Tweet

Transcript

  1. Get Things Done with Gradle Custom Tasks Keishin Yokomaku (@KeithYokoma)

    Shibuya.apk #36
  2. 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
  3. 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
  4. 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/*
  5. Get Things Done with Gradle Custom Tasks Continuous Integration Shibuya.apk

    #36 5
  6. 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
  7. 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
  8. 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
  9. Get Things Done with Gradle Custom Tasks Mainstream Workflow ▸

    Install dependencies ▸ Test ▸ Assemble / Collect test coverage ▸ Deploy the artifacts Shibuya.apk #36 9
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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
  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 = Node( null, “issues”, mapOf(“format” to “5”, “by” to “lint 3.4.0”) ) } 36 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 = // …… reports.forEach { report -> val elements = XmlParser().parse(report).children() if (elements.isEmpty()) { return@forEach } } } 37 Shibuya.apk #36
  38. 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
  39. 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
  40. 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
  41. 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)
  42. 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
  43. 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
  44. Get Things Done with Gradle Custom Tasks Keishin Yokomaku (@KeithYokoma)

    Shibuya.apk #36