Gradle, what is a sequence of execution in one task? - gradle

Gradle 2.14
I write my custom task "run"
task run() {
def allVariantList = [];
android.applicationVariants.all { variant ->
allVariantList.add(variant.getName())
println "Current allVariantList = " + allVariantList
}
println "Result allVariantList = " + allVariantList
}
Start my task: gradlew run
Result:
Result allVariantList = []
Current allVariantList = [prod_no_check]
Current allVariantList = [prod_no_check, prod]
Current allVariantList = [prod_no_check, prod, stage]
Current allVariantList = [prod_no_check, prod, stage, dev]
Current allVariantList = [prod_no_check, prod, stage, dev, release]
Current allVariantList = [prod_no_check, prod, stage, dev, release, dev_no_check]
Questions:
Why println "Result allVariantList = " + allVariantList run BEFORE println "Current allVariantList = " + allVariantList
I need to println "Result allVariantList = " + allVariantList execute AFTER
println "Current allVariantList = " + allVariantList. How I can do this?

I think the problem is, that at the time your task is configured (you do all your stuff at configuration time, not execution time, the applicationVariants are not yet configured by the android plugin. applicationVariants.all runs on all variants that are already added and also on all variants that get added in the future as soon as they are added.
So your output would suggest that at configuration time no variants are setup yet, thus your result printing is empty and the others come later when the variants are created.
As you do everythign you do at configuration time, it will also always be done, even if you don't execute your task. If you call gradlew help or anything else, you will get the same output.
So either do all your code in the execution phase (wrapping it in a doLast { } closure), or at least do the result printing in the execution phase. If you need your stuff to be done before the execution phase and independently whether your task is actually run or not, you might wrap at least your result printing in an afterEvaluate { } closure that gets executed after the project is evaluated, but still in the configuration phase.

OK, thank everybody. This is work:
task run() {
description "Install and run app on device/emulator"
def allVariantList = [];
android.applicationVariants.all { variant ->
allVariantList.add(variant.getName())
println "Current allVariantList = " + allVariantList
}
doLast {
println "Result allVariantList = " + allVariantList
}
}
Here is the explanation.
https://docs.gradle.org/current/userguide/build_lifecycle.html
Example 22.1. Single project build

Related

Gradle Task - unable to execute fibonacci series in groovy

Facing problem in a question:
Write a gradle program to generate 10 fibonaci series, with task name as fibo, and variable name as num. Use command line argument for num.
For example, if a task name is test and I want to pass 10 as the input, use gradle test -Pnum=10.
I have created a function:
def fibo(n){
a = 0
b = 1
if (n == 1)
println a
else if
(n == 2)
println a + " " + b
else if (n > 2) {
print a + " " + b
i = 2
while (i <= n)
{
c = a + b
print " " + c
a = b
b = c
i = i + 1
}
}
}
My question is, how to link it with a task as I encounter error like:
FAILURE: Build failed with an exception.
* What went wrong:
Task 'fibo' not found in root project 'root'.
* Try:
Run gradle tasks to get a list of available tasks. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 2.61 secs
or how to pass parameters in a gradle task?
Note: Please do not suggest optimization in fibonacci code, thats not a concern for now.
You can define a task like this:
def hello(name) {
println "Hello, $name"
}
task sayHello() {
doLast {
hello sayHelloTo
}
}
And call it like this:
% gradle sayHello -PsayHelloTo=World
> Task :sayHello
Hello, World
BUILD SUCCESSFUL in 518ms
1 actionable task: 1 executed
def fibo(num) {
if (num < 2) {
return 1
} else {
return fibo(num-2) + fib(num-1)
}
}
task (fibo) << {
println fibo(5)
}

how to archive artifacts at the end of pipeline stage

I have the following pipeline
node ("testNode"){
dev env = ${ENV};
stage ("Copy artifact"){
copyArtifacts(projectName: 'appBuildJob',selector: lastCompleted());
}
stage ("Archive artifact"){
// Archive the build output artifacts.
archiveArtifacts artifacts: 'app/build/outputs/apk/app-${ENV}.apk';
}
stage ('env1'){
if (env == "env1") {
buildResult = build(job: 'env1Tests',propagate: false).result;
currentBuild.description = 'env1 - ' + buildResult
} else {
echo 'Env param is ' + env +'. Nothing to do here.';
}
}
stage ('env2'){
if (env == "env2") {
buildResult = build(job: 'env2Tests',propagate: false).result;
currentBuild.description = 'env2 - ' + buildResult
} else {
echo 'Env param is ' + env +'. Nothing to do here.';
}
}
}
My problem is that the job appBuildJob can have either env1 or env2 param and both env1Tests and env2Tests depends on the artifact of my pipeline. So if for example now runs env1 it saves the artifact and everything. Then if I run env2 my env2Tests will fail because it can't find env2 app, it will find only env1 app. After this fails and the pipeline ends i have my env2 artifact saved. So if I run immediately emv2 it will work
I want to save and overwrite the artifact at the end of the "Archive artifact" stage but it only does that when all the pipeline ended.

I have 3 stages to build in jenkins using pipeline code (Scripted0

I have 3 stages(a,b,c) to run on jenkins using pipeline code(scripted), I
need to run stage a,b in parallel and run c after a is success (I am
doing this using pipeline code) but in blue ocean it showing only task
name but I wanna see stage names(in this case I have only 2 tasks with 3
stages and stage a and c are in one task). can someone help how can view
all three stages according to this situation.
def stages = [failFast: false]
def testList = ["a", "b", "c"]
def tasks = [:]
tasks["a-and-c"] = {
stage ("a"){
ansiColor('xterm') {
sh " ls -lart; sleep 30 "
}
if (currentBuild.currentResult == 'SUCCESS') {
stage("c") {
ansiColor('xterm') {
sh " ls -lart "
}
}
} else {
sh 'exit'
}
}
}
tasks["c"] = {
stage ("c"){
ansiColor('xterm') {
sh " ls -lart; sleep 20"
}
}
}
parallel tasks
I am expecting to have a separate view in blueocean for all three stages,
right now I am getting a-and-c and b parallel but I looking for a,b as
parallel and c after a is success. Thank you in advance.

Version increment using gradle task

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.
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)
}
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
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(".")
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.).
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
}
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 :)
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'
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)
}
}
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)
}
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
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)
}

Gradle - StopExecutionException doesn't change TaskStatus

I have three gradle Tasks: A, B and B2. They depend on each other in the following way: A <- B <- B2 (meaning B depends on A and B2 depends on B). Here is my code:
task A {
println "Exec A"
}
task B(dependsOn: A) << {
throw new StopExecutionException("skip this task") // this exception prevents the println, but doesn't change the TaskStatus of B
println "Exec B"
}
task B2(dependsOn: B) << {
println "Did work: " + B.getState().getDidWork();
println "Exec: " + B.getState().getExecuted();
println "Failure: " + B.getState().getFailure();
println "Skip message: " + B.getState().getSkipMessage();
println "Skipped: " + B.getState().getSkipped();
println "Exec B2"
}
When I execute this (by running gralde -q B2), I get the following output:
> gralde -q B2
Exec A
Did work: true
Exec: true
Failure: null
Skip message: null
Skipped: false
Exec B2
As can be seen, the properties of the TaskState didn't change although the StopExecutionException was thrown correctly. How can I determine in a task if all former tasks were executed completely?
StopExecutionException is simply a shortcut to finish the task execution. The task doesn't fail if it is thrown as you can read in documentation neither is the task skipped. You can throw GradleException to make the task fail and then the subsequent task will be able to check the result. Note that you will need to change B2 to make it a finalizing task of B (see here) or play with runAfter or something similar.

Resources