Jenkins groovy scripted pipeline variables not substituting correctly - bash

I'm running a very simple pipeline to create maven projects, the pipeline is to run a single maven install command.
The trouble is substituting variables into the one-liner. I've tried various different things but stuck in a strange place. Take example pipeline below:
node {
stage('Set Vars') {
GIT_HASH = sh (script: "git log -n 1 --pretty=format:'%H'" , returnStdout: true)
echo "git hash is >>>>>>>> $GIT_HASH"
BUILD_NUM="${env.BUILD_NUMBER}"
echo "build no is >>>>>>>> ${BUILD_NUM}"
}
stage('Build Project') {
sh "mvn clean install -PrunInstallPackage -Duser=admin -Dpass=guessing -Dip=200.0.0.1 -Dport=4444 -Dhash=${GIT_HASH} -Dbuildnumber=${BUILD_NUM}"
}
}
I would expect to see the variables substitued in the mvn install command, this does not seem to work this way though.
This build results in:
sh "mvn clean install -PrunInstallPackage -Duser=admin -Dpass=guessing -Dip=200.0.0.1 -Dport=4444 -Dhash=${GIT_HASH}
Both echo commands print out correct output.
Why does the last command get cut off after the first variable substitution?
Also, for some unknown reason, I cannot substitute -Dbuildnumber=${env.BUILD_NUMBER}" directly into the maven command. Seems like something that a user should be able to do. What am I missing here?
Many thanks in advance

I am trying to remember how I solved same issues in the past..
Problem 1
You are using the GIT_HASH variable across two stages, so you have to declare it global to share it across them:
// Global variables declaration
GIT_HASH = null
// Pipeline code
node {
stage('Set Vars') {
GIT_HASH = sh (script: "git log -n 1 --pretty=format:'%H'" , returnStdout: true)
echo "git hash is >>>>>>>> $GIT_HASH"
BUILD_NUM="${env.BUILD_NUMBER}"
echo "build no is >>>>>>>> ${BUILD_NUM}"
}
stage('Build Project') {
sh "mvn clean install -PrunInstallPackage -Duser=admin -Dpass=guessing -Dip=200.0.0.1 -Dport=4444 -Dhash=${GIT_HASH} -Dbuildnumber=${BUILD_NUM}"
}
}
Problem 2
env.BUILD_NUMBER is a Groovy statement, instead mvn gets executed inside a shell instance by the sh command.
For that reason I suggest you to use the BUILD_NUM variable way.

Related

Bash script never receives arguments when called from Jenkins pipeline

I'm running a declarative Jenkins pipeline on Ubuntu 18.04 slave. My issue is that whenever I'm trying to provide arguments from a sh step to a bash script, the arguments are not there. When running the exact same commands from either a terminal directly or another script file (similarly how Jenkins does it via temp file) the arguments work fine.
The Jenkinsfile looks something like
pipeline {
agent { label "ubuntu" }
options { timeout(time: 1, unit: 'HOURS') }
stages {
stage('Build') {
steps {
sh """
#!/bin/bash
...
. ./Scripts/install_tools.sh "force"
"""
}
}
}
}
The pipeline itself runs smooth and does what I need it to do. The problem is that when calling install_tools.sh no arguments are found. The script looks something like
#!/bin/bash
echo "Running $0"
echo "Args: $#"
...
The line echo "Args: $#" I have tried also with $* and $1 - Each time the arguments are returned as empty, but only when running from the pipeline. It seems to me that this is related to some Groovy stuff, but I have no clue what.
How do I call a bash script during the pipeline and get the arguments passed properly?
put #!/bin/bash into the first line
sh """#!/bin/bash
. ./Scripts/install_tools.sh "force"
"""
otherwise . (dot) command could have different meaning

How to suppress output of 'rm -rf' in Jenkins shell script?

I've a big Jenkins pipeline and when build is run, lot of console output is generated which causes space issue on Jenkins master.
I've following code in Jenkins pipeline with Shell Script, which logs every file being removed. I've lots of log files that cause lot of console output -
stage('Logs Cleanup') {
steps {
script {
sh '''rm -rf /home/oracle/test/logs1/* /home/oracle/test/logs2/*'''
}
}
}
Is there any way I can suppress output of that command?
NOTE: If same command it run from Terminal, it logs nothing in output.
For your specific delete using Jenkins only:
stage('Logs Cleanup') {
steps {
dir ('/home/oracle/test/logs1/') {
deleteDir()
}
dir ('/home/oracle/test/logs2/') {
deleteDir()
}
}
}
Looks like there are some comments that solve the problem for you, but no one mentioned that you can control the output of sh commands through the command itself.
The sh command has some optional parameters that can be used; one of them is returnStdout. In your case, you can suppress stdout like this:
stage('Logs Cleanup') {
steps {
script {
sh script: 'rm -rf /home/oracle/test/logs1/* /home/oracle/test/logs2/*', returnStdout: false
}
}
}
There are some other useful parameters, for example returnStatus will return the status code of the command for use in the pipeline.

Getting Error while Passing variables extracted from shell in Jenkinsfile

I am setting up Jenkins pipeline, but getting an error while Passing variables extracted from the shell in the environment
pipeline {
agent any
environment {
PHP_CHANGE_SET = sh (script: "git diff-tree --no-commit-id --name-only -r HEAD | grep '.php'",returnStdout: true).trim()
}
I am getting mentioned ERROR
[Pipeline] { (Declarative: Post Actions)
[Pipeline] sh
Required context class hudson.FilePath is missing
Perhaps you forgot to surround the code with a step that provides this, such as: node
Error when executing failure post condition:
org.jenkinsci.plugins.workflow.steps.MissingContextVariableException: Required context class hudson.FilePath is missing
at org.jenkinsci.plugins.workflow.steps.StepDescriptor.checkContextAvailability(StepDescriptor.java:260)
at org.jenkinsci.plugins.workflow.cps.DSL.invokeStep(DSL.java:262)
at org.jenkinsci.plugins.workflow.cps.DSL.invokeMethod(DSL.java:178)
at org.jenkinsci.plugins.workflow.cps.CpsScript.invokeMethod(CpsScript.java:122)
I need PHP files name only which are in commit and store in variable
As mentioned in the comment, you cannot use it outside node block. If you really need to do this and this is the first thing you want for your job(A), what you can do is make another job (B) and there run this command in the directory you want and then trigger this job(A). You can have "PHP_CHANGE_SET" as a parameter which you can pass from job B.

How to take the result of a precious build step in Jenkins with Groovy?

Is there an example script of taking the previous build step's return code? I would like to know how to do this with Groovy. The previous build step is running an SSH command remotely and returns a specific return code. How can I read this return code in the next build step with Groovy?
If you go to the pipeline snippet generator from a pipeline job in the Jenkins UI (click on 'pipeline syntax' on the left) it will give you the syntax of each step like "sh". For a shell command you can do it like this example:
pipeline {
// Assumes you have Linux agents..
agent any
stages{
stage('Test') {
steps {
script {
def result = sh returnStatus: true, script: 'ls -a'
echo "Return code of shell script: ${result}"
}
}
}
}
}
I don't know if there is any way of getting it for the previous step, if you did not get the result like this for every step though.
In case of failure, when the returnStatus is explicitly requested like this, an exception is not thrown so you will need to handle the return status and fail the job explicitly with error('message..') if that is what is required.

How can I run new gradle task?

I have created a new gradle task in build.gradle:
task callCL(type: Exec) {
println "hello"
commandLine './rerun.sh'
}
Which suppose to run rerun.sh:
#!/bin/bash
cucumber -f rerun --out rerun.txt
file="rerun.txt"
if [ -f "$file" ] then
cucumber #rerun.txt
rm $file
fi
I'm using IntelliJ as an IDE. How can I run this task?
I have tried to run in the zshell console and got this error:
gradle callCL
zsh: command not found: gradle
But in the IDE I use gradle all the time so it must be installed.
How can I fix this? And is my writing ok?
Try this:
1. Make sure GRADLE_HOME, GRADLE_OPTS are set.
2. Make sure $PATH has GRADLE_HOME/bin in it.
3. which gradle should return you a valid output.
4. then, see below, if this works on command prompt, then your IDE setting just need to know where's is GRADLE_HOME aka its installed / executable (either gradle or gradle.bat)
NOTE: I have used my own dummy rerun.sh file, you can you use build.gradle (as shown below).
$ cat rerun.sh
#!/bin/bash
echo Im re-running a command echo
echo something
echo ...
echo
$ cat build.gradle
task callCL(type: Exec) {
println "-----"
println "hello"
println "-----"
executable "bash"
args "-c", "bash ./rerun.sh"
//The following will do as well as magic number in bash is already set to #!/bin/bash
//args "-c", "./rerun.sh"
}
$ /cygdrive/c/gradle-2.0/bin/gradle callCL
-----
hello
-----
:callCL
Im re-running a command echo
something
...
BUILD SUCCESSFUL
Total time: 2.006 secs
This looks like problem with gradle not being found on path (in your shell).
You may use GVM to easily install gradle so that its available on your PATH.

Resources