Getting the build status in post-build script - jenkins

I would like to have a post-build hook or similar, so that I can have the same output as e. g. the IRC plugin, but give that to a script.
I was able to get all the info, except for the actual build status. This just doesn't work, neither as a "Post-build script", "Post-build task", "Parameterized Trigger" aso.
It is possible with some very ugly workarounds, but I wanted to ask, in case someone has a nicer option ... short of writing my own plugin.

It works as mentioned with the Groovy Post-Build Plugin, yet without any extra quoting within the string that gets executed. So I had to put the actual functionality into a shell script, that does a call to curl, which in turn needs quoting for the POST parameters aso.
def result = manager.build.result
def build_number = manager.build.number
def env = manager.build.getEnvironment(manager.listener)
def build_url = env['BUILD_URL']
def build_branch = env['SVN_BRANCH']
def short_branch = ( build_branch =~ /branches\//).replaceFirst("")
def host = env['NODE_NAME']
def svn_rev = env['SVN_REVISION']
def job_name = manager.build.project.getName()
"/usr/local/bin/skypeStagingNotify.sh Deployed ${short_branch} on ${host} - ${result} - ${build_url}".execute()

Use Groovy script in post-build step via Groovy Post-Build plugin. You can then access Jenkins internals via Jenkins Java API. The plugin provides the script with variable manager that can be used to access important parts of the API (see Usage section in the plugin documentation).
For example, here's how you can execute a simple external Python script on Windows and output its result (as well as the build result) to build console:
def command = """cmd /c python -c "for i in range(1,5): print i" """
manager.listener.logger.println command.execute().text
def result = manager.build.result
manager.listener.logger.println "And the result is: ${result}"

For this I really like the Conditional Build Step plugin. It's very flexible, and you can choose which actions to take based on build failure or success. For instance, here's a case where I use conditional build step to send a notification on build failure:
You can also use conditional build step to set an environment variable or write to a log file that you use in subsequent "execute shell" steps. So for instance, you might create a build with three steps: one step to compile code/run tests, another to set a STATUS="failed" environment variable, and then a third step which sends an email like The build finished with a status: ${STATUS}

Really easy solution, maybe not to elegant, but it works!
1: Catch all the build result you want to catch (in this case SUCCESS).
2: Inject an env variable valued with the job status
3: Do the Same for any kind of other status (in this case I catch from abort to unstable)
4: After you'll be able to use the value for whatever you wanna do.. in this case I'm passing it to an ANT script! (Or you can directly load it from ANT as Environment variable...)
Hope it can help!

Groovy script solution:-
Here I am using groovy script plugin to take the build status and setting it to the environmental variable, so the environmental variable can be used in post-build scripts using post-build task plugin.
Groovy script:-
import hudson.EnvVars
import hudson.model.Environment
def build = Thread.currentThread().executable
def result = manager.build.result.toString()
def vars = [BUILD_STATUS: result]
build.environments.add(0, Environment.create(new EnvVars(vars)))
Postscript:-
echo BUILD_STATUS="${BUILD_STATUS}"

Try Post Build Task plugin...
It lets you specify conditions based on the log output...

Basic solution (please don't laugh)
#!/bin/bash
STATUS='Not set'
if [ ! -z $UPSTREAM_BUILD_DIR ];then
ISFAIL=$(ls -l /var/lib/jenkins/jobs/$UPSTREAM_BUILD_DIR/builds | grep "lastFailedBuild\|lastUnsuccessfulBuild" | grep $UPSTREAM_BUILD_NR)
ISSUCCESS=$(ls -l /var/lib/jenkins/jobs/$UPSTREAM_BUILD_DIR/builds | grep "lastSuccessfulBuild\|lastStableBuild" | grep $UPSTREAM_BUILD_NR)
if [ ! -z "$ISFAIL" ];then
echo $ISFAIL
STATUS='FAIL'
elif [ ! -z "$ISSUCCESS" ]
then
STATUS='SUCCESS'
fi
fi
echo $STATUS
where
$UPSTREAM_BUILD_DIR=$JOB_NAME
$UPSTREAM_BUILD_NR=$BUILD_NUMBER
passed from upstream build
Of course "/var/lib/jenkins/jobs/" depends of your jenkins installation

Related

Jenkinsfile shell command not using env variables as expected

In my Jenkinsfile I want to dynamically find the unity version using a python script like so:
environment {
UNITY_EDITOR = bat(script: "py $WORKSPACE/get_versions.py --unity", returnStdout: true).trim()
UNITY_BASE = "C:/Program Files/Unity/Hub/Editor/$UNITY_EDITOR/Editor/Unity.exe"
UNITY_WRAPPER = "UnityBatchWrapper -silent-crashes -no-dialogs -batchmode -quit -unityPath \"$UNITY_BASE\""
}
post {
always {
script {
echo "Returning license"
licenseReturnStatus = bat (
script: "$UNITY_WRAPPER -returnlicense",
returnStatus: true
) == 0
}
}
From other stackoverflow answers this seems like it should work, but instead my Jenkins job errors out during the post-build step because $UNITY_WRAPPER isn't defined:
groovy.lang.MissingPropertyException: No such property: UNITY_WRAPPER for class: groovy.lang.Binding
I'm thinking the batch step is what's failing, even though Jenkins doesn't complain about it. I've also tried using $env.WORKSPACE and %WORKSPACE% and that doesn't work either.
I'm beginning to think $WORKSPACE doesn't exist til after the environments step...
Turns out I didn't have Python installed since it was an ephemeral GCP builder and I hadn't updated the node label yet.
For anyone reading this that has trouble with bat commands - be sure to put an # sign in front of your command like "#py ..." or else the command will be echoed in the output. Also trim your output so it doesn't have CRLF in it.

How to send credentials to a powershell script in a jenkins pipeline?

When executing the following code in a Jenkins pipeline, a "The following steps that have been detected may have insecure interpolation of sensitive variables" warning is being added to the build, with a link to https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#string-interpolation with explanation.
powershell script: """
\$ErrorActionPreference = "Stop"
cd "${WORKSPACE}\\MyDirectory"
& .\\myScript.ps1 -user "${creds_USR}" -passw "${creds_PSW}"
"""
I've already tried to change it as described in the link above, but then the variables don't seem to be replaced anymore.
powershell script: '''
\$ErrorActionPreference = \"Stop\"
cd \"$WORKSPACE\\MyDirectory\"
& .\\myScript.ps1 -user \"$creds_USR\" -passw \"$creds_PSW\"
'''
Would somebody know a working solution for this please?
Presumably you have a block like this that's generating those values:
environment {
creds = credentials('some-credentials')
}
So your build environment has those variables available to Powershell. Rather than interpolating the string that constitutes the Powershell script, then, just write the script to pull the data from the environment.
powershell script: '''\
$ErrorActionPreference = "Stop"
cd "$Env:WORKSPACE\MyDirectory"
& .\myScript.ps1 -user "$Env:creds_USR" -passw "$Env:creds_PSW"
'''

Active choice plugin Groovy script - Read environment variable

I want to use environment variable "WORKSPACE" in the active choice plugin groovy script.
I tried to retrieve it like this but it didnt work. WORKSPACE is not recognised.
${WORKSPACE}
Can anyone help me here?
Snippet:
def sout = new StringBuffer(), serr = new StringBuffer()
def proc ='/test/script.sh'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println sout
Here instead of /test/script.sh i need to access the script as following:
def process='$workspace path/test/script.sh
It's not possible to get that "environment" variable. A better name would be "property". Those are dynamically generated by Jenkins when the build starts, not when the parameters are set.
You can get some environment variables with EnvVars when you're setting the parameters, but they are very few. This can be tested on the Jenkins Script Console with the following code:
import hudson.EnvVars
for (envVarName in EnvVars.masterEnvVars.keySet()) {
def envVarValue = EnvVars.masterEnvVars[envVarName]
println("${envVarName}=${envVarValue}")
}
Result:
_=/etc/alternatives/java
HOME=/home/jenkins
LANG=en_US.UTF-8
LOGNAME=jenkins
NLSPATH=/usr/dt/lib/nls/msg/%L/%N.cat
PATH=/sbin:/usr/sbin:/bin:/usr/bin
PWD=/
SHELL=/bin/bash
SHLVL=2
TERM=xterm-256color
USER=jenkins
XFILESEARCHPATH=/usr/dt/app-defaults/%L/Dt
WORKSPACE property has more to it. The directory may not exist when you launch the build, specially if it's the first time you are doing it. My recommendation, if it makes sense to you, is to place the script in userContent directory and work out the rest based on that.

Raise Abort in Jenkins Job from Batch script

I have a Jenkins job, which do Git syncs and build the source code.
I added and created a "Post build task" option.
In 'post build task', I am searching for keyword "TIMEOUT:" in console output (this part is done) and want to declare job as Failed and Aborted if keyword matches.
How can I raise / declare the Job as Aborted from batch script if keyword matches. Something like echo ABORT?
It is easier if you want mark it as "FAIL"
Just exit 1 will do that.
It is tricky to achieve "Abort" from post build task plugin, it is much easier to use Groovy post build plugin.
The groovy post build provide rich functions to help you.
Such as match function:
def matcher = manager.getLogMatcher(".*Total time: (.*)\$")
if(matcher?.matches()) {
manager.addShortText(matcher.group(1), "grey", "white", "0px", "white")
}
Abort function:
def executor = build.executor ?: build.oneOffExecutor;
if (executor != null){
executor.interrupt(Result.ABORTED)
}
Br,
Tim
you can simply exit the flow and raise the error code that you want:
echo "Timeout detected!"
exit 1
Jenkins should detect the error and set-up the build as failed.
The error code must be between 1 and 255. You can chose whatever your want, just be aware that some code are reserved:
http://tldp.org/LDP/abs/html/exitcodes.html#EXITCODESREF
You can also consider using the time-out plugin:
https://wiki.jenkins.io/display/JENKINS/Build-timeout+Plugin
And another option is to build a query to BUILD ID URL/stop. Which is exactly what is done when you manually abort a build.
echo "Timeout detected!"
curl yourjenkins/job_name/11/stop

Multiple value parameter in jenkins

I have a situation where i need to use multiple value parameter or using extended-choice-parameter for Jenkins where we can select multiple options for my parameter.
I have different protractor test suites {Suite1, Suite2, Suite3, Suite4} which i am using as parameter of build for user to select which suite they want to execute. If they select multiple suite in option, how should i read those values in my shell script?
Currently i am using $Suite to read value but i am not sure what should i use to read multiple values selected. Can someone please help?
One option is:
get input of simple params (S1, S2)
build the string using 'execute shell'
save it to file in the workspace
inject it with the EnvInject plugin
execute-shell block:
#!/bin/sh
SUITS="{"
if [ "${S1}" = "test-1" ]; then
SUITS="${SUITS}test-1 "
fi
if [ "${S2}" = "test-2" ]; then
SUITS="${SUITS}test-2 "
fi
SUITS="${SUITS}}"
# SUITS="{test-1 test2- }"
cat "SUITS=${SUITS}" > suits.file
Then inject the file using the EnvInject plugin and SUITS will be available in the workspace

Resources