I like to commit my Jenkins email script to my working copy and use it with Email-ext.
So I wrote something like :
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building...'
}
}
}
post {
always {
echo 'Sending email...'
emailext body: '''${SCRIPT, template="${WORKSPACE}\\Src\\Scripts\\Jenkins\\groovy-html2.template"}''',
mimeType: 'text/html',
subject: "[Leeroy Jenkins] ${currentBuild.fullDisplayName}",
to: "user#company.com",
replyTo: "user#company.com",
recipientProviders: [[$class: 'CulpritsRecipientProvider']]
}
}
}
But I get the following mail:
Groovy Template file [${WORKSPACE}SrcScriptsJenkinsgroovy-html2.template] was not found in $JENKINS_HOME/email-templates.
Templates must live in the correct directory for security reasons. If you want to keep them in a SCM I suggest you create a Jenkins job that checks out that SCM to the correct directory. Technically though that directory shouldn't be writable but probably is. Alternatively you can use the groovy code in the pipeline itself
On Jenkins 2.190, using a local workspace file as a jelly template, works well. It is pulled with SCM step during the build, and the correct html content is received.
This is the Default Content of my email-ext configuration:
${JELLY_SCRIPT,template="${WORKSPACE}/some_dir/email_template.jelly"}
Solve it by manually overriding the file using command line:
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building...'
}
}
}
post {
always {
echo 'Sending email...'
bat "copy /Y ${WORKSPACE}\\Src\\Scripts\\Jenkins\\groovy-html2.template \"${JENKINS_HOME}\\email-templates\\groovy-html2.template\""
emailext body: '''${SCRIPT, template="${WORKSPACE}\\Src\\Scripts\\Jenkins\\groovy-html2.template"}''',
mimeType: 'text/html',
subject: "[Leeroy Jenkins] ${currentBuild.fullDisplayName}",
to: "user#company.com",
replyTo: "user#company.com",
recipientProviders: [[$class: 'CulpritsRecipientProvider']]
}
}
}
A bit crude, but it works.
Related
I am running a Jenkins pipline which is calling a script
In following example, running a script which is generating output file with issue_{datetime}.txt
I want to send this file as attachment. However, as file name is generated every time with separate date time stamps not able to find a way to attach file.
e.g.
pipeline {
agent any
stages{
stage('Start Build'){
steps{
python run.py
}
}
}
post {
always {
echo ("${email_id}")
emailext from: 'xyz#yahoo.com', attachmentsPattern: 'resources/*.xlsx',
to: "${email_id}",
}
}
}
You can do it like this try this,
emailext attachmentsPattern: '**/resources/*.xlsx', body: 'Find attachments', subject: 'Attachment', to: 'test#ab.org'
OUTPUT_FILE = sh(script: 'ls -t resources/issue*.xlsx | head -1', returnStdout: true)
emailext from: 'test#yahoo.com', attachmentsPattern:"${OUTPUT_FILE}"
The Allure report is not attaching to the Jenkins email. I am using the Jenkins pipeline script and this is my script however this is the error i get in my email:
Groovy Template file [allure-report.groovy] was not found in $JENKINS_HOME/email-templates.
Also I am not able to find allure-report.groovy in my computer
Here is my Jenkins pipeline, I am not sure how to include the template:
pipeline {
agent {
label {
label ""
customWorkspace "/john/qa-end-to-end"
}
}
tools {nodejs "node"}
stages {
stage('Checkout App') {
steps {
dir("${env.HOME}/app") {
echo "Building.."
sh 'git reset --hard HEAD'
sh 'git clean -f -d'
sh 'git pull'
}
}
}
stage('Starting Tests') {
steps {
echo "Starting End to End Tests"
dir("${env.HOME}/qa-end-to-end/") {
sh './tests.sh'
}
}
}
}
post('Publish Report') {
always {
script {
allure([
includeProperties: false,
jdk: '',
properties: [],
reportBuildPolicy: 'ALWAYS',
results: [[path: '$WORKSPACE/${env.HOME}/app/target/allure-results']]
])
}
}
failure {
emailext(
attachmentsPattern: "$WORKSPACE/${env.HOME}/qa-end-to-end/allure-report/index.html",
body: '''${SCRIPT, template="allure-report.groovy"}''',
subject: "Failure in End to End Tests -> Build Number: ${env.BUILD_NUMBER}",
from: "john#gmail.com",
to: "mike#gmail.com"
)
}
}
}
$JENKINS_HOME/email-templates is used to place email body template, generally when you install Jenkins plugin like email, it which includes some pre-defined templates and those templates will be extracted into $JENKINS_HOME/email-templates after plugin installed.
And when you use send email in job's Post Action, you can choose to use one of template of plugin and Jenkins will try to get the template from folder $JENKINS_HOME/email-templates
If you want to use self template, you need to put it into $JENKINS_HOME/email-templates too.
Using custom scripts (those not packaged with email-ext) requires the cooperation of your Jenkins administrator. The steps are relatively simple:
Create the script/template. The name of the script end in the standard extension for the language (.groovy). The template can be named anything
Have your Jenkins administrator place the script inside $JENKINS_HOME\email-templates.
Use the script token with the template parameter equal to your template filename, or in addition the script parameter equal to the custom script name. For example, if the template filename is foobar.template, the email content would look like this ${SCRIPT, template="foobar.template"}.
More detail
I have a Master (Unix) and a slave Machine (Windows).
I have created a Multibranch pipeline Project on Master and Trigger request all of the Process takes place in Slave. I am trying to send the HTML reports which are being generated at the Slave machine but get Exception:
ERROR: Error: No workspace found!
Sending email to: abhishek.gaur1#pb.com
[Pipeline] }
[Pipeline] // stage
[Pipeline] End of Pipeline
Finished: SUCCESS
I am using the below code in Jenkinsfile:
success {
emailext attachmentsPattern: '**/overview-features.html',
body: '${SCRIPT, template="groovy-html.template"}',
mimeType: 'text/html',
subject: 'Success Pipeline: ${currentBuild.fullDisplayName}',
to: 'abhishek.gaur1#pb.com'
}
The file should be attached to the email and sent. Currently it shows ERROR:
Error: No workspace found!
From my tests it seems the agent none case has a problem in configurations where the workspace is not allocated on the master.
agent none allows to set agents per stage, but the post() block doesn't allow to set an agent, it will run on master without workspace on the case of agent none from what i gathered.
So the only solution for declarative pipeline in that case would be to run the whole build on agent with label Developer30, if your example is complete it should be no problem.
pipeline {
agent {
label 'Developer30'
}
tools {
maven 'MAVEN_HOME'
}
stages {
stage ('Compile Stage') {
steps {
bat 'mvn clean'
}
}
}
post {
success {
// emailext stuff
}
}
}
We have a project on GitHub which has two Jenkins Multibranch Pipeline jobs - one builds the project and the other runs tests. The only difference between these two pipelines is that they have different JenkinsFiles.
I have two problems that I suspect are related to one another:
In the GitHub status check section I only see one check with the following title:
continuous-integration/jenkins/pr-merge — This commit looks good,
which directs me to the test Jenkins pipeline. This means that our build pipeline is not being picked up by GitHub even though it is visible on Jenkins. I suspect this is because both the checks have the same name (i.e. continuous-integration/jenkins/pr-merge).
I have not been able to figure out how to rename the status check message for each Jenkins job (i.e. test and build). I've been through this similar question, but its solution wasn't applicable to us as Build Triggers aren't available in Multibranch Pipelines
If anyone knows how to change this message on a per-job basis for Jenkins Multibranch Pipelines that'd be super helpful. Thanks!
Edit (just some more info):
We've setup GitHub/Jenkins webhooks on the repository and builds do get started for both our build and test jobs, it's just that the status check/message doesn't get displayed on GitHub for both (only for test it seems).
Here is our JenkinsFile for for the build job:
#!/usr/bin/env groovy
properties([[$class: 'BuildConfigProjectProperty', name: '', namespace: '', resourceVersion: '', uid: ''], buildDiscarder(logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '', numToKeepStr: '5')), [$class: 'ScannerJobProperty', doNotScan: false]])
node {
stage('Initialize') {
echo 'Initializing...'
def node = tool name: 'node-lts', type: 'jenkins.plugins.nodejs.tools.NodeJSInstallation'
env.PATH = "${node}/bin:${env.PATH}"
}
stage('Checkout') {
echo 'Getting out source code...'
checkout scm
}
stage('Install Dependencies') {
echo 'Retrieving tooling versions...'
sh 'node --version'
sh 'npm --version'
sh 'yarn --version'
echo 'Installing node dependencies...'
sh 'yarn install'
}
stage('Build') {
echo 'Running build...'
sh 'npm run build'
}
stage('Build Image and Deploy') {
echo 'Building and deploying image across pods...'
echo "This is the build number: ${env.BUILD_NUMBER}"
// sh './build-openshift.sh'
}
stage('Upload to s3') {
if(env.BRANCH_NAME == "master"){
withAWS(region:'eu-west-1',credentials:'****') {
def identity=awsIdentity();
s3Upload(bucket:"****", workingDir:'build', includePathPattern:'**/*');
cfInvalidate(distribution:'EBAX8TMG6XHCK', paths:['/*']);
}
};
if(env.BRANCH_NAME == "PRODUCTION"){
withAWS(region:'eu-west-1',credentials:'****') {
def identity=awsIdentity();
s3Upload(bucket:"****", workingDir:'build', includePathPattern:'**/*');
cfInvalidate(distribution:'E6JRLLPORMHNH', paths:['/*']);
}
};
}
}
Try to use GitHubCommitStatusSetter (see this answer for declarative pipeline syntax). You're using a scripted pipeline syntax, so in your case it will be something like this (note: this is just prototype, and it definitely must be changed to match your project specific):
#!/usr/bin/env groovy
properties([[$class: 'BuildConfigProjectProperty', name: '', namespace: '', resourceVersion: '', uid: ''], buildDiscarder(logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '', numToKeepStr: '5')), [$class: 'ScannerJobProperty', doNotScan: false]])
node {
// ...
stage('Upload to s3') {
try {
setBuildStatus(context, "In progress...", "PENDING");
if(env.BRANCH_NAME == "master"){
withAWS(region:'eu-west-1',credentials:'****') {
def identity=awsIdentity();
s3Upload(bucket:"****", workingDir:'build', includePathPattern:'**/*');
cfInvalidate(distribution:'EBAX8TMG6XHCK', paths:['/*']);
}
};
// ...
} catch (Exception e) {
setBuildStatus(context, "Failure", "FAILURE");
}
setBuildStatus(context, "Success", "SUCCESS");
}
}
void setBuildStatus(context, message, state) {
step([
$class: "GitHubCommitStatusSetter",
contextSource: [$class: "ManuallyEnteredCommitContextSource", context: context],
reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://github.com/my-org/my-repo"],
errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
]);
}
Please check this and this links for more details.
You can use the Github Custom Notification Context SCM Behaviour plugin https://plugins.jenkins.io/github-scm-trait-notification-context/
After installing go to the job configuration. Under "Branch sources" -> "GitHub" -> "Behaviors" click "Add" and select "Custom Github Notification Context" from the dropdown menu. Then you can type your custom context name into the "Label" field.
This answer is pretty much like #biruk1230's answer. But if you don't want to downgrade your github plugin to work around the bug, then you could call the API directly.
void setBuildStatus(String message, String state)
{
env.COMMIT_JOB_NAME = "continuous-integration/jenkins/pr-merge/sanity-test"
withCredentials([string(credentialsId: 'github-token', variable: 'TOKEN')])
{
// 'set -x' for debugging. Don't worry the access token won't be actually logged
// Also, the sh command actually executed is not properly logged, it will be further escaped when written to the log
sh """
set -x
curl \"https://api.github.com/repos/thanhlelgg/brain-and-brawn/statuses/$GIT_COMMIT?access_token=$TOKEN\" \
-H \"Content-Type: application/json\" \
-X POST \
-d \"{\\\"description\\\": \\\"$message\\\", \\\"state\\\": \\\"$state\\\", \
\\\"context\\\": \\\"${env.COMMIT_JOB_NAME}\\\", \\\"target_url\\\": \\\"$BUILD_URL\\\"}\"
"""
}
}
The problem with both methods is that continuous-integration/jenkins/pr-merge will be displayed no matter what.
This will be helpful with #biruk1230's answer.
You can remove Jenkins' status check which named continuous-integration/jenkins/something and add custom status check with GitHubCommitStatusSetter. It could be similar effects with renaming context of status check.
Install Disable GitHub Multibranch Status plugin on Jenkins.
This can be applied by setting behavior option of Multibranch Pipeline Job on Jenkins.
Thanks for your question and other answers!
I have two Jenkins pipelines, let's say pipeline-A and pipeline-B. I want to invoke pipeline-A in pipeline-B. How can I do this?
(pipeline-A is a subset of pipeline-B. Pipeline-A is responsible for doing some routine stuff which can be reused in pipeline-B)
I have installed Jenkins 2.41 on my machine.
Following solution works for me:
pipeline {
agent
{
node {
label 'master'
customWorkspace "${env.JobPath}"
}
}
stages
{
stage('Start') {
steps {
sh 'ls'
}
}
stage ('Invoke_pipeline') {
steps {
build job: 'pipeline1', parameters: [
string(name: 'param1', value: "value1")
]
}
}
stage('End') {
steps {
sh 'ls'
}
}
}
}
Adding link of the official documentation of "Pipeline: Build Step" here:
https://jenkins.io/doc/pipeline/steps/pipeline-build-step/
A little unclear if you want to invoke another pipeline script or job, so I answer both:
Pipeline script
The "load" step will execute the other pipeline script. If you have both scripts in the same directory, you can load it like this:
def pipelineA = load "pipeline_A.groovy"
pipelineA.someMethod()
Other script (pipeline_a.groovy):
def someMethod() {
//do something
}
return this
Pipeline job
If you are talking about executing another pipeline job,
the "build job" step can accomplish this:
build job: '<Project name>', propagate: true, wait: true
propagate: Propagate errors
wait: Wait for completion
If you have paramters on the job, you can add them like this:
build job: '<Project name>', parameters: [[$class: 'StringParameterValue', name: 'param1', value: 'test_param']]
As mentioned by #Matias Snellingen and #Céline Aussourd, in the case of launching a multibranch job you have to specify the branch to build like this :
stage ('Invoke_pipeline') {
steps {
build job: 'pipeline1/master', parameters: [
string(name: 'param1', value: "value1")
]
}
}
In my case it solved the problem.
I am going to post my solution, which is similar to #Michael COLL, #Matias Snellingen, and #Céline Aussourd.
For the multibranch pipeline I am using the following code in Jenkinsfile to trigger my multibranch B with multibranch A (in the example there are two cases for pipeline and multibranch pipeline):
post {
always {
echo 'We are in post part and Jenkins build with QA tests is going to be triggered.'
// For triggering Pipeline
//build job: 'WGF-QA WITH ALLURE', parameters: [string(name: 'QA-Automation', value: 'value from Build pipeline')]
// For triggering Multibranch Pipeline
build job: 'Testing QA/QA Selenium Tests/feature%2FGET-585', parameters: [string(name: 'QA-Automation', value: 'value from Build pipeline')]
}
}
Just be sure to define the whole path to the branch as is defined in the case and instead of / in branch name use %2F (feature/GET-585 -> feature%2FGET-585).
To add to what #matias-snellingen said. If you have multiple functions, the return this should be under the function that will be called in the main pipeline script. For example in :
def someMethod() {
helperMethod1()
helperMethod2()
}
return this
def helperMethod1(){
//do stuff
}
def helperMethod2(){
//do stuff
}
The someMethod() is the one that will be called in the main pipeline script
Another option is to create a package, load it and execute it from the package.
package name.of.package
import groovy.json.*
def myFunc(var1) {
return result
}
Than consume it
#Library('name_of_repo')
import name.of.package.*
utils = new name_of_pipeline()
// here you can invoke
utils.myFunc(var)
hope it helps