How to send a html file in the Email body based on multiple projects?
with the below straight forward code am able to send the mail but if i use " if else condition" then its failing, is it possible to use if condition with in the format?
straight forward code:
always {
emailext mimeType: 'text/html',
body: '${FILE,path="./logs/${JOB_NAME}_Build_${BUILD_NUMBER}/misc/email_dashboard.html"}',
subject: '${JOB_NAME} Report',
to: 'xyz.com'
}
I am trying to achieve something like this:
post {
success {
archiveArtifacts 'logs/${JOB_BASE_NAME}_Build_${BUILD_NUMBER}/**/*, logs/static_results/*'
script {
load "logs/${JOB_BASE_NAME}_Build_${BUILD_NUMBER}/display/pipeline_vars.groovy"
}
}
if ((${NODE_NAME}.contains("KG"))&&(${JOB_NAME}.contains("Nightly"))) {
always {
emailext mimeType: 'text/html',
body: '${FILE,path="./logs/${JOB_NAME}_Build_${BUILD_NUMBER}/misc/email_dashboard.html"}',
subject: '${JOB_NAME} Report',
to: 'xyz.com'
}
}
else if ((${NODE_NAME}.contains("MT")) &&(${JOB_NAME}.contains("Feature"))) {
always {
emailext mimeType: 'text/html',
body: '${FILE,path="./logs/${JOB_NAME}_Build_${BUILD_NUMBER}/misc/email_dashboard.html"}',
subject: '${JOB_NAME} Report',
to: 'xyz.com'
}
}
}
The issue here is that you cannot have always inside an if-else block. In Declarative pipeline syntax, you will have to use if-else inside a script block as shown below:
pipeline {
agent { label 'windows' }
//agent { label 'linux' }
stages {
stage('Echo') {
steps {
echo 'Inside Echo block'
}
}
}
post {
always {
script {
if ((env.NODE_NAME == "windows")) {
echo "Running on ${env.NODE_NAME} node"
}
else if ((env.NODE_NAME == "linux")) {
echo "Running on ${env.NODE_NAME} node"
}
}
}
}
}
Output:
Below code solved my problem:
always {
script {
if (env.JOB_NAME.contains('Nightly'))
{
emailext (
to: '${DEFAULT_RECIPIENTS}',
subject: "${env.JOB_NAME}-Report",
body: '${FILE,path="./logs/${JOB_NAME}_Build_${BUILD_NUMBER}/misc/xyz.html"}',
attachLog: true,
attachmentsPattern: 'logs/${JOB_NAME}_Build_${BUILD_NUMBER}/misc/xyz.png',
)
}
}
}
Related
Below is my declarative pipeline code to deploy code to 2 environments upon approval from UAT lead. But UAT lead would like to approve to deploy one environment . Second environment he would like to after a day or so ( this can be day or few days . Unpredictable) . How can it be achieved ? . Sleep / timeout does work here . Two separate approval stage can be done ?
#Library('xxxxxx') _
import jenkins.model.*
def userInput
def builduserid
def buildusername
def MANIFESTFILE
def SNAPSHOT
def BUILD_TIMESTAMP
def ucdDeployProcess
def deplprocess = env.DEPLOYPROCESS.split(",").findAll { it }.collect { it.trim() }
node("BDP") {
wrap([$class: 'BuildUser']) {
builduserid = env.BUILD_USER_ID
buildusername = env.BUILD_USER
}
}
pipeline {
agent { label 'BDP'}
stages {
stage ('Generate and Create Consolidated Snapshot') {
steps {
println "Cleaning workspace"
step([$class: 'WsCleanup'])
dir('') {
git url: 'xxxxx'
}
dir('scripts') {
git url: 'xxxxx'
}
script {
def now = new Date()
BUILD_TIMESTAMP=now.format("yyyyMMddHHmm", TimeZone.getTimeZone('UTC'))
env.MANIFESTFILE="${ucdApplication}_${RELEASE}_Manifest.csv"
env.SNAPSHOT="${ucdApplication}_${RELEASE}_${BUILD_TIMESTAMP}"
sh(script: '$WORKSPACE/scripts/scripts/SelfServiceBaselineVerificationPrePareForSnapshot.ksh "$ucdApplication" "${COMPSNAPSHOT}" "$ucdApplication"/"${MANIFESTFILE}"')
def props = readProperties file: 'env.cfg' //readProperties is a step in Pipeline Utility Steps plugin
env.SnapshotContent = props.COMBINEDSNAPSHOTVERSION
}
}
post {
failure {
emailext body: '''
<div>Hi Application Team</div>
<br>
<div>
<br>
<br>
<h4>Failed Checks: </h4>
<div style="margin-left: 50px;">
${BUILD_LOG_REGEX, regex="FAILED!", showTruncatedLines=false, escapeHtml=true, defaultValue="Nothing found, please check logs for other errors", matchedLineHtmlStyle="color:red;"}
</div>
<br>
<br>
</div>
<br>
<div>Thank you</div>
''',
mimeType: 'text/html',
to: "${builduserid}",
subject: '$ucdApplication Component Baseline Verification FAILED'
}
}
}
stage ('Create Consolidated Snapshot') {
steps {
ucdCreateCustomSnapshot()
}
}
stage ('Approval Stage') {
steps {
script {
emailext body: """
Hi Approver,<br/><br/><br/>
You have request from application team (${buildusername}) to deploy $ucdApplication application snapshot ${env.SNAPSHOT} to ${deploymentEnv} environment.<br/><br/><br/>
Please approve or reject deployement request: Click here.<br/><br/><br/>
Thanks,<br/><br/>
Happy Automation<br/>
""",
mimeType: 'text/html',
subject: "Deployment Approval Request",
from: "${builduserid}",
to: "${approverRecipients}"
userInput = input id: 'userInput',
message: 'Let\'s promote?.Please select to approve',
submitterParameter: 'submitter',
submitter: approverRecipients,
parameters: [
[$class: 'BooleanParameterDefinition', defaultValue: false, description: "Select this to deploy the code ${deploymentEnv} environment", name: deploymentEnv]]
if (userInput[deploymentEnv] == false ) {
currentBuild.result = 'ABORTED'
}
}
}
}
stage("Deploy to Acceptance") {
when {
expression { userInput[deploymentEnv] == true }
}
steps {
script {
for (int i = 0; i < deplprocess.size(); i++) {
env.ucdDeployProcess = deplprocess[i]
ucdCustomDeploySnapshot("${deploymentEnv}")
}
}
}
}
stage('Post Activities') {
steps {
println "Cleaning workspace"
step([$class: 'WsCleanup'])
}
}
}
post {
failure {
emailext body: """
Hi Team,<br/><br/><br/>
Code Deployment is failed for ${ucdApplication} application.<br/><br/><br/>
<p><font size="5" color="red">Deployment Request is failed for ${ucdApplication} application with snapshot ${env.SNAPSHOT}!</font></p>
<p>Check console output at "<a href='${BUILD_URL}consoleText'>${JOB_NAME} [${BUILD_NUMBER}]</a>"</p>
Thanks,<br/>
Happy Automation<br/><br/><br/>
""",
mimeType: 'text/html',
to: "${mailToRecipients},${builduserid}",
from: "${builduserid}",
subject: "FAILURE: Code Deployment is failed for '$ucdApplication' application with snapshot ${env.SNAPSHOT}"
}
success {
emailext body: """
Hi Team,<br/><br/><br/>
<p><font size="5" color="green">Code Deployment is success for $ucdApplication application for ${deploymentEnv} environment with snapshot ${env.SNAPSHOT}!</font></p>
Thanks,<br/>
Happy Automation<br/><br/><br/>
""",
mimeType: 'text/html',
to: "${mailToRecipients},${builduserid}",
from: "${builduserid}",
subject: "SUCCESSFUL: Code Deployment is success for '$ucdApplication' application with snapshot ${env.SNAPSHOT}"
}
aborted {
emailext body: """
Hi Team,<br/><br/><br/>
<p><font size="5" color="red">Deployment Request is rejected for ${ucdApplication} application by approver !</font></p>
Thanks,<br/>
Happy Automation<br/><br/><br/>
""",
mimeType: 'text/html',
to: "${mailToRecipients},${builduserid}",
from: "${builduserid}",
subject: "REJECTED: Code Deployment is rejected for $ucdApplication application with snapshot ${env.SNAPSHOT} by approver"
}
}
enter code here
}
jenkins-pipeline
I am trying to pass the variable value from one stage to the mail body of jenkins. But the variable value is not reflecting.
The code works if I create another stage and call the variable. But not in the
notifyStatusChangeViaEmail method block
Below is the example code.
def variable
pipeline {
agent { label 'master' }
options {
timestamps()
timeout(time: 1, unit: 'HOURS' )
}
stages{
stage('Variable'){
steps {
script{
variable = "Hi, Build is successful"
}
}
}
}
}
def notifyStatusChangeViaEmail(prevBuild) {
def subject
def body
if (currentBuild.previousBuild != null) {
switch (prevBuild.result) {
case 'FAILURE':
emailext attachLog: true, body: "${variable}", recipientProviders: [[$class: 'CulpritsRecipientProvider']], subject: 'Build Status : Build is back to Normal', to: 'sumith.waghmare#gmail.com';
break
case 'UNSTABLE':
emailext attachLog: true, body: "${variable}", recipientProviders: [[$class: 'CulpritsRecipientProvider']], subject: 'Build Status : Build is back to Normal', to: 'sumith.waghmare#gmail.com';
break
case 'SUCCESS':
emailext attachLog: true, body: "${variable}", recipientProviders: [[$class: 'CulpritsRecipientProvider']], subject: 'Build Status', to: 'sumith.waghmare#gmail.com';
break
}
}
}
The problem is that the variable is not defined in the scope of the function (and this post explains how scope of functions works in groovy).
To fix the issue you're seeing I would either make variable a parameter of notifyStatusChangeViaEmail, or I would remove the def variable statement, because that would make variable a global variable and so the function would be able to access it.
Examples:
Making the variable, a parameter of notifyStatusChangeViaEmail:
pipeline {
agent { label 'master' }
options {
timestamps()
timeout(time: 1, unit: 'HOURS' )
}
stages {
stage('Send Email') {
steps {
script {
def emailBody = "Hi, Build is successful"
// I assume that prevBuild is defined somewhere already
notifyStatusChangeViaEmail(prevBuild, emailBody)
}
}
}
}
}
def notifyStatusChangeViaEmail(prevBuild, emailBody) {
if (currentBuild.previousBuild != null) {
switch (prevBuild.result) {
case 'FAILURE':
emailext attachLog: true,
body: emailBody,
recipientProviders: [[$class: 'CulpritsRecipientProvider']],
subject: 'Build Status : Build is back to Normal',
to: 'sumith.waghmare#gmail.com';
break
//...
}
}
}
Using variable as a global:
// --> I deleted the "def variable" line <--
pipeline {
agent { label 'master' }
options {
timestamps()
timeout(time: 1, unit: 'HOURS' )
}
stages {
stage('Variable') {
steps {
script {
// There is no "def" when you first assign a value to
// `variable`, so it will become a global variable,
// which is a variable you can use anywhere in your file
variable = "Hi, Build is successful"
}
}
}
}
}
def notifyStatusChangeViaEmail(prevBuild) {
if (currentBuild.previousBuild != null) {
switch (prevBuild.result) {
case 'FAILURE':
emailext attachLog: true, body: variable, recipientProviders: [[$class: 'CulpritsRecipientProvider']], subject: 'Build Status : Build is back to Normal', to: 'sumith.waghmare#gmail.com';
break
//...
}
}
}
Using variable as a parameter:
I am trying to attach the content of some specific log files in mail body while nofifying a job execution failiure via email.
stage("Checkout Fusion Source") {
parallel 'A': {
node('LinuxNode') {
try {
echo "Hello World(Linux)"
} catch (Exception e) {
mail body: 'Failed!',
subject: 'Job has failed in Linux!',
to: 'abc#xyz.com',
attachmentsPattern: '/path/to/log/file/log_linux.out'
}
mail body: 'Passed!',
subject: 'Job has passed in Linux!',
to: 'abc#xyz.com',
attachmentsPattern: '/path/to/log/file/log_linux.out'
}
}, 'B': {
node('AixNode') {
try {
echo "Hello World(AIX)"
} catch (Exception e) {
mail body: 'Failed!',
subject: 'Job has failed in AIX!',
to: 'abc#xyz.com',
attachmentsPattern: '/path/to/log/file/log_aix.out'
}
mail body: 'Passed!',
subject: 'Job has passed in AIX!',
to: 'abc#xyz.com',
attachmentsPattern: '/path/to/log/file/log_aix.out'
}
}
}
This attachmentsPattern is not helping for the same.
P.S. My Jenkins version is 2.46.3.
Install the email-extension plugin and try something like this in your pipeline workflow.
emailext attachLog: true, body: "${currentBuild.result}: ${BUILD_URL}", compressLog: true, replyTo: 'email#xxx.com',
subject: "Build Notification: ${JOB_NAME}-Build# ${BUILD_NUMBER} ${currentBuild.result}", to: 'email123#xxx.com'
I have many similar configs in declarative pipelines, like agent, tools, options, or post section. Is there any option to define those option somehow, so that an individual job has only to define the steps (which may come from a shared library)?
There is a description at "Defining a more stuctured DSL", where there is something similar to that what I want to achieve, but this seems to apply to scripted pipelines.
pipeline {
agent {
label 'somelabel'
}
tools {
jdk 'somejdk'
maven 'somemaven'
}
options {
timeout(time: 2, unit: 'HOURS')
}
stages {
stage('do something') {
steps {
doSomething()
}
}
}
post {
failure {
emailext body: '${DEFAULT_CONTENT}', subject: '${DEFAULT_SUBJECT}',
to: 'some#mail.com', recipientProviders: [[$class: 'CulpritsRecipientProvider'], [$class: 'RequesterRecipientProvider'], [$class: 'DevelopersRecipientProvider']]
}
}
}
Actually, I tried something like that, trying to pass a closure to the pipeline, but this does not seem to work. Probably if it worked, there was some documentation on how to do it.
def call(stageClosure) {
pipeline {
agent {
label 'somelabel'
}
tools {
jdk 'somejdk'
maven 'somemaven'
}
options {
timeout(time: 2, unit: 'HOURS')
}
stages {
stageClosure()
}
post {
failure {
emailext body: '${DEFAULT_CONTENT}', subject: '${DEFAULT_SUBJECT}',
to: 'some#mail.com', recipientProviders: [[$class: 'CulpritsRecipientProvider'], [$class: 'RequesterRecipientProvider'], [$class: 'DevelopersRecipientProvider']]
}
}
}
}
and calling it somehow like this:
library 'my-library#master'
callJob{
stage('do something') {
steps {
doSomething()
}
}
}
I created a full flow
//SbtFlowDockerLarge.groovy
def call(int buildTimeout,String sbtVersion,List<String> fbGoals, List<String> masterGoals ){
def fbSbtGoals = fbGoals.join ' '
def masterSbtGoals = masterGoals.join ' '
pipeline {
agent { label DPgetLabelDockerLarge() }
options {
timestamps()
timeout(time: buildTimeout, unit: 'MINUTES')
disableConcurrentBuilds()
buildDiscarder(logRotator(daysToKeepStr: '35'))
}
stages {
stage('Prepare') {
steps {
setGitHubBuildStatus("Running Build", "PENDING")
echo "featureTask : ${fbSbtGoals}"
echo "masterTask : ${masterSbtGoals}"
}
}
stage('Build') {
when {
not { branch 'master' }
}
steps {
sbtTask tasks: "${fbSbtGoals}", sbtVersion: sbtVersion
}
}
stage('Deploy') {
when {
branch 'master'
}
environment {
TARGET_ENVIRONMENT='prod'
}
steps {
sbtTask tasks: "${masterSbtGoals}", sbtVersion: sbtVersion
}
}
}
post {
success {
setGitHubBuildStatus("Build complete", "SUCCESS")
}
failure {
setGitHubBuildStatus("Build complete", "FAILED")
}
always {
junit allowEmptyResults: true, testResults: '**/target/test-reports/*.xml'
dockerCleanup()
}
}
}
}
and here is the Jenkinsfile
#Library('aol-on-jenkins-lib') _
def buildTimeout = 60
def sbtVersion = 'sbt-0.13.11'
OathSbtFlowDockerLarge (buildTimeout, sbtVersion,['clean test-all'],['clean test-all publish'])
I have a pipeline with multiple steps, for example:
stage 'dev - compile'
node('master') {
//do something
}
stage 'test- compile'
node('master') {
//do something
}
stage 'prod- compile'
node('master') {
//do something
}
I want to send a email if something goes wrong in the job, how can I send an email no matter where the error got triggered, something like:
try {
/**
all the code above
**/
} catch(Exception e) {
mail the error
}
I think it is a better way to use the jenkins build in post section instead of using try catch:
pipeline {
agent any
stages {
stage('whatever') {
steps {
...
}
}
}
post {
always {
step([$class: 'Mailer',
notifyEveryUnstableBuild: true,
recipients: "example#example.com",
sendToIndividuals: true])
}
}
}
}
}
What I did to include useful information in my mail about the failure:
try {
stage 'checkout cvs'
node('master') {
/** CODE **/
}
stage 'compile'
node('master') {
/** CODE **/
}
stage 'test unit'
node('master') {
/** CODE **/
}
stage 'package'
node('master') {
/** CODE **/
}
stage 'nexus publish'
node('master') {
/** CODE **/
}
stage 'Deploy to App Server'
node('master') {
/** CODE **/
}
} catch(e) {
String error = "${e}";
// Make the string with job info, example:
// ${env.JOB_NAME}
// ${env.BUILD_NUMBER}
// ${env.BUILD_URL}
// and other variables in the code
mail bcc: '',
cc: '',
charset: 'UTF-8',
from: '',
mimeType: 'text/html',
replyTo: '',
subject: "ERROR CI: Project name -> ${env.JOB_NAME}",
to: "${mails_to_notify}",
body: "<b>${pivote}</b><br>\n\nMensaje de error: ${error}\n\n<br>Projecto: ${env.JOB_NAME} <br>Build Number: ${env.BUILD_NUMBER} <br> URL de build: ${env.BUILD_URL}";
error "${error}"
}
Well, your idea is absolutely correct, you just need to move mail after the catch block or use finally. Examples (in pseudocode):
try {
//code
email = 'success'
} catch(Exception e) {
// error handler: logging
email = 'failure'
}
send email
Or the same approach using the catchError pipeline built-in:
result = 'failure'
catchError { // this catches all exceptions and set the build result
//code
result = 'success' // we will reach this point only if no exception was thrown
}
send result
Or using finally:
try {
//code
} finally {
send email
}