Overview
I am currently setting up a pipeline consisting of several platforms. At the beginning of the pipeline, the user can choose which platforms to create or skip.
Depending on whether the “build” phase for each platform goes through or fails, the steps in the downstream steps can check the build status of this platform and determine whether to launch it. This allows the pipeline to try and complete other platforms (if this is confirmed by the user) if one or more platforms do not work.
Progress
In its current form, my conveyor achieves this by allowing the user to enable / exclude platforms at the beginning of the conveyor and allow the conveyor to continue building if the platform fails (but marks the conveyor as a failure). This allows you to archive assembly / publication files, etc. that can be done in stages / steps downstream. Here is my Jenkins file:
def buildDefinitions = [ 'windows' : true , 'macos' : true , 'ubuntu' : true ]
def failedBuilds = [:]
stage('Build Customisation') {
try {
timeout(time: 30, unit: 'SECONDS') {
buildDefinitions = input(
message: 'Toggle which builds to run (Abort will use default)',
parameters: generateInputBoolParams( buildDefinitions )
)
}
} catch ( error ) {
echo 'Using default pipeline configuration...'
}
if ( !mapContainsTrue( buildDefinitions ) ) {
error 'No builds selected, aborting pipeline'
}
}
stage('Conditional Build') {
parallel (
'Windows' : {
try {
if ( buildDefinitions['windows'] ) {
node('windows') {
checkout(scm)
bat 'build.bat default-windows'
}
} else {
echo 'Build was disabled by user'
}
} catch ( error ) {
failedBuilds['windows'] = true
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'
}
}
)
if ( mapContainsTrue( failedBuilds ) ) {
def updatedBuildDefinitions = subtractMap( buildDefinitions, failedBuilds )
if ( mapContainsTrue( updatedBuildDefinitions ) ) {
buildDefinitions = updatedBuildDefinitions
timeout(time: 30, unit: 'SECONDS') {
input(
message: 'Builds failed ' + getKeyset( failedBuilds ) + ', do you want to continue the pipeline and skip failed builds?'
)
}
} else {
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:
def call ( map1, map2 ) {
return map1 - map2
}
boolean call ( array ) {
for ( entry in array ) {
if ( entry.value == true ) {
isBuildConfigValid = true
return true
} else {
return false
}
}
}
def call ( map ) {
return map.keySet() as String[]
}
def call ( array ) {
def parameterList = []
for ( item in array ) {
parameterList.add( booleanParam(defaultValue: item.value, name: item.key) )
}
return parameterList
}
Problem
While overall functionality works, the user interface response is no different from marking the pipeline as a failure. I would like to mark the parallel branch as a failure, so in Blue Ocean UI it is easy to see which platform could not be built.
Blue Ocean UI with unsuccessful parallel branch in try / catch block
, , Blue Ocean UI, Stage View , ( , ), Blue Ocean .
() ()