Hi, I’m new to Kotlin, Gradle and build.gradle.kts
I’d like to add the git hash to the version number (e.g. “0.8.2-a7b3d”) and use this constant in my Kotlin/jvm project.
I found about a dozen howtos for Java/Android but non for build.gradle.kts
(also searching for “git hash” in any combination with other words seams to include a lot of “noise”).
Please point me into the right direction!
Something like this but for build.gradle.kts
// from https://stackoverflow.com/a/64311102
import kotlinx.cinterop.*
import platform.posix.*
fun executeCommand(
command: String,
trim: Boolean = true,
redirectStderr: Boolean = true
): String {
val commandToExecute = if (redirectStderr) "$command 2>&1" else command
val fp = popen(commandToExecute, "r") ?: error("Failed to run command: $command")
val stdout = buildString {
val buffer = ByteArray(4096)
while (true) {
val input = fgets(buffer.refTo(0), buffer.size, fp) ?: break
append(input.toKString())
}
}
val status = pclose(fp)
if (status != 0) {
error("Command `$command` failed with status $status${if (redirectStderr) ": $stdout" else ""}")
}
return if (trim) stdout.trim() else stdout
}
fun main() {
println("Git Info in local directory:")
println(executeCommand("git rev-parse --abbrev-ref HEAD"))
println(executeCommand("git tag -l --points-at HEAD"))
println(executeCommand("git rev-parse --short=8 HEAD"))
}
i’ve got this in my code, although i’m not sure where org.apache.commons stuff is coming from:
fun versionBanner(): String {
val os = org.apache.commons.io.output.ByteArrayOutputStream()
project.exec {
commandLine = "git describe --long".split(" ")
standardOutput = os
}
return String(os.toByteArray()).trim()
}
I have this extension function for my gradle builds
fun String.runCommand(
workingDir: File = File("."),
timeoutAmount: Long = 60,
timeoutUnit: TimeUnit = TimeUnit.SECONDS
): String = ProcessBuilder(split("\\s(?=(?:[^'\"`]*(['\"`])[^'\"`]*\\1)*[^'\"`]*$)".toRegex()))
.directory(workingDir)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start()
.apply { waitFor(timeoutAmount, timeoutUnit) }
.run {
val error = errorStream.bufferedReader().readText().trim()
if (error.isNotEmpty()) {
throw IOException(error)
}
inputStream.bufferedReader().readText().trim()
}
and then you can call it like
"git rev-list --count HEAD".runCommand(workingDir = rootDir)
1 Like
Hi @oakkitten, thank you for your reply!
Where (in build.gradle.kts
?) do I put this?
How can I add this to version
? Like this:
plugins {
kotlin("multiplatform") version "1.4.10"
}
group = "me.eugen"
version = "1.0-" + versionBanner()
repositories {
mavenCentral()
}
kotlin {
...
1 Like
Hi @chrimaeon, thank you for your reply!
Where (in build.gradle.kts
?) do I put this?
How can I add this to version
? Like this:
plugins {
kotlin("multiplatform") version "1.4.10"
}
group = "me.eugen"
version = "1.0-" + "git rev-list --count HEAD".runCommand("./")
repositories {
mavenCentral()
}
kotlin {
...
well i have this as a top-level function. git describe --long
will give you version as well as long as you are using tags, e.g. you can get something like v1.2-119-g17dd14b7
. as to how you use that, that’s up to you; i’m doing android so i’m using
android {
defaultConfig {
buildConfigField("String", "VERSION", "\"${versionBanner()}\"")
...
and then i use that in the about window.
1 Like
I found a (temporary?) solution:
build.gradle.kts
:
plugins {
kotlin("multiplatform") version "1.4.10"
id("com.github.gmazzo.buildconfig") version "2.0.1"
}
group = "me.eugen"
version = "1.0.0"
...
fun String.runCommand(
workingDir: File = File("."),
timeoutAmount: Long = 60,
timeoutUnit: TimeUnit = TimeUnit.SECONDS
): String = ProcessBuilder(split("\\s(?=(?:[^'\"`]*(['\"`])[^'\"`]*\\1)*[^'\"`]*$)".toRegex()))
.directory(workingDir)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start()
.apply { waitFor(timeoutAmount, timeoutUnit) }
.run {
val error = errorStream.bufferedReader().readText().trim()
if (error.isNotEmpty()) {
throw Exception(error)
}
inputStream.bufferedReader().readText().trim()
}
buildConfig {
sourceSets.getByName("nativeMain") {
val branch = "git rev-parse --abbrev-ref HEAD".runCommand(workingDir = rootDir)
val tag = "git tag -l --points-at HEAD".runCommand(workingDir = rootDir)
val commitId = "git rev-parse --short=8 HEAD".runCommand(workingDir = rootDir)
className("BuildConfig")
buildConfigField("String", "version", "\"${version.toString()}\"")
buildConfigField("String", "branch", "\"${branch}\"")
buildConfigField("String", "tag", "\"${tag}\"")
buildConfigField("String", "commit", "\"${commitId}\"")
}
}
main.kt
:
import me.eugen.githash.BuildConfig
fun main() {
val version = BuildConfig.version + "-" + BuildConfig.commit;
println("githash version: " + version)
}
Any suggestions to improve this further?
If you need the project.version
always be the concat version with the commit you can just write
plugins {
kotlin("multiplatform") version "1.4.10"
id("com.github.gmazzo.buildconfig") version "2.0.1"
}
group = "me.eugen"
version = "1.0.0" + "git rev-parse --short=8 HEAD".runCommand(workingDir = rootDir)
...
1 Like