how to archive artifacts at the end of pipeline stage - jenkins-pipeline

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.

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)
}

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.

Incremental build support for output directory considering added files

The Gradle documentation tells this:
Note that if a task has an output directory specified, any files added to that directory since the last time it was executed are ignored and will NOT cause the task to be out of date. This is so unrelated tasks may share an output directory without interfering with each other. If this is not the behaviour you want for some reason, consider using TaskOutputs.upToDateWhen(groovy.lang.Closure)
Question: How does the solution with upToDateWhen look like (so that added files are considered). The main problem is that one has to access the build cache to retrieve the output directory content hash the last time the task ran.
Not sure if I understand the question correctly or why you mention the build cache. I assume you are not aware that the predicates added with upToDateWhen() are considered in addition to any other up-to-date checks like the ones added with TaskOutputs.dir()?
Take the following sample task:
task foo {
def outDir = file('out')
outputs.dir(outDir)
outputs.upToDateWhen { outDir.listFiles().length == 1 }
doLast {
new File(outDir, 'foo.txt') << 'whatever'
}
}
As long as there is only a single file in the output directory (as configured via upToDateWhen) and the file produced by the task (out/foo.txt) isn’t changed after the task has run, the task will be up-to-date. If you change/remove the file created by the task in the output directory or if you add further files to the output directory, then the task will run again.
Updated answer as per the updated question from the comments:
task foo {
def outDir = file('out')
/* sample task action: */
doFirst {
def numOutFiles = new Random().nextInt(5)
for (int i = 1; i <= numOutFiles; i++) {
new File(outDir, "foo${i}.txt") << 'whatever'
}
}
/* up-to-date checking configuration: */
def counterFile = new File(buildDir, 'counterFile.txt')
outputs.dir(outDir)
outputs.upToDateWhen {
counterFile.isFile() \
&& counterFile.text as Integer == countFiles(outDir)
}
doLast {
counterFile.text = countFiles(outDir)
}
}
def countFiles(def dir) {
def result = 0
def files = dir.listFiles()
if (files != null) {
files.each {
result++
if (it.isDirectory()) {
result += countFiles(it)
}
}
}
result
}

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

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

Call one Gradle Task from another with arguments

I have a gradle task which calls a script and passed the command line arguments to the script using -PARGS.
task taskAll(type: Exec, dependsOn: taskinit) {
environment['PROJECT_ROOT'] = "${projectDir}"
workingDir rootProject.projectDir.path
description = 'Main task'
executable rootProject.projectDir.path + "/execute.me"
if (project.hasProperty('ARGS')) {
args(ARGS.split(','))
}
}
I call this gradle task with any of the below options
./gradlew taskAll
./gradlew taskAll -PARGS="arg1"
./gradlew taskAll -PARGS="arg2"
However, am looking to see if I split taskAll into multiple tasks, say
./gradlew taskA #Calls task taskAll with arg1
./gradlew taskB #Calls task taskAll with arg2
I understand that I will have to replicate the taskAll to create taskA, taskB and remove the "if" condition and hardcode args in each of these.
However, I wonder if it is possible to have a cleaner implementation by having MainTask which only calls the executable, and then have TaskA, TaskB, TaskC call MainTask and pass the arguments arg1, arg2 and arg3.
In most cases, executing one task from another is done by configuration of task dependencies, via providing dependsOn and optionally mustRunAfter properies. In your case, it's not possible to use it, since your main task has to be executed after some configuration task. In that case, you can use finalizedBy property of the task.
For your requirements, you can create a number of tasks, which will set some script variable with predefined arguments, just as you need it. And you could leave your main task, which will call something, relying on this arguments. Only thing you need to do, is to make each custom task finilizedBy your main task. So, every call of custom task will execute the main task after excution.
Here is the short example, how to do it:
//define a variable to store arguments
def ARGS = null
//2 custom tasks, which set arguments during the execution phase
task taskA << {
ARGS = "poperty1,property2"
}
task taskB << {
ARGS = "property3,property4"
}
//your main task
task mainTask (type: Exec) {
environment['PROJECT_ROOT'] = "${projectDir}"
workingDir rootProject.projectDir.path
description = 'Main task'
executable rootProject.projectDir.path + "/execute.me"
//here is the main difference, we moved arguments setting into
//execution phase, before execution of this task
doFirst{
//if you call custom task it will be executed with predefined params
if (ARGS != null) {
args(ARGS)
//if you call mainTask, you are able to pass arguments via command line with -PCOMMAND_LINE_ARGS=123
} else if (project.hasProperty('COMMAND_LINE_ARGS')) {
args(COMMAND_LINE_ARGS)
} else {
throw new GradleException("No arguments found")
}
}
}
//finilization settings for custom tasks
taskA.finalizedBy mainTask
taskB.finalizedBy mainTask
A prettier way to do that with GradleBuild API:
task ('taskA', type: GradleBuild) {
startParameter.projectProperties = ['ARGS':'arg1']
tasks = ['taskAll']
}
task ('taskB', type: GradleBuild) {
startParameter.projectProperties = ['ARGS':'arg2']
tasks = ['taskAll']
}
You can have complex project properties, for example command line argument -Pmyextension.config=true will become :
startParameter.projectProperties = ['myextension.config':true]
Note that this will erase CLI args. If you need to append it :
startParameter.projectProperties << project.getGradle().getStartParameter().getProjectProperties() << ['myextension.config':true]
You can use ext:
task outraTask << {
printf(arg0)
printf(arg1)
}
project(':projetc2').tasks.outraTask {
ext.arg0 = "0"
ext.arg1 = "1"
}.execute()
output:
> Task :projetc2:outraTask
0
1

Resources