Get Version in Kotlin/Java code in Gradle project

I have a webservice coded in kotlin and managed by gradle for the build/dependencies etc...

I want to do a simple thing: When someone call the version REST endpoint of my webservice, it returns the version.

Since gradle already handle the version with the version properties in build.gradle, I thought it would be easy to get this value but it seems it is not... I've been searching google for hours and everything seems so complicated.

Any idea how to handle the version the good way?

Here is what I have right now:

build.gradle

version = "1.0.0"
...

StatusService.kt

class StatusService : IStatusService {

    //TODO: Here I would like to get the version from the gradle 
    //file instead of maintaining 2 places for the version
    //Something like Gradle.getProperties("version") for example
    override fun getVersion() : String = "1.0.0"

}

I may be completely wrong about this so if you have another equivalent solution, I will accept it too! Thanks

Upvotes: 16

Views: 14754

Answers (5)

sergeych
sergeych

Reputation: 869

In modern build.gradle.kts it is rather simpler. In the build file all you need is to add a task:

tasks.withType<ProcessResources>() {
    doLast {
        val propertiesFile = file("$buildDir/resources/main/version.properties")
        propertiesFile.parentFile.mkdirs()
        val properties = Properties()
        properties.setProperty("version", rootProject.version.toString())
        propertiesFile.writer().use { properties.store(it, null) }
    }
}

Now you have it packed and can use it the way you want, I prefer a helper like:

object Config : LogTag("CONF") {

    private val versionProps by lazy {
        Properties().also {
            it.load(this.javaClass.getResourceAsStream("/version.properties"))
        }
    }

    val version by lazy {
        versionProps.getProperty("version") ?: "no version"
    }
}

Upvotes: 4

superdave
superdave

Reputation: 2298

It took some time to figure out how translate the accepted answer to build.gradle.kts, but this works:

import java.io.FileOutputStream
import java.util.Properties

version = "your-version"

val generatedVersionDir = "$buildDir/generated-version"

sourceSets {
  main {
    kotlin {
      output.dir(generatedVersionDir)
    }
  }
}

tasks.register("generateVersionProperties") {
  doLast {
    val propertiesFile = file("$generatedVersionDir/version.properties")
    propertiesFile.parentFile.mkdirs()
    val properties = Properties()
    properties.setProperty("version", "$version")
    val out = FileOutputStream(propertiesFile)
    properties.store(out, null)
  }
}

tasks.named("processResources") {
  dependsOn("generateVersionProperties")
}

Upvotes: 6

Dmitry Zinkevich
Dmitry Zinkevich

Reputation: 3518

Consider simple Kotlin Spring Boot example:

@SpringBootApplication
@RestController
class DemoApplication {
    @Value("\${version}")
    private lateinit var version: String

   @GetMapping("/version")
   fun version() = version
}

fun main(args: Array<String>) {
    runApplication<DemoApplication>(*args)
}

Since the property could be taken from application.properties we need to generate that file with required version. To do so we could create a template properties file with following content:

version=###appVersion

Now lets tell Gradle to copy that template to the resource folder and put the version instead of placeholder

import org.apache.tools.ant.filters.ReplaceTokens

task preprocessProperties(type: Copy) {
    from 'src/main/resources/templates'
    into 'src/main/resources'
    include 'template.properties'
    rename 'template.properties', 'application.properties'
    filter(ReplaceTokens, beginToken: '###', endToken: '', tokens: [appVersion: '1.0.0'])
}

compileKotlin.dependsOn preprocessProperties

And, voilà, every time you compile Kotlin sources you will get a property file with the version you need.

Upvotes: 1

JK Ly
JK Ly

Reputation: 2945

One approach to this is to output a version file as part of your Gradle build to a location in your classpath that is accessible as a resource within your application.

For example:

You can add this to your build.gradle file which will generate a properties file containing the project version number and add it to your applications source set so that it is available in the classpath.

def generatedVersionDir = "${buildDir}/generated-version"

sourceSets {
    main {
        output.dir(generatedVersionDir, builtBy: 'generateVersionProperties')
    }
}

task generateVersionProperties {
    doLast {
        def propertiesFile = file "$generatedVersionDir/version.properties"
        propertiesFile.parentFile.mkdirs()
        def properties = new Properties()
        properties.setProperty("version", rootProject.version.toString())
        propertiesFile.withWriter { properties.store(it, null) }
    }
}
processResources.dependsOn generateVersionProperties

Then in your code you will be able to access it by reading in the properties file:

class StatusService : IStatusService {
    private val versionProperties = Properties()

    init {
        versionProperties.load(this.javaClass.getResourceAsStream("/version.properties"))
    }

    override fun getVersion() : String = versionProperties.getProperty("version") ?: "no version"
}

Of course you might find it simpler and more appropriate to just output a String to the version file, and then read in the entire file as a String in your code instead of using a properties file.

Upvotes: 11

Kevin Robatel
Kevin Robatel

Reputation: 8386

Gradle is present only at the compilation, not at Runtime.

For doing this, you have to generate a class at the compilation time.
With Android project, the file BuildConfig.java is generated but I don't know if it's Gradle or Android.

For generating Kotlin code, you can check KotlinPoet.

Upvotes: 0

Related Questions