Slide 1

Slide 1 text

Kotlin Ͱॻ͘
 Gradle Custom Tasks KeithYokoma (Keishin Yokomaku) / shuuu-mai

Slide 2

Slide 2 text

Kotlin Ͱॻ͘ Gradle Custom Tasks About Me ▸ Keishin Yokomaku ▸ @KeithYokoma: GitHub / Twitter / Qiita / Stack Overflow ▸ Merpay, Inc. / Engineer ▸ Fun: Gymnastics / Cycling / Photography / Motorsport / Camping shuuu-mai 2

Slide 3

Slide 3 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Tasks 3 $ ./gradlew assembleDebug testDebugUnitTest ktlintDebug shuuu-mai

Slide 4

Slide 4 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Tasks 4 $ ./gradlew assembleDebug testDebugUnitTest ktlintDebug shuuu-mai

Slide 5

Slide 5 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Tasks 5 $ ./gradlew assembleDebug testDebugUnitTest ktlintDebug main sourceSet Λ debug variant ͰίϯύΠϧ͠ apk Λੜ੒͢Δ shuuu-mai

Slide 6

Slide 6 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Tasks 6 $ ./gradlew assembleDebug testDebugUnitTest ktlintDebug test sourceSet ʹ͋Δ Unit Test Λ debug variant Ͱ࣮ߦ͢Δ shuuu-mai

Slide 7

Slide 7 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Tasks 7 $ ./gradlew assembleDebug testDebugUnitTest ktlintDebug ktlint Λ debug variant Ͱ࣮ߦ͢Δ shuuu-mai

Slide 8

Slide 8 text

Kotlin Ͱॻ͘ Gradle Custom Tasks General use of Gradle Tasks ▸ Build setup ▸ clean, init, etc… ▸ Compile the source and generate artifacts ▸ assemble, jar, etc… ▸ Verification ▸ test, lint, etc… 8 shuuu-mai

Slide 9

Slide 9 text

Kotlin Ͱॻ͘ Gradle Custom Tasks What we can do with Gradle Custom Tasks? ▸ Whatever you want! ▸ Access to Web APIs ▸ Git operations ▸ File I/O 9 shuuu-mai

Slide 10

Slide 10 text

Kotlin Ͱॻ͘ Gradle Custom Tasks What we can do with Gradle Custom Tasks? ▸ Whatever you want! ▸ Access to Web APIs ▸ Git operations ▸ File I/O 10 shuuu-mai = Automation!

Slide 11

Slide 11 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Case Study: What we do with Gradle Custom Tasks 1. Keep the master up-to-date with the latest release branch ‣ Daily feature development: master ‣ Bug-fixes: release/* ‣ release/* may conflict with master… shuuu-mai 11 master release/*

Slide 12

Slide 12 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Case Study: What we do with Gradle Custom Tasks 1. Keep the master up-to-date with the latest release branch ‣ Daily feature development: master ‣ Bug-fixes: release/* ‣ release/* may conflict with master… Resolve it as early as possible! shuuu-mai 12 master release/*

Slide 13

Slide 13 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Declare a new Gradle Task ▸ In the build script ▸ In buildSrc ▸ Standalone project 13 shuuu-mai

Slide 14

Slide 14 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Declare a new Gradle Task ▸ In the build script: one-off task for a single build script ▸ In buildSrc ▸ Standalone project 14 shuuu-mai

Slide 15

Slide 15 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Declare a new Gradle Task ▸ In the build script: one-off task for a single build script ▸ In buildSrc: Commonly-used task among multiple build scripts ▸ Standalone project 15 shuuu-mai

Slide 16

Slide 16 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Declare a new Gradle Task ▸ In the build script: one-off task for a single build script ▸ In buildSrc: Commonly-used task among multiple build scripts ▸ Standalone project: Generates sharable jar artifact of Gradle Tasks 16 shuuu-mai

Slide 17

Slide 17 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks with buildSrc ▸ Create buildSrc directory under the project root ▸ src for Gradle Custom Tasks source code ▸ build.gradle.kts for buildSrc configuration ▸ dependencies of Gradle Custom Tasks 17 shuuu-mai

Slide 18

Slide 18 text

Kotlin Ͱॻ͘ Gradle Custom Tasks buildSrc/build.gradle.kts repositories { jcenter() } plugins { `kotlin-dsl` `java-gradle-plugin` } dependencies { implementation(gradleApi()) } shuuu-mai

Slide 19

Slide 19 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Getting Started ▸ Gradle Custom Task class ▸ Must be open class ▸ Extends DefaultTask ▸ Task function is annotated with @TaskAction 19 shuuu-mai

Slide 20

Slide 20 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Getting Started import org.gradle.api.DefaultTask import org.gradle.api.tasks.TaskAction open class MyCustomTask : DefaultTask() { @TaskAction fun sayHello() { println("Hello") } } shuuu-mai

Slide 21

Slide 21 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Getting Started import org.gradle.api.DefaultTask import org.gradle.api.tasks.TaskAction open class MyCustomTask : DefaultTask() { @TaskAction fun sayHello() { println("Hello") } } shuuu-mai

Slide 22

Slide 22 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Getting Started import org.gradle.api.DefaultTask import org.gradle.api.tasks.TaskAction open class MyCustomTask : DefaultTask() { @TaskAction fun sayHello() { println("Hello") } } shuuu-mai

Slide 23

Slide 23 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Getting Started import org.gradle.api.DefaultTask import org.gradle.api.tasks.TaskAction open class MyCustomTask : DefaultTask() { @TaskAction fun sayHello() { println("Hello") } } shuuu-mai

Slide 24

Slide 24 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Task registration in the root build.grdle.kts 24 shuuu-mai tasks.register("myCustomTask") { group = "Sample Group" description = "Print Hello" } // $ ./gradlew tasks // Sample Group tasks // ------------------ // myCustomTask - Print Hello

Slide 25

Slide 25 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Task registration in the root build.grdle.kts 25 shuuu-mai tasks.register("myCustomTask") { group = "Sample Group" description = "Print Hello" } // $ ./gradlew tasks // Sample Group tasks // ------------------ // myCustomTask - Print Hello

Slide 26

Slide 26 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Task registration in the root build.grdle.kts 26 shuuu-mai tasks.register("myCustomTask") { group = "Sample Group" description = "Print Hello" } // $ ./gradlew tasks // Sample Group tasks // ------------------ // myCustomTask - Print Hello

Slide 27

Slide 27 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Task registration in the root build.grdle.kts 27 shuuu-mai tasks.register("myCustomTask") { group = "Sample Group" description = "Print Hello" } // $ ./gradlew myCustomTask // > Task: myCustomTask // Hello

Slide 28

Slide 28 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Options ▸ Gradle Custom Task class ▸ lateinit variable with @Input ▸ Get a CLI option from properties field in the project root build.gradle.kts 28 shuuu-mai

Slide 29

Slide 29 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Declare input variable import org.gradle.api.DefaultTask import org.gradle.api.tasks.TaskAction open class MyCustomTask : DefaultTask() { @Input lateinit var personName: String @TaskAction fun sayHello() { println("Hello, $personName") } } shuuu-mai

Slide 30

Slide 30 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Read options 30 shuuu-mai tasks.register("myCustomTask") { group = "Sample Group" description = "Print Hello" personName = properties["personName"] as String? ?: "noname" } // $ ./gradlew myCustomTask -PpersonName=keithyokoma // > Task: myCustomTask // Hello, keithyokoma

Slide 31

Slide 31 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Case Study: Daily release branch merge into master 1. Workflow ‣ Pull all the updates ‣ Checkout a wokring branch for merging from a release branch ‣ Create a merge commit, push and open a pull request shuuu-mai 31

Slide 32

Slide 32 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Case Study: Daily release branch merge into master 2. What we need ‣ GitHub API token ‣ A library to execute Git operations and GitHub API calls ‣ e.g. JGit for Git operations ‣ e.g. github-api for GitHub API calls ‣ e.g. jsemver for comparing semantic version shuuu-mai 32

Slide 33

Slide 33 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Case Study: Daily release branch merge into master 3. What the command looks like? shuuu-mai 33 ./gradlew mergeReleaseToMaster -PgithubToken=$GITHUB_API_TOKEN

Slide 34

Slide 34 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Prepare Git open class DailyMergeTask : DefaultTask() { @Input lateinit var token: String @TaskAction fun merge() { val git = FileRepositoryBuilder() .setGitDir(File("${project.rootDir}/.git")) .build() .let(::Git) } } shuuu-mai

Slide 35

Slide 35 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Prepare Git open class DailyMergeTask : DefaultTask() { @Input lateinit var token: String @TaskAction fun merge() { // … val provider = UsernamePasswordCredentialsProvider( "token", token ) } } shuuu-mai

Slide 36

Slide 36 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Get the latest releae branch open class DailyMergeTask : DefaultTask() { @Input lateinit var token: String @TaskAction fun merge() { // … // mostly equivalent: $ git branch -a --sort=committerdate | grep "release/" val branch = git.lsRemote() .setCredentialProvider(provider) .call() .filter { ref -> ref.name.contains("release/") }.sortedBy { ref -> val versionName = ref.name.replace("refs/heads/release/", "") Version.valueOf(versionName) }.last() // alternative: maxBy {} } } shuuu-mai

Slide 37

Slide 37 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Create a working branch open class DailyMergeTask : DefaultTask() { @Input lateinit var token: String @TaskAction fun merge() { // … // equivalent: $ git checkout -b ci/$version_to_master val version = releaseBranch.name.replace("refs/heads/release/", "") val workingBranch = "ci/$version_to_master" // Ext method to create a new branch (delete existing one if any) and checkout git.createAndCheckout(workingBranch) } } shuuu-mai

Slide 38

Slide 38 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Checkout release branch open class DailyMergeTask : DefaultTask() { @Input lateinit var token: String @TaskAction fun merge() { // … // equivalent: $ git fetch origin && git branch -f release/$version origin/release/$version git.fetch() .setCredentialProvider(provider) .call() val releaseBranch = branch.name.replace("refs/heads/", "") val releaseBranchRef = git.branchCreate() .setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.SET_UPSTREAM) .setName(branchName) .setStartPoint("origin/$releaseBranch") .setForce(true) .call() } } shuuu-mai

Slide 39

Slide 39 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Create a merge commit on the working branch open class DailyMergeTask : DefaultTask() { @Input lateinit var token: String @TaskAction fun merge() { // … // equivalent: $ git merge —no-ff release/$version val mergeResult = git.merge() .include(releaseBranchRef) .setFastForward(MergeCommand.FastForwardMode.NO_FF) .setMessage("CI Merge $releaseBranch") .call() } } shuuu-mai

Slide 40

Slide 40 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Check if any conflicts open class DailyMergeTask : DefaultTask() { @Input lateinit var token: String @TaskAction fun merge() { // … val status = mergeResult.mergeStatus if (!status.isSuccessful && status == CONFLICTING) { throw IllegalStateException(mergeResult.message) } } } shuuu-mai

Slide 41

Slide 41 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Push if succeeds open class DailyMergeTask : DefaultTask() { @Input lateinit var token: String @TaskAction fun merge() { // … // equivalent: $ git push --force-with-rease origin ci/$version_to_master git.push() .setForce(true) .setCredentialProvider(provider) .call() } } shuuu-mai

Slide 42

Slide 42 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Gradle Custom Tasks: Push if succeeds open class DailyMergeTask : DefaultTask() { @Input lateinit var token: String @TaskAction fun merge() { // … // equivalent: $ hub pull-request GitHub.connectUsingOAuth(token) .getRepository("user_name/repository_name") .createPullRequest( "[CI] Daily merge from $releaseBranch to master", workingBranch, "master", "Automatically created pull request!" ) } } shuuu-mai

Slide 43

Slide 43 text

Kotlin Ͱॻ͘ Gradle Custom Tasks Wrap up: General use of Gradle Tasks ▸ Automate the stuff you are doing in daily basis with Gradle Custom Tasks. ▸ A Gradle Custom Task can handle File and/or Network I/O. ▸ No need to consider some kind of AsyncTask. ▸ And… you can write unit tests on Gradle Custom Tasks. :) 43 shuuu-mai

Slide 44

Slide 44 text

Kotlin Ͱॻ͘
 Gradle Custom Tasks KeithYokoma (Keishin Yokomaku) / shuuu-mai