Parallel execution 'mvn test' in Jenkins - jenkins-pipeline

I try to create jenkinsfile for parallel execution command mvn test with different arguments. On the first stage of jenkinsfile I create *.csv file where are will be future arguments for mvn test command. Also I don't know the quantity of parallel stages (it depends on first stage where I get data from DB). So, summarize it again. Logic:
First stage for getting data from DB over command mvn test (with args). On this test I save data into csv file.
In loop of jenkinsfile I read every string, parse it and get args for arallel execution mvn test (with args based on the parsed data).
Now it looks like this (only necessary fragments of jenkinsfile):
def buildProject = { a, b, c ->
node {
stage(a) {
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
sh "mvn -Dtest=test2 test -Darg1=${b} -Darg2=${c}"
}
}
}
}
stages {
stage('Preparation of file.csv') {
steps {
sh 'mvn -Dtest=test1 test'
}
}
stage('Parallel stage') {
steps {
script {
file = readFile "file.csv"
lines = file.readLines()
def branches = [:]
for(i = 0; i < lines.size(); i++) {
values = lines[i].split(';')
branches["${values[0]}"] = { buildProject(values[0], values[1], values[2]) }
}
parallel branches
}
}
}
}
So, which problems do I face now with?
I see in log following error:
[ERROR] The goal you specified requires a project to execute but there is no POM in this directory (/Data/jenkins/workspace//#2)
I look at workspaces of Jenkins and see that there were created several empty(!!!) directories (quantity equals to quantity of parallel stages). And therefore mvn command could be executed because of absence of pom.xml and other files.
In branches the same data are saved on every iteration of loop and in 'stage(a)' I see the same title (but every iteration of loop has unique 'values[0]').
Can you help me with this issue?
Thank you in advance!

So, regarding this jenkins issue issues.jenkins.io/browse/JENKINS-50307 and workaround which could be found there, task could be closed!

Related

Keep workspace when switching stages in combination with agent none

I have a Jenkins pipeline where I want to first build my project (Stage A) and trigger an asynchronous long running external test process with the built artifacts. The external test process then resumes the Job using a callback. Afterwards (Stage B) performs some validations of the test results and attaches them to the job. I don't want to block an executor while the external test process is running so I came up with the following Jenkinsfile which mostly suites my needs:
#!/usr/bin/env groovy
pipeline {
agent none
stages {
stage('Stage A') {
agent { docker { image 'my-maven:0.0.17' } }
steps {
script {
sh "rm testfile.txt"
sh "echo ABCD > testfile.txt"
sh "cat testfile.txt"
}
}
}
stage('ContinueJob') {
agent none
input { message "The job will continue once the asynchronous operation has finished" }
steps { echo "Job has been continued" }
}
stage('Stage B') {
agent { docker { image 'my-maven:0.0.17' } }
steps {
script {
sh "cat testfile.txt"
def data = readFile(file: 'testfile.txt')
if (!data.contains("ABCD")) {
error("ABCD not found in testfile.txt")
}
}
}
}
}
}
However, depending on the load of the Jenkins or the time passed or some unknown other conditions, sometimes the files that I create in "Stage A" are no longer available in "Stage B". It seems that Jenkins switches to a different Docker node which causes the loss of workspace data, e.g. in the logs I can see:
[Pipeline] { (Stage A)
[Pipeline] node
Running on Docker3 in /var/opt/jenkins/workspace/TestJob
.....
[Pipeline] stage
[Pipeline] { (Stage B)
[Pipeline] node
Running on Docker2 in /var/opt/jenkins/workspace/TestJob
Whereas with a successful run, it keeps using e.g. node "Docker2" for both stages.
Note that I have also tried reuseNode true within the two docker sections but that didn't help either.
How can I tell Jenkins to keep my workspace files available?
As pointed out by the comment from #Patrice M. if the files are not that big (which is the case for me) stash/unstash are very useful to solve this problem. I have used this combination now since a couple of months and it has solved my issue.

Returning Boolean value in Groovy function when Maven build fails in shell script

I have wrote a Jenkins Pipeline Groovy for executing multiple project maven sonar analysis. The code is working fine but the issue is that sometimes build fails for some projects which I need to track it properly. My executeMavenSonarBuild function is given as below
def executeMavenSonarBuild(projectName) {
stage ('Execute Maven Build for '+projectName)
{
sh """ {
cd ${projectName}/
mvn clean install verify sonar:sonar
} || {
echo 'Build Failed'
}
"""
}
return true;
}
If build fails it prints echo 'Build Failed' but how we can return a false Boolean as the return to the function.
You have to get the status from the mvn call itself..which should look like this:
def result = sh ( script: 'mvn ...', returnStatus: true)

Console Output in pipeline:Jenkins

I have created a complex pipeline. In each stage I have called a job. I want to see the console output for each job in a stage in Jenkins. How to get it?
The object returned from a build step can be used to query the log like this:
pipeline {
agent any
stages {
stage('test') {
steps {
echo 'Building anotherJob and getting the log'
script {
def bRun = build 'anotherJob'
echo 'last 100 lines of BuildB'
for(String line : bRun.getRawBuild().getLog(100)){
echo line
}
}
}
}
}
}
The object returned from the build step is a RunWrapper class object. The getRawBuild() call is returning a Run object - there may be other options than reading the log line-by-line from the looks of this class. For this to work you need to either disable the pipeline sandbox or get script approvals for these methods:
method hudson.model.Run getLog int
method org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper getRawBuild
If you are doing this for many builds, it would be worth putting some code in a pipeline shared library to do what you need or define a function in the pipeline.

Unable to create a Gradle task rule with an Exec task

I'm trying to write a task rule to create a series of tasks that checkout various svn repository locations. Here is my rule:
tasks.addRule("Pattern: svnCheckout&ltClassifier> - Checks out the indicated svn repo") { String taskName ->
if(taskName.startsWith('svnCheckout')) {
task(name: taskName, type: Exec) {
String classifier = taskName - 'svnCheckout'
String svnDir = svnRepoUrl //defined elsewhere
switch(classifier) {
case 'SourceTrunk':
svnDir += 'branches/CleanBuild/trunk'
break
case 'AutoInstaller':
svnDir += 'Tools/AutoInstaller'
break
case 'ContentAutomation':
svnDir += 'Tools/ContentAutomation'
break
case 'InternalTools':
svnDir += 'Tools/Internal'
break
default:
throw new GradleException("Invalid svnCheckout classifier '$classifier'")
}
String svnCommand = "svn co $svnDir --trust-server-cert"
//commandLine 'cmd', '/c', "$svnCommand"
commandLine 'cmd', '/c/', "echo 'Task created'"
workingDir = "$workspace"
}
}
}
I then try to run the task 'svnCheckoutSourceTrunk' with this command:
gradlew -Pworkspace="." svnCheckoutSourceTrunk
which fails with the error
FAILURE: Could not determine which tasks to execute.
* What went wrong:
Task 'svnCheckoutSourceTrunk' not found in root project 'GradleScripts'.
* Try:
Run gradlew tasks to get a list of available tasks.
BUILD FAILED
Anyone see what I'm doing wrong? I put some println statements around the first few lines, and the execution is getting past the if statement, but it's not getting inside the task declaration.
The syntax used for declaring the task(s) is incorrect. (Not sure why it's not giving an error.) The first positional argument always need to be the task name:
task(taskName, type: Exec) { ... }
In a build script, this will also work:
task "$taskName"(type: Exec) { ... }

How to continue a Jenkins build even though a build step failed?

I am using a Phing build script with Jenkins and would like to run it end to end on a job and capture all the reports. The problem is it stop building on a failed build step. Is there a way or a plugin that would continue the job even on failures?
Thanks
I don't know a lot about Phing but, since it's based on Ant, if the build step you are executing has a "failonerror" attribute you should be able to set it to false so that the entire build doesn't fail if the step returns an error.
Yes, use try, catch block in you pipeline scripts
example:
try {
// do some stuff that potentially fails
} catch (error) {
// do stuff if try fails
} finally {
// when you need some clean up to do
}
Or alternatively if you use sh commands to run these tests, consider running your sh scripts with the "|| true" suffix, this tells the linux sh script to exit with a result code of 0, even if your real command exited with an exit code.
example:
stage('Test') {
def testScript = ""
def testProjects = findFiles(glob: 'test/**/project.json')
if (!fileExists('reports/xml')) {
if (!fileExists('reports')) {
sh "mkdir reports"
}
sh "mkdir reports/xml"
}
for(prj in testProjects) {
println "Test project located, running tests: " + prj.path
def matcher = prj.path =~ 'test\\/(.+)\\/project.json'
testScript += "dotnet test --no-build '${prj.path}' -xml 'reports/xml/${matcher[0][1]}.Results.xml' || true\n"
}
sh testScript

Resources