Declarative pipeline - groovy

i need to execute the jenkinsfile different behaviors, like suppose:
if the build will trigger manually jenkinsfile executes till build
stage and
if the build trigger by change scm/timer then need to
execute all the stages.
I am a new to Jenkins file(groovy script) so could anyone please help me where and how i can apply condition in Jenkins file. please give me an example for the same with the condition
Jenkinsfile:
pipeline{
agent any
stage('Checkout'){
checkout(scm)
}
stage('build'){
echo "build is success"
}
stage('deploy'){
echo " deployment successfully completed "
}
stage('email notify'){
emailext attachLog: true, body: 'job $job has been triggered', compressLog: true, subject: 'Email notification', to: 'mail id'
}
}

You can use the when directive: https://jenkins.io/doc/book/pipeline/syntax/#when .
Paired up with something like this: currentBuild.rawBuild.getCauses()[0].toString().contains('UserIdCause'), a stage will run whether or not (you decide) if this evaluates to true
This should work:
when {
expression { return currentBuild.rawBuild.getCauses()[0].toString().contains('UserIdCause') }
}
You also have the following from the syntax documentation:
when {
triggeredBy "TimerTrigger"
}

Related

Jenkinsfile - Pipeline job stuck at input() step

I'm running terraform pipeline through Jenkinsfile, where I'm using a input(...) block for the user approval, before apply. This is the code snippet:
stage('tf_plan') {
agent {
label: 'Jenkins-Linux-Dev'
}
steps {
sh(
label: 'Terraform Plan',
script: '''
#!/usr/bin/env bash
terraform plan -input=false -no-color -out=plan.tfplan'
'''
)
}
}
stage('tf_approve') {
when { expression { return env.Action == 'apply' } }
options {
timeout( time: 1, unit: 'MINUTES' )
}
steps {
input(
message: 'Proceed with above Terraform Plan??',
ok: 'Proceed'
)
}
}
stage('tf_apply') {
agent {
label: 'Jenkins-Linux-Dev'
}
when { expression { return env.Action == 'apply' } }
steps {
sh(
label: 'Terraform Apply',
script: '''
#!/usr/bin/env bash
terraform apply -auto-approve -input=false -no-color plan.tfplan'
'''
)
}
}
stage('tf_plan') is working absolutely fine but when env.Action = 'apply', it's not moving any further after stage('tf_approve'). It's stuck at Proceed or Abort step - not moving forward at all clicking either of 'em. Any idea what might be the problem?
Any help would be very much appreciated.
-S
My setup:
Jenkins 2.277.1
Groovy 2.3
Pipeline 2.6
Pipeline Utility Steps 2.6.1
And the following code works fine:
pipeline {
agent any
parameters {
choice(choices: ['-', 'apply'], name: 'Action')
}
stages {
stage('Trigger Promotion') {
when { expression { return env.Action == 'apply' } }
options {
timeout( time: 1, unit: 'MINUTES' )
}
steps {
script {
input(
message: 'Proceed with above Terraform Plan??',
ok: 'Proceed'
)
}
}
}
}
}
Therefore, I don't think the issue is with the input step. Need more info on what's going on with Jenkins and its workers at that moment. Try grabbing logs of Jenkins main node.
P.S.: I'd suggest avoiding PascalCase variables in Groovy. It's usually used to declare classses

how to call a groovy function in an active choice parameter in Jenkins pipeline

I have a requirement where user has to select multiple resource names from the input block. I tried active choice parameter inside the user input step, and its working when I hardcode the values but the output is empty when I call a groovy function to dynamically generate the value. This function will return a list of resources names based on the environment passed earlier at the start of the job. So hardcoding the values won't be ideal for my situation. Any ideas on how to call a groovy function into the active choice parameter block?
pipeline {
agent any
stages{
stage('test user input') {
steps {
timestamps {
script {
def userInput = input(
parameters: [[$class: 'ChoiceParameter', choiceType: 'PT_CHECKBOX', description: 'Please select the values', filterLength: 1, filterable: false, name: 'testvalues', randomName: 'choice-parameter-37737065277176157', script: [$class: 'GroovyScript', fallbackScript: [classpath: [], sandbox: false, script: '''return[
\'error\'
]'''], script: [classpath: [], sandbox: false, script: '''def getvalues(){
return[
\'values1\',
\'values2\',
\'values3\',
\'values4\'
]
}
def value=getvalues()
return value''']]]]
)
println("input: " + userInput)
}
}
}
}
}
}

Jenkins pipeline skip stage if copying fails

Let's say we have a simple pipeline setup like this:
pipeline {
stages {
stage('Stage1') {
sh '''
echo 'Copying files'
cp ./file1 ./directory1
'''
}
stage('Stage2') {
sh '''
echo 'This stage should still work and run'
cp ./directory2/files ./directory2/subdirectory
'''
}
stage('Stage3') { ... }
...
}
}
Whenever I don't have the files in Stage1 or Stage2, it fails the build saying:
'cp cannot stat ./file1 ./directory1' or 'cp cannot stat ./directory2/files ./directory2/subdirectory'
Of course if the files exist, both stages work perfectly fine. The problem is that the build fails for the rest of the stages if a stage fails. So if Stage1 fails because there are no files, it fails every stage after and they don't even run, same goes for if Stage2 fails, then we know that Stage1 succeeded but then Stage3 and onwards fails and does not even run.
Is there a way to make it so that if the cp command fails and the cp cannot stat shows, to just skip the stage and proceed to the next one? Or at least make it so that only that stage fails and it can proceed to build the next stage(s)?
Here is an simple way of skipping the stage when a file does not exist, using the when directive:
pipeline {
agent any
stages {
stage('Stage1') {
when { expression { fileExists './file1' } }
steps {
sh '''
echo 'Copying files'
cp ./file1 ./directory1
'''
}
}
stage('Stage2') {
when { expression { fileExists './directory2/files' } }
steps {
sh '''
echo 'This stage should still work and run'
cp ./directory2/files ./directory2/subdirectory
'''
}
}
stage('Stage3') {
steps {
echo "stage 3"
}
}
}
}
In above case you have to specify the path twice, in the when directive and in the sh step, it is better to handle it in a another way e.g. using variables or closures.
Because of the restrictions in the declarative pipeline, I would recommend you to use the scripted pipeline instead.
This can be achieved using the catchError
pipeline {
agent any
stages {
stage('1') {
steps {
script{
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
echo 'Copying files'
cp ./file1 ./directory1
}
}
}
}
stage('2') {
steps {
script{
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
echo 'This stage should still work and run'
cp ./directory2/files ./directory2/subdirectory
}
}
}
}
stage('3') {
steps {
sh 'exit 0'
}
}
}
}
From above pipeline script, all stages will executed. If the cp command will not work for either of stage 1 or stage 2, it will show as failed for that particular stage but rest all stages will execute.
Similar to below screenshot:
Modified Answer
Following pipeline script include sh ''' ''', which need not have to be present inside the catchError block.
You can include only those commands inside catchError for which you want to catch the errors.
pipeline {
agent any
stages {
stage('1') {
steps {
sh """
echo 'Hello World!!!!!!!!'
curl https://www.google.com/
"""
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
echo 'Copying files'
cp ./file1 ./directory1
}
}
}
stage('2') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
echo 'This stage should still work and run'
cp ./directory2/files ./directory2/subdirectory
}
}
}
stage('3') {
steps {
sh 'exit 0'
}
}
}
}
You could just check if the file exists before you try to copy it using a conditional like this:
[ -f ./directory2/files ] && cp ./directory2/files ./directory2/subdirectory || echo "File does not exist"
Source and more info

How can I create parallel stages in Jenkins scripted pipeline?

I am trying to implement parallelization in my Jenkins pipeline code where I can run two stages in parallel. I know this is possible in declarative pipeline, but I am using scripted pipeline.
I've attempted to implement this by doing something like this:
parallel(
stage('StageA') {
echo "This is branch a"
},
stage('StageB') {
echo "This is branch b"
}
)
When I run this and look at this in Blue ocean, the stages do not run in parallel, but instead, StageB is executed after StageA.
Is it possible to have parallel stages in scripted jenkins pipeline? If so, how?
Try this syntax for scripted pipeline:
parallel(
"StageA": {
echo "This is branch a"
},
"StageB": {
echo "This is branch b"
}
)
It should look like this in Blue Ocean, this is what you expect right?
If you want to see the stages (and console output) in the classic view, you can use stage like this:
parallel(
"StageA": {
stage("stage A") {
echo "This is branch a"
}
},
"StageB": {
stage("stage B") {
echo "This is branch b"
}
}
)
This worked for me
stage('Check code quality') {
parallel {
stage('Run prospector') {
when {
expression { params.SKIP_PROSPECTOR == false }
}
steps {
checkout scm
sh 'echo "Running prospector..."'
sh 'make dockerized-run-prospector'
}
}
stage('Run Tests') {
when {
expression { params.SKIP_TESTS == false }
}
steps {
checkout scm
sh 'echo "Running tests..."'
sh 'make dockerized-test'
}
}
}
}
This runs stages inder the parent stage parallely.
Jenkins blue shows it like this

How to set quietperiod on Jenkins Pipeline

I have a pipeline with some boolean parameters. I'd like to add the quietPeriod as described in the docs but I'm struggling to get the syntax right. I tried:
properties([
parameters :[
booleanParam(name: 'foo', defaultValue: false, description: 'bar')
],
quietPeriod: 10
])
But that yields a
java.lang.UnsupportedOperationException: must specify $class with an implementation of interface java.util.List.
Does anyone know how to add this parameter correctly?
Use it as an option in the pipeline as follows:
pipeline {
agent any
options {
quietPeriod(300) //Quiet period in seconds
}
stages {
stage('1') {
steps {
println("Hello")
}
}
}
}
From this Jenkins ticket in JIRA it seems like the feature is only available by default when the Declarative Pipeline syntax is used.
As a workaround I found that doing
currentBuild.rawBuild.getParent().setQuietPeriod(210)
works like a charm. You can put it right after setting the properties, like this:
properties([
parameters :[
booleanParam(name: 'foo', defaultValue: false, description: 'bar')
]
])
currentBuild.rawBuild.getParent().setQuietPeriod(210)

Resources