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
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
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
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