Project Setup
Continuous Integration
Tests should run on Drone as part of the build process.
Steps to run on Drone:
- Create a .drone.yml at the root of the project
- Create a .drone.sec file on drone for any necessary secrets (These will not be available to the build step)
build:
image: registry.vokal.io/android
volumes:
- /home/ubuntu/android_build/android-sdk:/usr/local/android-sdk
- /home/ubuntu/.android:/root/.android
commands:
- ./gradlew build deviceCheck
- curl -sSL https://secure.vokal.io/new | sh
publish:
script:
image: vokal/drone-android-publish
apiToken: $$hockeyApiToken
path: app/build/outputs/apk/<name of debug>.apk
Artifactory Setup
- Some projects will require private or staging versions of internal projects.
To handle this we can add our local artifactory to our build step. - Add your artifactory user and password to the ~/.gradle/gradle.properties file
artifactory_user=[insert user provided]
artifactory_passord=[insert password provided]
- Add your maven repository to either the buildScript or your project repos
- For buildScript, replace with
plugins-release
- For project dependencies, replace with
libs-release
...
jcenter()
maven {
url 'http://artifactory.vokal.io/artifactory/<repository>'
credentials {
username = "${artifactory_user}"
password = "${artifactory_password}"
}
}
Ktlint
We automate our code style review using Ktlint. We ensure our code meets the standard style guidelines
by running it specially before our final commit prior to making a Git pull request
. Ktlint
notifies if our code passes or fails and where we need to amend for changes. Once we update our code and it passes then we can commit and make a pull request
.
How to install Ktlint
using Kotlin Gradle
plugin.
repositories {
jcenter()
}
val ktlint by configurations.creating
dependencies {
ktlint("com.pinterest:ktlint:$ktLintVersion")
}
tasks.create<JavaExec>("ktlint") {
group = "verification"
val outputDir = "${project.buildDir}/reports/ktlint/"
val outputFile = "${outputDir}ktlint-checkstyle-report.xml"
val inputFiles = project.fileTree(
mapOf(
"dir" to "src",
"include" to "**/*.kt"
)
)
inputs.files(inputFiles)
outputs.files(outputFile)
description = "Check Kotlin code style."
main = "com.pinterest.ktlint.Main"
classpath = configurations.getByName("ktlint")
args = listOf(
"--reporter=plain",
"--reporter=checkstyle,output=${outputFile}",
"src/**/*.kt",
"--verbose"
)
// to generate report in checkstyle format prepend following args:
// "--reporter=plain", "--reporter=checkstyle,output=${buildDir}/ktlint.xml"
// see https://github.com/pinterest/ktlint#usage for more
}
tasks.getByName("check").dependsOn("ktlint")
How to install Ktlint
using Gradle
repositories {
jcenter()
}
configurations {
ktlint
}
dependencies {
ktlint "com.pinterest:ktlint:$ktLintVersion"
}
task ktlint(type: JavaExec, group: "verification") {
def outputDir = "${project.buildDir}/reports/ktlint/"
def outputFile = "${outputDir}ktlint-checkstyle-report.xml"
def inputFiles = project.fileTree(dir: "src", include: "**/*.kt")
inputs.files(inputFiles)
outputs.files(outputDir)
description = "Check Kotlin code style."
main = "com.pinterest.ktlint.Main"
classpath = configurations.ktlint
args = [
"--reporter=plain",
"--reporter=checkstyle,output=${outputFile}",
"src/**/*.kt",
"--verbose"
]
// to generate report in checkstyle format prepend following args:
// "--reporter=plain", "--reporter=checkstyle,output=${buildDir}/ktlint.xml"
// see https://github.com/pinterest/ktlint#usage for more
}
check.dependsOn ktlint
Also attach .editorconfig
at the root of your project
[*.{kt,kts}]
# possible values: number (e.g. 2), "unset" (makes ktlint ignore indentation completely)
indent_size=4
# possible values: number (e.g. 2), "unset"
continuation_indent_size=4
# true (recommended) / false
insert_final_newline=true
# possible values: number (e.g. 120) (package name, imports & comments are ignored), "off"
# it's automatically set to 100 on `ktlint --android ...` (per Android Kotlin Style Guide)
max_line_length=100
Gradle
Our Gradle setup has been written in Groovy and new projects will be written in Kotlin baserd on Kotlin DSL
Version Code Automation
Each time an Android project is committed in Git, its versionCode can be updated based on generateVersionCode()
Kotlin:
android {
defaultConfig {
versionCode = generateVersionCode()
}
}
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.Reader
fun generateVersionCode(): Int {
val result = "rev-list HEAD --count".git()
if (result.isEmpty()) {
throw RuntimeException("Could not generate versioncode. See if you have git installed.")
}
return result.toInt()
}
fun String.git(): String {
var result = "git $this".execute()
if (result.isEmpty()) {
// windows
result = "PowerShell -Command git $this".execute()
}
return result
}
fun String.execute(): String {
return try {
val process = Runtime.getRuntime().exec(this)
val inputStream = process.inputStream
val inputStreamReader: Reader = InputStreamReader(inputStream, "utf-8")
val bufferedReader = BufferedReader(inputStreamReader)
bufferedReader.readLine().trim()
} catch (e: Exception) {
""
}
}
Groovy:
android {
defaultConfig {
versionCode generateVersionCode()
}
}
static def generateVersionCode() {
// unix
def result = "git rev-list HEAD --count".execute().text.trim()
if(result.empty) {
// windows
result = "PowerShell -Command git rev-list HEAD --count".execute().text.trim()
}
if(result.empty) {
throw new RuntimeException("Could not generate versioncode. See if you have git installed")
}
return result.toInteger()
}