Jenkins boolean expression not evaluating as expected - jenkins

I'm working on a Jenkins job that will allow users to run tasks against the the load balancers in our development and production environments, and there is a requirement for an "are you sure?" check for jobs run against the production environment.
I've added a simple, annoying checkbox as below, but it always acts as if the box is not checked.
pipeline {
parameters {
choice(
name: 'ANSIBLE_LB_ENV',
choices: ['---', 'dev', 'prod'],
description: 'Environment against which to run the LB config.'
)
booleanParam(
name: 'ANSIBLE_LB_SECRET_BUTTON',
defaultValue: false,
description: 'Secret Button.'
)
}
stages {
stage('sanityCheck') {
steps {
script {
echo "ANSIBLE_LB_ENV: ${ANSIBLE_LB_ENV}"
echo "ANSIBLE_LB_SECRET_BUTTON: ${ANSIBLE_LB_SECRET_BUTTON}"
if( ANSIBLE_LB_ENV == '---' ) {
currentBuild.result = 'ABORTED'
error("You must select a valid environment.")
}
if( ( ANSIBLE_LB_ENV == 'prod' ) && ( ANSIBLE_LB_SECRET_BUTTON != true ) ) {
currentBuild.result = 'ABORTED'
error("If you want to touch production you have to click the secret button.")
}
}
}
}
}
}
Example output:
14:51:43 ANSIBLE_LB_ENV: prod
14:51:43 ANSIBLE_LB_SECRET_BUTTON: true
ERROR: If you want to touch production you have to click the secret button.
Finished: ABORTED
I've made if( ( ANSIBLE_LB_ENV == 'prod' ) && ( ANSIBLE_LB_SECRET_BUTTON != true ) ) {...} as explicitly-defined as I can, but it just won't let me do anything when prod is selected.

ANSIBLE_LB_SECRET_BUTTON is returned as a String, not a Boolean :)
So simply,
if( ( ANSIBLE_LB_ENV == 'prod' ) && ( ANSIBLE_LB_SECRET_BUTTON != "true" ) ) {...}

Related

Jenkins cron schedule Invalid trigger type "parameterizedCron"

I'm trying to run only Stage C in pipeline every night based on the parameters. But pipeline is throwing me Invalid trigger type "parameterizedCron" error. Below is my pipeline script. Please help what could be the issue. Also my pipeline is not triggering via cron job i need to trigger manually.
pipeline {
agent any
}
parameters {
choice(
name: 'ENV',
choices: [ 'uat', 'perf' ],
)
booleanParam(
name: 'RUN',
defaultValue: true
)
}
triggers {
parameterizedCron('''
17 14 * * * %RUN=true;ENV=uat
''')
}
stages {
stage ('A') {
}
stage ('B') {
}
stage('C') {
when {
expression { env.RUN || env.ENV == 'uat' }
}
## RUN THIS STAGE
}
}
Have you installed and enabled the plugin?
If you freshly installed the plugin try restarting Jenkins.

The jenkins job is not continue after checking the if statement

stage('Checkout')
{
steps
{
checkout scm
script
{
if (params.myParam == '') { // and/or whatever condition you want
currentBuild.result = 'ABORTED'
error('myParam not set')
}
}
}
}
Above will Abort the build if parameter is null, working as expected.But when i give the value on parameter the job is still failing, not taking the value or passing the build.
The == '' (equality operator) also needs to be declared that it represents 'null' to satisfy the boolean value.
As this is not declared, any value in that parameter will meet the condition to error/false, see the slight change to your stage below:
stage('Checkout') {
steps {
checkout scm
script {
if(params.myParam == '' || params.myParam == null) {
currentBuild.result = 'ABORTED'
error('myParam not set')
} else {
//whatever condition you want
}
}
}
}

Groovy script for a Jenkins multijob pipeline

I have a multijob pipeline that triggers several other builds to run. It takes in a couple of choice parameters (PRODUCT and BRANCH) to separate the builds into different groups. The UI was easy to set up and works well. Now I need to transfer the same functionality onto a Groovy script instead of using the UI. I have the script below, but it's not working. I'm getting the following error message:
eCaught: groovy.lang.MissingMethodException: No signature of method...
I'm pretty sure my syntax is way off:
pipeline {
parameters {
choice(
choices: ['A', 'B'],
description: 'Select which set of artifacts to trigger',
name: 'PRODUCT')
choice(
choices: ['develop', 'release'],
description: 'Select which branch to build the artifacts from',
name: 'BRANCH')
}
stages {
stage ('Build') {
when {
expression {
env.PRODUCT == 'A' && env.BRANCH == 'release'
}
}
steps {
parallel (
build (job: '../../Builds/artifact1/release'),
build (job: '../../Builds/artifact2/release'),
build (job: '../../Builds/artifact3/release'),
)
}
when {
expression {
env.PRODUCT == 'A' && env.BRANCH == 'develop'
}
}
steps {
parallel (
build (job: '../../Builds/artifact1/develop'),
build (job: '../../Builds/artifact2/develop'),
build (job: '../../Builds/artifact3/develop'),
)
}
when {
expression {
env.PRODUCT == 'B' && env.BRANCH == 'release'
}
}
steps {
parallel (
build (job: '../../Builds/artifact4/release'),
build (job: '../../Builds/artifact5/release'),
build (job: '../../Builds/artifact6/release'),
}
when {
expression {
env.PRODUCT == 'B' && env.BRANCH == 'develop'
}
}
steps {
parallel (
build (job: '../../Builds/artifact4/develop'),
build (job: '../../Builds/artifact5/develop'),
build (job: '../../Builds/artifact6/develop'),
)
}
}
}
}
Inside the steps , run the build in a script segment, it might help
script{
j1BuildResult = build job: "Compile", propagate: true, wait: true, parameters: [
//booleanParam(name: 'portal', value: env.PORTAL),
string(name: 'BRANCH', value: params.BRANCH),
booleanParam(name: 'portal', value: false),
string(name: 'db', value: params.SCHEME_NAME),
]
}

Jenkinsfile exit a parallel stage when parameter is empty

I have the belo Jenkinsfile where I take user input for one and/or two parallel steps/stages. If the user input is empty, how can I exit that step/stage?
For example, if the user didn't enter any value for firstTask_build_number I need to echo "firstTask_build_number is empty - aborting firstTask!" and exit that. How can I exit safely?
pipeline {
agent any
parameters {
string(name: 'firstTask_build_number', defaultValue: '', description: 'Build ID of firstTask')
string(name: 'secondTask_build_number', defaultValue: '', description: 'Build ID of secondTask')
}
stage("Parallel") {
steps {
parallel (
"firstTask" : {
if (firstTask_build_number.size() == 0) {
echo "firstTask_build_number is empty - aborting firstTask!"
}
else {
//do some stuff
}
},
"secondTask" : {
if (secondTask_build_number.size() == 0) {
echo "secondTask_build_number is empty - aborting secondTask!"
}
else {
//do some stuff
}
}
)
}
}
}
You can just return out of it.
parallel (
"firstTask" : {
if (firstTask_build_number.size() == 0) {
echo "firstTask_build_number is empty - aborting firstTask!"
return
}
else {
//do some stuff
}
}
)

How do you set Jenkins stage or pipeline parallel branch status (unstable, failure etc) for use in Stage view and Blue Ocean UI?

Overview
I'm currently configuring a pipeline consisting of a number of platform builds. At the beginning of the pipeline, a user can select which platforms to build or skip.
Depending on whether the 'build' stage for each platform passes or fails, steps in downstream stages can check the status of that platform build and determine whether or not to run. This allows the pipeline to try and complete the other platforms (if confirmed by user to do so) if one or more platforms fail.
Progress
As it stands, my pipeline achieves this, allowing a user to include/exclude platforms at the start of the pipeline and authorise the pipeline to continue building if a platform fails (but marking the pipeline as a failure). This allows archiving of build files/ publishing gtests etc which may be done in downstream stages/steps. Here is my Jenkinsfile:
// Specify whether or not to build platform by default
def buildDefinitions = [ 'windows' : true , 'macos' : true , 'ubuntu' : true ]
// Keep track of builds that fail
def failedBuilds = [:]
stage('Build Customisation') {
try {
// Wait limited amount of time for user input
timeout(time: 30, unit: 'SECONDS') {
// Update the build definitions based on user input
buildDefinitions = input(
message: 'Toggle which builds to run (Abort will use default)',
// Use custom global function to generate boolean input parameters based on a map
// Sets default value to value in input map
parameters: generateInputBoolParams( buildDefinitions )
)
}
// Continue pipeline if user input not provided within time limit
} catch ( error ) {
echo 'Using default pipeline configuration...'
}
// Check that at least one build platform is selected
if ( !mapContainsTrue( buildDefinitions ) ) {
error 'No builds selected, aborting pipeline'
}
}
stage('Conditional Build') {
parallel (
'Windows' : {
// Prevent a build failure from terminating the pipeline after this stage
try {
// Check if windows build is set to run
if ( buildDefinitions['windows'] ) {
node('windows') {
checkout(scm)
bat 'build.bat default-windows'
}
} else {
echo 'Build was disabled by user'
}
// Catch an error in the build
} catch ( error ) {
// Make note that the build failed
failedBuilds['windows'] = true
// Set the pipeline status as failure
currentBuild.result = 'FAILURE'
}
},
'MacOS' : {
try {
if ( buildDefinitions['macos'] ) {
node('macos') {
checkout(scm)
sh './build.sh default-macos'
}
} else {
echo 'Build was disabled by user'
}
} catch ( error ) {
failedBuilds['macos'] = true
currentBuild.result = 'FAILURE'
}
},
'Ubuntu' : {
try {
if ( buildDefinitions['ubuntu'] ) {
node('ubuntu') {
checkout(scm)
sh './build.sh default-ubuntu'
}
} else {
echo 'Build was disabled by user'
}
error 'test error'
} catch ( error ) {
failedBuilds['ubuntu'] = true
currentBuild.result = 'FAILURE'
}
}
)
// Check if any builds have been marked as failed
if ( mapContainsTrue( failedBuilds ) ) {
// Remove failed builds from the original map of enabled builds
def updatedBuildDefinitions = subtractMap( buildDefinitions, failedBuilds )
// Check that there are builds left to run
if ( mapContainsTrue( updatedBuildDefinitions ) ) {
// Update the original build map
buildDefinitions = updatedBuildDefinitions
// Lists the failed builds and asks whether to continue or abort the pipeline
timeout(time: 30, unit: 'SECONDS') {
input(
message: 'Builds failed ' + getKeyset( failedBuilds ) + ', do you want to continue the pipeline and skip failed builds?'
)
}
} else {
// Throw an error to terminate the pipeline if no builds are left to run
error 'No builds left to run'
}
}
}
stage('Conditional Downstream') {
parallel (
'Windows' : {
if ( buildDefinitions['windows'] ) {
echo 'You chose to run the windows build!'
} else {
echo 'The windows build was skipped'
}
},
'MacOS' : {
if ( buildDefinitions['macos'] ) {
echo 'You chose to run the macos build!'
} else {
echo 'The macos build was skipped'
}
},
'Ubuntu' : {
if ( buildDefinitions['ubuntu'] ) {
echo 'You chose to run the ubuntu build!'
} else {
echo 'The ubuntu build was skipped'
}
}
)
}
And my global functions:
// subtractMap.groovy
def call ( map1, map2 ) {
return map1 - map2
}
// mapContainsTrue.groovy
boolean call ( array ) {
for ( entry in array ) {
if ( entry.value == true ) {
isBuildConfigValid = true
return true
} else {
return false
}
}
}
// getKeyset.groovy
def call ( map ) {
return map.keySet() as String[]
}
// generateInputBoolParams.groovy
def call ( array ) {
def parameterList = []
for ( item in array ) {
parameterList.add( booleanParam(defaultValue: item.value, name: item.key) )
}
return parameterList
}
Problem
While the general functionality works, the UI response does not, aside from marking the pipeline as a failure. I would like to be able to mark the parallel branch as a failure so that in Blue Ocean UI, it is easy to see which platform failed to build.
Blue Ocean UI with failed parallel branch in try/catch block
It would also be useful to mark the stage as failed so when not in Blue Ocean UI, the Stage View shows which one failed (unless this only happens if the pipeline is terminated in that stage) although once Blue Ocean is out of Beta this wouldn't really be a problem anymore.
Stage View failed stage (Above) and as is (Below)
Question
How can I mark the parallel branch as failed so that it shows up in Blue Ocean UI with a red cross? Perhaps with an environment variable like currentBuild.result
Is a similar thing possible with the whole stage so that it shows up in Stage View? (Less important)
The UI response can be achieved by wrapping both the parallel step and the stage step in a try block, throwing the error from the try/catch block within the parallel branch up to the stage block. Not as clean as setting a property but does have the correct UI response for both Blue Ocean and Stage View.
try {
stage('example') {
try {
parallel (
'A' : {
try {
// Example...
}
catch (error) {
// Mark branch as failed somewhere
throw error
}
},
'B' : {
try {
// Example...
}
catch (error) {
// Mark branch as failed somewhere
throw error
}
}
)
}
catch (error) {
throw (error)
}
finally {
// Parallel branch A failed, do you want to continue? etc...
}
}
}
catch (error) {
println (error)
}
This works for me in Blue Ocean :
stage("Global Stage") {
def parallelStages = [failfast: false]
parallelStages["Branch 1"] = {
//Code for branch 1
}
parallelStages["Branch 2"] = {
//Code for branch 2
}
catchError(buildResult: 'SUCCESS', message: 'Branch Failed', stageResult: 'UNSTABLE')
{ parallel parallelStages }
}
This properly marks the failed parallel branches as UNSTABLE in Blue Ocean, does not touch other stage results and marks the overall build as SUCCESS

Resources