Jenkinsfile: Ask for input in a post condition block - jenkins

I'd like my Jenkins deploy pipeline to
attempt a shell command,
provide an input step if that command fails, and then
re-try the command and continue the pipeline on "ok".
Here's the (start) of my attempt to do so.
stage('Get config') {
steps {
sh 'aws appconfig get-configuration [etc etc]'
}
post {
failure {
input {
message "There is no config deployed for this environment. Set it up in AWS and then continue."
ok "Continue"
}
steps {
sh 'aws appconfig get-configuration [etc etc]'
}
}
}
}
When running the input directly in a stage, this example does show the input. However, when putting it in the post { failure }, I get this error:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 27: Missing required parameter: "message" # line 27, column 21.
input {
^
Do Jenkins declarative pipelines allow input in post?
Is there a better way to accomplish my desired outcome?

As per documentation:
Post-condition blocks contain steps the same as the steps section.
This means that input in your code is interpreted as step instead of directive.
Solution using script syntax (try/catch would also be fine there):
stage('Get config') {
steps {
script {
def isConfigOk = sh( script: 'aws appconfig get-configuration [etc etc]', returnStatus: true) == 0
if ( ! isConfigOk ) {
input (message: "There is no config deployed for this environment. Set it up in AWS and then continue.", ok: "Continue")
sh 'aws appconfig get-configuration [etc etc]'
}
}
}
}
Using post section:
stage('Get config') {
steps {
sh 'aws appconfig get-configuration [etc etc]'
}
post {
failure {
input (message: "There is no config deployed for this environment. Set it up in AWS and then continue.", ok: "Continue")
sh 'aws appconfig get-configuration [etc etc]'
}
}
}
Remember that your approach with post section will ignore outcome of second aws appconfig get-configuration [etc etc] and fail. There is a way to change this behaviour but I wouldn't call this solution any clean.

Related

Define and access a variable in multiple steps of a jenkins pipeline

I came here from this post Defining a variable in shell script portion of Jenkins Pipeline
My situation is the following I have a pipeline that is updating some files and generating a PR in my repo if there are changes in the generated files (they change every couple of weeks or less).
At the end of my pipeline I have a post action to send the result by email to our teams connector.
I wanted to know if I could somehow generate a variable and include that variable in my email.
It looks something like this but off course it does not work.
#!groovy
String WasThereAnUpdate = '';
pipeline {
agent any
environment {
GRADLE_OPTS = '-Dorg.gradle.java.home=$JAVA11_HOME'
}
stages {
stage('File Update') {
steps {
sh './gradlew updateFiles -P updateEnabled'
}
}
stage('Create PR') {
steps {
withCredentials(...) {
sh '''
if [ -n \"$(git status --porcelain)\" ]; then
WasThereAnUpdate=\"With Updates\"
...
else
WasThereAnUpdate=\"Without updates\"
fi
'''
}
}
}
}
post {
success {
office365ConnectorSend(
message: "Scheduler finished: " + WasThereAnUpdate,
status: 'Success',
color: '#1A5D1C',
webhookUrl: 'https://outlook.office.com/webhook/1234'
)
}
}
}
I've tried referencing my variable in different ways ${}, etc... but I'm pretty sure that assignment is not working.
I know I probably could do it with a script block but I'm not sure how I would put the script block inside the SH itself, not sure this would be possible.
Thanks to the response from MaratC https://stackoverflow.com/a/64572833/5685482 and this documentation
I'll do it something like this:
#!groovy
def date = new Date()
String newBranchName = 'protoUpdate_'+date.getTime()
pipeline {
agent any
stages {
stage('ensure a diff') {
steps {
sh 'touch oneFile.txt'
}
}
stage('AFTER') {
steps {
script {
env.STATUS2 = sh(script:'git status --porcelain', returnStdout: true).trim()
}
}
}
}
post {
success {
office365ConnectorSend(
message: "test ${env.STATUS2}",
status: 'Success',
color: '#1A5D1C',
webhookUrl: 'https://outlook.office.com/webhook/1234'
)
}
}
In your code
sh '''
if [ -n \"$(git status --porcelain)\" ]; then
WasThereAnUpdate=\"With Updates\"
...
else
WasThereAnUpdate=\"Without updates\"
fi
'''
Your code creates a sh session (most likely bash). That session inherits the environment variables from the process that started it (Jenkins). Once it runs git status, it then sets a bash variable WasThereAnUpdate (which is a different variable from likely named Groovy variable.)
This bash variable is what gets updated in your code.
Once your sh session ends, bash process gets destroyed, and all of its variables get destroyed too.
This whole process has no influence whatsoever on Groovy variable named WasThereAnUpdate that just stays what it was before.

How would I store all failed stages of my declarative Jenkins pipeline

In my Jenkins pipeline, I have 15 stages. Now I have a post function at the end of the Jenkins file to send me an email about whether the whole process is failed or success. I would like to include all the stages that are failed in the email too. Using post in each stage is not a good idea, because I would receive 15 emails each time the job runs.
I am thinking of creating a list and save all failed env.STAGE_NAME in the list and print it at the end? But it would not allow me to do such a thing in the post.
I want to achieve something like:
pipeline {
agent { label 'master'}
stages {
stage('1') {
steps {
echo 'make fail'
}
}
stage('2') {
steps {
sh 'make fail'
}
}
...
stage('15') {
steps {
sh 'make fail'
}
}
}
post {
always {
echo 'ok'
}
failure {
"There are 3 stages have failed the test, which are: '1', '2' '15'"
}
}
}
How would I do it?

Chained multiple pipeline based on 'post' jenkins block

I'm beginner to Jenkins. I have code pipeline structure like this
Repo1 -> Repo2 -> Repo3 -> Deploy
I already created such hierarchy via GUI but I want to create it via pipeline as code.I want to create chain of pipelines where I clone different repos and perform tests on it and then continue to another repo based on current pipeline post result.
This is my jenkinsfile - (psuedo code like as it gives me error to build)
pipeline {
agent any
stages {
stage('Build Repo1') {
steps {
sh 'echo "repo1 build!"'
}
}
stage('Test Repo1') {
steps {
sh 'echo "repo success!"'
}
}
}
post {
success {
pipeline {
agent any
stages {
stage('Build Repo2') {
steps {
sh 'echo "build repo2!"'
}
}
stage('Test Repo2') {
steps {
sh 'echo "test repo2!"'
}
}
}
post {
success {
# continue to generate pipeline for repo3
echo 'This will always run'
}
failure {
echo 'This will run only if failed'
}
}
}
}
failure {
echo 'This will run only if failed'
}
unstable {
echo 'This will run only if the run was marked as unstable'
}
changed {
echo 'This will run only if the state of the Pipeline has changed'
echo 'For example, if the Pipeline was previously failing but is now successful'
}
}
}
Please help!

Jenkinsfile Pipeline errors: "expected a symbol" and "undefined section"

Can anyone explain why I get the following errors, and what can be a possible solution for them?
org.codehaus.groovy.control.MultipleCompilationErrorsException:
startup failed: WorkflowScript: 20: Expected a symbol # line 20,
column 4.
environment {
WorkflowScript: 17: Undefined section "error" # line 17, column 1.
pipeline {
The code in the Jenkinsfile is as follows:
#!groovy
def application, manifest, git, environment, artifactory, sonar
fileLoader.withGit('git#<reducted>', 'v1', 'ssh-key-credential-id-number') {
application = fileLoader.load('<reducted>');
manifest = fileLoader.load('<reducted>');
git = fileLoader.load('<reducted>');
environment = fileLoader.load('<reducted>');
}
pipeline {
agent { label 'cf_slave' }
environment {
def projectName = null
def githubOrg = null
def gitCommit = null
}
options {
skipDefaultCheckout()
}
stages {
stage ("Checkout SCM") {
steps {
checkout scm
script {
projectName = git.getGitRepositoryName()
githubOrg = git.getGitOrgName()
gitCommit = manifest.getGitCommit()
}
}
}
stage ("Unit tests") {
steps {
sh "./node_modules/.bin/mocha --reporter mocha-junit-reporter --reporter-options mochaFile=./testResults/results.xml"
junit allowEmptyResults: true, testResults: 'testResults/results.xml'
}
}
//stage ("SonarQube analysis") {
//...
//}
// stage("Simple deploy") {
// steps {
// // Login
// sh "cf api <reducted>"
// sh "cf login -u <reducted> -p <....>"
//
// // Deploy
// sh "cf push"
// }
// }
}
post {
// always {
// }
success {
sh "echo 'Pipeline reached the finish line!'"
// Notify in Slack
slackSend color: 'yellow', message: "Pipeline operation completed successfully. Check <reducted>"
}
failure {
sh "echo 'Pipeline failed'"
// Notify in Slack
slackSend color: 'red', message: "Pipeline operation failed!"
//Clean the execution workspace
//deleteDir()
}
unstable {
sh "echo 'Pipeline unstable :-('"
}
// changed {
// sh "echo 'Pipeline was previously failing but is now successful.'"
// }
}
}
Your Pipeline is mostly fine — adding Scripted Pipeline elements before the Declarative pipeline block is generally not a problem.
However, at the very start, you're defining an variable called environment (and git), which are basically overriding the elements declared by the various Pipeline plugins.
i.e. When you attempt to do pipeline { environment { … } }, the environment is referring to your variable declaration, which causes things to go wrong.
Rename those two variables, and you'll fix the first error message.
To fix the second error message, remove the attempts to declare variables from the environment block — this block is only intended for exporting environment variables for use during the build steps, e.g.:
environment {
FOO = 'bar'
BAR = 'baz'
}
The script block you have will work fine without these declarations. Alternatively, you can move those variable declarations to the top level of your script.
If you're using declarative pipeline (which you are, e.g. the outer pipeline step), then you may only declare the pipeline on the outer layer, e.g. you can't have variable and function definitions. This is the downside of using declarative pipeline.
More info here
As I see it you can solve this the following ways:
Use scripted pipeline instead
Move the code at the beginning to a global pipeline library (Might be tricky to solve variable scoping if a value is used in several places, but it should be doable.
Move the code at the beginning to an script step inside the pipeline and store the values as described here.

Cannot define variable in pipeline stage

I'm trying to create a declarative Jenkins pipeline script but having issues with simple variable declaration.
Here is my script:
pipeline {
agent none
stages {
stage("first") {
def foo = "foo" // fails with "WorkflowScript: 5: Expected a step # line 5, column 13."
sh "echo ${foo}"
}
}
}
However, I get this error:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 5: Expected a step # line 5, column 13.
def foo = "foo"
^
I'm on Jenkins 2.7.4 and Pipeline 2.4.
The Declarative model for Jenkins Pipelines has a restricted subset of syntax that it allows in the stage blocks - see the syntax guide for more info. You can bypass that restriction by wrapping your steps in a script { ... } block, but as a result, you'll lose validation of syntax, parameters, etc within the script block.
I think error is not coming from the specified line but from the first 3 lines. Try this instead :
node {
stage("first") {
def foo = "foo"
sh "echo ${foo}"
}
}
I think you had some extra lines that are not valid...
From declaractive pipeline model documentation, it seems that you have to use an environment declaration block to declare your variables, e.g.:
pipeline {
environment {
FOO = "foo"
}
agent none
stages {
stage("first") {
sh "echo ${FOO}"
}
}
}
Agree with #Pom12, #abayer. To complete the answer you need to add script block
Try something like this:
pipeline {
agent any
environment {
ENV_NAME = "${env.BRANCH_NAME}"
}
// ----------------
stages {
stage('Build Container') {
steps {
echo 'Building Container..'
script {
if (ENVIRONMENT_NAME == 'development') {
ENV_NAME = 'Development'
} else if (ENVIRONMENT_NAME == 'release') {
ENV_NAME = 'Production'
}
}
echo 'Building Branch: ' + env.BRANCH_NAME
echo 'Build Number: ' + env.BUILD_NUMBER
echo 'Building Environment: ' + ENV_NAME
echo "Running your service with environemnt ${ENV_NAME} now"
}
}
}
}
In Jenkins 2.138.3 there are two different types of pipelines.
Declarative and Scripted pipelines.
"Declarative pipelines is a new extension of the pipeline DSL (it is basically a pipeline script with only one step, a pipeline step with arguments (called directives), these directives should follow a specific syntax. The point of this new format is that it is more strict and therefore should be easier for those new to pipelines, allow for graphical editing and much more.
scripted pipelines is the fallback for advanced requirements."
jenkins pipeline: agent vs node?
Here is an example of using environment and global variables in a Declarative Pipeline. From what I can tell enviroment are static after they are set.
def browser = 'Unknown'
pipeline {
agent any
environment {
//Use Pipeline Utility Steps plugin to read information from pom.xml into env variables
IMAGE = readMavenPom().getArtifactId()
VERSION = readMavenPom().getVersion()
}
stages {
stage('Example') {
steps {
script {
browser = sh(returnStdout: true, script: 'echo Chrome')
}
}
}
stage('SNAPSHOT') {
when {
expression {
return !env.JOB_NAME.equals("PROD") && !env.VERSION.contains("RELEASE")
}
}
steps {
echo "SNAPSHOT"
echo "${browser}"
}
}
stage('RELEASE') {
when {
expression {
return !env.JOB_NAME.equals("TEST") && !env.VERSION.contains("RELEASE")
}
}
steps {
echo "RELEASE"
echo "${browser}"
}
}
}//end of stages
}//end of pipeline
You are using a Declarative Pipeline which requires a script-step to execute Groovy code. This is a huge difference compared to the Scripted Pipeline where this is not necessary.
The official documentation says the following:
The script step takes a block of Scripted Pipeline and executes that
in the Declarative Pipeline.
pipeline {
agent none
stages {
stage("first") {
script {
def foo = "foo"
sh "echo ${foo}"
}
}
}
}
you can define the variable global , but when using this variable must to write in script block .
def foo="foo"
pipeline {
agent none
stages {
stage("first") {
script{
sh "echo ${foo}"
}
}
}
}
Try this declarative pipeline, its working
pipeline {
agent any
stages {
stage("first") {
steps{
script {
def foo = "foo"
sh "echo ${foo}"
}
}
}
}
}

Resources