Version increment task always runs twice

I created the following task (Kotlin DSL), to increment the BuildNumber upon every new build, based on a file that stores the current version numbers called version.props:

tasks.create("incrementVersion") {
    // incrementing the build number
    val versionProps: Properties = Properties()
    val versionPropsFile = file("version.props")
    if (versionPropsFile.exists()) versionProps.load(FileInputStream(versionPropsFile))
    val buildNumber = ((versionProps["BUILD_NUMBER"] ?: "0") as String).toInt()
    versionProps["BUILD_NUMBER"] =, null)
    project.version = "${versionProps["MAJOR_NUMBER"]}.${versionProps["MINOR_NUMBER"]}.${versionProps["BUILD_NUMBER"]}"
    println("build number = ${versionProps["BUILD_NUMBER"]}")

However it runs twice every time I build, and the build number increases by 2, not 1. Example output from a gradle build:

3:40:15 PM: Executing task 'build'...

> Configure project :
build number = 151

> Task :wrapper

1 actionable task: 1 executed

> Configure project :
build number = 152

> Task :compileKotlin UP-TO-DATE
> Task :compileJava NO-SOURCE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE
> Task :inspectClassesForKotlinIC
> Task :jar
> Task :assemble
> Task :compileTestKotlin NO-SOURCE
> Task :compileTestJava NO-SOURCE
> Task :processTestResources NO-SOURCE
> Task :testClasses UP-TO-DATE
> Task :test NO-SOURCE
> Task :check UP-TO-DATE
> Task :build

4 actionable tasks: 2 executed, 2 up-to-date
3:40:17 PM: Task execution finished 'build'.

This is within IntelliJ. It happens whether I do a normal gradle build or a gradle shadowJar build. How can I get it run just once per build?

Bonus question: is it possible to NOT run the task except when specifically doing a gradle build? In other words, if I am just running/testing the program in the IDE, to NOT run this task to increment the build number?

Thank you.

I would also add that if I replace tasks.create with tasks.register, or if I surround the code with doLast{} or doFirst{} (even if I still use tasks.create), the project.version is written as unspecified in the manifest file.

Your task is actually running 0 times per build, and you can verify this in the build output. Each line that starts with “> Task” shows a task that was part of the execution plan. Tasks with NO-SOURCE or UP-TO-DATE were part of the execution plan, but didn’t actually need to execute due to those conditions.

This is always the behavior of Gradle tasks. Only tasks that are explicitly requested or have a task dependency from another task that is explicitly requested will be executed. However, your logic is executing as part of the build configuration. It is not correctly defined as a task action.

This would be expected because once you correctly use doLast to setup your task action, the task is no longer running unless you configure a task dependency from the build task or explicitly run it.

A specific task only can run once per build, but IntelliJ is actually running more than one build, one after the other.

Overall, I would expect you would want to register a task, include your logic to increment the build number in a doLast { } block and then create a task dependency from anything that needs that updated build number. I would normally also expect that you’d read the build number in separately from the task to update it, but that’s up to you whether there’s any reason you might want the previous number to still be available even when running builds that don’t need to update the number.

Thank you. Yes, I can change tasks.create to tasks.register, and I can place the commands inside a doLast{}. But when I do either of those, or both, the line project.version = ... no longer persists, or at least, no longer does so in a way that is available to be read inside the shadowJar task. So I have a manifest file with Implementation-Version: unspecified.

The old way was annoying by running twice, but at least it created a manifest file with a valid version number. How can I restore the project.version as readable with a valid version number inside the shadowJar task:

val shadowJar: ShadowJar by tasks
shadowJar.apply {
    manifest.attributes.apply {
        put("Manifest-Version", 1.0)
        put("Implementation-Version", project.version) // "unspecified"
        put("Main-Class", "MainKt")