8

I want to increase the version number of my project from 1.0.0. to 1.0.1 automatically whenever a new build is made through bash command. I only need to increase path number and others i will be increasing manually during manual build.

i want to change

this :

version=1.0.0

to This:

version=1.0.1

using gradle task. any help that how can i do this . Is there any way to update this using regex or using substring function.

Community
  • 1
  • 1
Sidharth
  • 1,402
  • 2
  • 16
  • 37

11 Answers11

7

Here's a custom task for version bumps in Gradle (Android project):

class Version {

    private int major
    private int minor
    private int patch
    private int code

    Version(int code, String version) {
        this.code = code

        def (major, minor, patch) = version.tokenize('.')
        this.major = major.toInteger()
        this.minor = minor.toInteger()
        this.patch = patch.toInteger()
    }

    @SuppressWarnings("unused")
    void bumpMajor() {
        major += 1
        minor = 0
        patch = 0

        code += 1
    }

    @SuppressWarnings("unused")
    void bumpMinor() {
        minor += 1
        patch = 0

        code += 1
    }

    @SuppressWarnings("unused")
    void bumpPatch() {
        patch += 1
        code += 1
    }

    String getName() { "$major.$minor.$patch" }

    int getCode() { code }
}

tasks.addRule("Pattern: bump<TYPE>Version") { String taskName ->
    if (taskName.matches("bump(Major|Minor|Patch)Version")) {
        task(taskName) {
            doLast {
                String type = (taskName - 'bump' - 'Version')

                println "Bumping ${type.toLowerCase()} version…"

                int oldVersionCode = android.defaultConfig.versionCode
                String oldVersionName = android.defaultConfig.versionName

                version = new Version(oldVersionCode, oldVersionName)
                version."bump$type"()

                String newVersionName = version.getName()
                String newVersionCode = version.getCode()

                println "$oldVersionName ($oldVersionCode) → $newVersionName ($newVersionCode)"

                def updated = buildFile.getText()
                updated = updated.replaceFirst("versionName '$oldVersionName'", "versionName '$newVersionName'")
                updated = updated.replaceFirst("versionCode $oldVersionCode", "versionCode $newVersionCode")

                buildFile.setText(updated)
            }
        }
    }
}

See this Kanji learning Android app for completeness.

Prerequisites

Following format required (note the single quotes):

android {
    defaultConfig {
        versionCode 3
        versionName '0.3.13'
    }
}

Usage

$ ./gradlew bumpPatchVersion

> Task :app:bumpPatchVersion
Bumping patch version…
0.3.13 (3) → 0.3.14 (4)

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

$ ./gradlew bumpMinorVersion

> Task :app:bumpMinorVersion
Bumping minor version…
0.3.14 (4) → 0.4.0 (5)

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

$ ./gradlew bumpMajorVersion             

> Task :app:bumpMajorVersion
Bumping major version…
0.4.0 (5) → 1.0.0 (6)

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed
user123
  • 170
  • 1
  • 9
  • 1
    Might be worth linking to the [Android Versioning doc](https://developer.android.com/studio/publish/versioning) for folks, like me, who are unfamiliar with the `code` field. But your code can easily be adapted to non-Android projects. – Charlie Reitzel Jan 31 '20 at 15:00
6

Here is an example task:

version='1.0.0'  //version we need to change

task increment<<{
    def v=buildFile.getText().find(version) //get this build file's text and extract the version value
    String minor=v.substring(v.lastIndexOf('.')+1) //get last digit
    int m=minor.toInteger()+1                      //increment
    String major=v.substring(0,v.length()-1)       //get the beginning
    //println m
    String s=buildFile.getText().replaceFirst("version='$version'","version='"+major+m+"'")
    //println s
    buildFile.setText(s) //replace the build file's text
}

Run this task several times and you should see the version change.

A variant:

version='1.0.0'

task incrementVersion<<{
    String minor=version.substring(version.lastIndexOf('.')+1)
    int m=minor.toInteger()+1
    String major=version.substring(0,version.length()-1)
    String s=buildFile.getText().replaceFirst("version='$version'","version='"+major+m+"'")
    buildFile.setText(s)
}
Alexiy
  • 1,966
  • 16
  • 18
  • What good is the `def v=buildFile.getText().find(version)` here? Wouldn't that just give you `version` right away? – cfrick Oct 04 '16 at 17:13
  • Yes, you can omit that and reference the version directly. But if you don't want the build to fail if the version is not set, you can add `if(v)` check to that task. But if you do `if(version)` check and the version is not set, the build will fail. – Alexiy Oct 04 '16 at 18:41
  • 1
    @Alexity this will create an issue if version='1.0.100' – unknown Dec 03 '17 at 00:58
  • 2
    why wouldn't you use `split` this hurts my brain. Also `int m`, please don't. – MushyPeas Jan 30 '18 at 16:46
  • @MushyPeas I wasn't masterful in Groovy at that time, so no need for showing "brain hurt". – Alexiy Jan 30 '18 at 19:54
3

You could also use split with a increment-matrix, that could be changed depending on the amount of changes:

def version = '1.0.0'
def incstep = '0.0.1'.split(/\./).collect{it.toInteger()}

def indexedVersionList = version.split(/\./).toList().withIndex()
def updatedVersionList = indexedVersionList.collect{num, idx -> num.toInteger()+incstep[idx]}
def updatedVersion = updatedVersionList.join(".")
MushyPeas
  • 2,469
  • 2
  • 31
  • 48
2

This is how I did it with Kotlin DSL (build.gradle.kts):

tasks.create("incrementVersion") {
    group = "my tasks"
    description = "Increments the version in this build file everywhere it is used."
    fun generateVersion(): String {
        val updateMode = properties["mode"] ?: "minor" // By default, update the minor
        val (oldMajor, oldMinor, oldPatch) = version.split(".").map(String::toInt)
        var (newMajor, newMinor, newPatch) = arrayOf(oldMajor, oldMinor, 0)
        when (updateMode) {
            "major" -> newMajor = (oldMajor + 1).also { newMinor = 0 }
            "minor" -> newMinor = oldMinor + 1
            else -> newPatch = oldPatch + 1
        }
        return "$newMajor.$newMinor.$newPatch"
    }
    doLast {
        val newVersion = properties["overrideVersion"] as String? ?: generateVersion()
        val oldContent = buildFile.readText()
        val newContent = oldContent.replace("""= "$version"""", """= "$newVersion"""")
        buildFile.writeText(newContent)
    }
}

Usage:

./gradlew incrementVersion [-P[mode=major|minor|patch]|[overrideVersion=x]]

Examples:

./gradlew incrementVersion -Pmode=minor
./gradlew incrementVersion -PoverrideVersion=2.5.11

That is given that you have something like this in your build script:

version = "1.2.3"

... and the patch part of the version is just a number (not containing letters like alpha, rc, etc.).

Mahozad
  • 18,032
  • 13
  • 118
  • 133
1

Below solution will not create an issue evern last number exceed from 9-10 and so on

   version='1.0.11.1001'


    task incrementrevsion{
        def v = version
        println v
        String minor=v.substring(v.lastIndexOf('.')+1) //get last digit
        int m=minor.toInteger()+1                      //increment
        println m
        String major=v.substring(0,v.lastIndexOf("."));       //get the beginning
        println major
        String s=buildFile.getText().replaceFirst("version='$version'","version='"+major+ "." +m+"'")
        //println s
        buildFile.setText(s) //replace the build file's text
    }
unknown
  • 1,815
  • 3
  • 26
  • 51
0
def patch = version.substring(version.lastIndexOf('.') + 1)
def p = patch.toInteger() + 1
def major = version.substring(0, version.length() - p.toString().length())
def s = buildFile.getText().replaceFirst("version = '$version'", "version = '" + major + p + "'")
buildFile.setText(s)

The only difference with Alexiy's answer that line 3 contains m.toString().length() as if minor version > 10, i.e 1.0.12 and you will use that approach it will change it to 1.0.113. We need to calculate the length of minor version instead of chopping off only 1 symbol.

And one more thing, usually the last number is called patch, minor is a middle one :)

Bogdan Nechyporenko
  • 1,226
  • 2
  • 14
  • 21
0

My Solution where the version will be set by a Parameter.

version = '4.0.0' // I have whitespaces between the equals-sign
task setVersion << {
group = 'Versioning'
description = "Sets the version to the new number specified with -PnewVersion=\'x.x.x\'"
println version
if(project.hasProperty('newVersion')) {
    println 'Set Project to new Version '+newVersion
    String s=buildFile.getText().replaceFirst("version = '$version'","version = '"+newVersion+"'")
    buildFile.setText(s)
}

}

Call Gradle Task with:

gradle setVersion -PnewVersion='5.1.1'
herres
  • 53
  • 1
  • 5
  • I had to change the use of left operator with doTask as per this answer: https://stackoverflow.com/a/55793096/6095334. Also, I had to either remove the pings (') from around the version number in the argument or in the string building line such as to avoid too many pings around the version number. Other than that the answer works for me. – Hervian May 24 '22 at 12:28
0

As for me work this solution. You need add this code into build.gradle file:

version='1.0.1'

tasks.register("incrementVersion") {
doLast {
    def ver = version
    println ver
    String lastNumber = ver.substring(ver.lastIndexOf('.') + 1)
    int increment = lastNumber.toInteger() + 1
    println increment

    String firstNumber = ver.substring(0, ver.lastIndexOf("."))
    println firstNumber
    String result = buildFile.getText().replaceFirst("version='$version'","version='" + firstNumber + "." + increment + "'")
    buildFile.setText(result)
}

}

Kirill Sereda
  • 469
  • 1
  • 10
  • 25
0

I know I am posting this quite late, but the answers mentioned above work well upto '1.0.99'. After which it starts misbehaving.

If any one is still interested, I found a different approach.

 task increment {

    def v = buildFile.getText().find(version)
    def (major, minor, patch) = v.tokenize('.')
    int newPatch = patch.toInteger() + 1
    String newVersion = major + "." + minor + "." + newPatch
    String updatedVersion = buildFile.getText().replaceFirst("version='"+v+"'","version='"+newVersion+"'")
    buildFile.setText(updatedVersion)
 }
Aryan Raj
  • 134
  • 10
0

This is an example of same think but with KTS(Kotlin Script).

val newVersion: String? by project
tasks.register("bumpVersion") {
    this.doFirst {
        println("Old version $version")
        val newVersion = takeIf { newVersion.isNullOrBlank() }?.let {
            val versionArray = version.toString().split(".")
            "${versionArray[0]}.${versionArray[1]}.${versionArray.last().toInt().plus(1)}"
        } ?: newVersion

        buildFile.readText().apply {
            println("Bump to $newVersion")
            val content = this.replaceFirst("version = \"$version\"", "version = \"$newVersion\"")
            buildFile.writeText(content)
        }
    }
}

Increment automatic the patch or it is possible to send new version as property.

./gradlew bumpVersion -PnewVersion=0.2.0
Rudge
  • 630
  • 7
  • 7
0

Kotlin dsl:

tasks.create("incrementPatch") {
    group = "version"
    description = "Автоматически поднять патч версию в файле VERSION"
    doFirst {
        incrementVersion("patch")
    }
}
tasks.create("incrementMinor") {
    group = "version"
    description = "Автоматически поднять минор версию в файле VERSION"
    doFirst {
        incrementVersion("minor")
    }
}
tasks.create("incrementMajor") {
    group = "version"
    description = "Автоматически поднять мажор версию в файле VERSION"
    doFirst {
        incrementVersion("major")
    }
}

tasks.named("compileKotlin") {
    dependsOn(":incrementPatch")
}

fun incrementVersion(updateMode: String){
    val versions = file("version").readText().trim()
    println("read version = $versions")
    val (oldMajor, oldMinor, oldPatch) = versions.substringBefore("-").split(".").map(String::toInt)
    var (newMajor, newMinor, newPatch) = arrayOf(oldMajor, oldMinor, 0)
    when (updateMode) {
        "major" -> newMajor = (oldMajor + 1).also { newMinor = 0 }
        "minor" -> newMinor = oldMinor + 1
        else -> newPatch = oldPatch + 1
    }
    val newVersion ="$newMajor.$newMinor.$newPatch-SNAPSHOT"
        println("new version = $newVersion")
    file("version").writeText(newVersion)
}
Vovan
  • 478
  • 4
  • 5