Jenkins: how to set body content from a variable - string

I have a scripted pipeline. In one of my steps I want to send different mails based on test results. Here is how I do it now:
if (buildResult == 'SUCESSS'
def email_body="TEST_SUCESS.template"
else
def email_body="TEST_FAILURES.template"
emailext(
subject: "Job '${env.JOB_NAME} [${env.BUILD_NUMBER}] finished",
body: "${SCRIPT,template=$email_body}", // LINE A
recipientProviders: [[$class: 'DevelopersRecipientProvider']],
to: 'XXXX',
from: 'YYYY',
replyTo: 'ZZZZ',
mimeType: 'text/html',
)
I can't have Jenkins expand the value of the variable email_body. I've tried various approaches in the line A:
"${SCRIPT,template=$email_body}"
"${SCRIPT,template=${email_body}}"
'''${SCRIPT,template=$email_body}'''
'''${SCRIPT,template=${email_body}}'''
None of them works. All I get in the email is either:
Groovy Template file [$email_body] was not found in $JENKINS_HOME/email-templates.
or
${SCRIPT,template=$email_body}.
What is the correct way of setting email content if the email content is stored in a variable?

Try to use this example:
String subject = "${env.JOB_NAME} was " + currentBuild.result.toString();
String email_body="TEST_" + currentBuild.result.toString() + ".template"
String body = "SCRIPT,template=" + email_body;
String to="some_mail#mail.com"
String reply="ZZZ"
emailext(subject: subject, body: body, to: to, replyTo: reply);

Related

Missing part of content when automatic (crone) sending email by nodemailer

I have a strange problem. I made a small application in node.js, using nodemailer to send emails each day.
And it's working perfectly when I run it from the terminal (for testing).
But when I add a job to crontab, then emails are sent but there is missing some of the content inside.
This is my transporter conf:
// send mail with defined transport object
let info = await transporter.sendMail({
priority: 'high',
from: '"Example" <example#gmail.com>', // sender address
to: 'recip#gmail.com', // list of receivers
subject: 'Example title: '+currentDate, // Subject line
text: '', // plain text body
html: header + missing + carrierStatArr + ending,// html body
attachments: attachments
});
And code for variables to html field:
let carrierStatArr = [], attachments = [];
let header = `<h1>some text ${currentDate}</h1><div><i>some text</br>some text</i></div>`;
let missing = `<h3 style="color:red;">some text: <b>${missingArr}</b></h3>`;
for (let i in checkResultArr) {
let imgName = checkResultArr[i].file;
let correctedImgName = imgName.substring(0,16);
carrierStatArr.push(`<p>Some text <b>${checkResultArr[i].name}</b>,</br>
<span>Some text: <b>${checkResultArr[i].status}</b></span></br>
<span><img src="cid:${correctedImgName}" width="1000px"/></span>
</p>`);
}
//console.log(carrierStatArr);
attachments = checkResultArr.map((file)=>{
let pat = '/var/www/html/public_html/MM1_service/images/';
let fi = file.file;
let fit = fi.substring(0,16);
return {path: pat+file.file, cid: fit};
});
//console.log(attachments[0].path);
let ending = `<hr size="1" width="100%" color="gray"><p><i>some text</i></p>`;
Of course, there are all data in arrays. And as I wrote, when I run this code manually using terminal /node sendmail.js/ it works perfectly, email contains all the information's, text, and images.
But when the script is run automatically by the cron job, the email has only header, missing, and ending variables (and the content from arrays is there) but the rest: carrierStatArr, attachments are missing.
Why is that? Manually work, run by cron not exacly.
Note: I managed to solve my problem by using the 'node-cron' module instead of the system cron. The app is working correctly.
But still I'm curious, from an academic point, why that problem occurred.

Populate choice parameter in jenkinsfile with list of folders in SCM repository

I've got a Jenkinsfile that drives a pipeline which the user must select a specific folder in a bitbucket repo to target. I want that choice parameter dropdown to be dynamically populated.
Currently, I've got the choice param list hardcoded as per this generic example:
choice(name: 'IMAGE', choices: ['workload-x','workload-y','workload-z'])
I wondered if this is possible from within the jenkinsfile itself, or whether I'd have to create a specific groovy script for this then call it. Either way I'm a bit lost as I'm pretty new to jenkins and have only just started working with Jenkinsfiles.
Some trial and error googling has allowed me to create a groovy script which returns an array of folder names in the repository using json slurper:
import groovy.json.JsonSlurper
import jenkins.model.Jenkins
def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.Credentials.class,
Jenkins.instance,
null,
null
);
def credential = creds.find {it.id == "MYBITBUCKETCRED"}
if (!credential) { return "Unable to pickup credential from Jenkins" }
username = credential.username
pass = credential.password.toString()
def urlStr = "https://bitbucket.mydomain.com/rest/api/1.0/projects/MYPROJECT/repos/MYREPO/browse/"
HttpURLConnection conn = (HttpURLConnection) new URL(urlStr).openConnection()
String encoded = Base64.getEncoder().encodeToString((username + ":" + pass).getBytes("UTF-8"));
conn.setRequestProperty("Authorization", "Basic " + encoded);
conn.connect();
def slurper = new JsonSlurper()
def browseList = slurper.parseText(conn.getInputStream().getText())
def dfList = browseList.children.values.path.name.findAll {it.contains('workload-')}
return dfList
This returns a result as follows:
Result: [workload-a,workload-b,workload-c,workload-x,workload-y,workload-z]
However I'm unsure how then to call this in my Jenkinsfile in order to populate the dropdown.
Any help would be greatly appreciated.
you can do it this way (follow my example below) or make use of Active Choice Jenkins Plugins - because It allows some groovy scripting to prepare your choice
Note- The Choice parameter will be available after a first run.
def choiceArray = []
node {
checkout scm
def folders = sh(returnStdout: true, script: "ls $WORKSPACE")
folders.split().each {
//condition to skip files if any
choiceArray << it
}
}
pipeline {
agent any;
parameters { choice(name: 'CHOICES', choices: choiceArray, description: 'Please Select One') }
stages {
stage('debug') {
steps {
echo "Selected choice is : ${params.CHOICES}"
}
}
}
}
I used the previous example to load the list in the same build
I send the command output to a file, to be consumed in the next step
Here the jenkinsfile:
def choiceArray = []
pipeline {
agent any
parameters {
string defaultValue: '', description: 'PATH_to_scripts', name: 'SCRIPTPATH', trim: false
string defaultValue: '', description: 'Optional parameters', name: 'MOREparams', trim: false
}
stages {
stage('show available date') {
steps {
sh '''
echo $JENKINS_HOME
cd $JENKINS_HOME/scripts
./0_db_show_available.sh $DBlike $AWS_PROFILE $DATEFILTER > $JENKINS_HOME/scripts/lista.txt
echo "Show available date"
cat $JENKINS_HOME/scripts/lista.txt
'''
}
}
stage('Restore') {
steps {
script {
def folders = sh(returnStdout: true, script: "cat $JENKINS_HOME/scripts/lista.txt")
//load the array using the file content (lista.txt)
folders.split().each {
choiceArray << it
}
// wait for user input
def INPUT_DATE = input message: 'Please select date', ok: 'Next',
//generate the list using the array content
parameters: [ choice(name: 'CHOICES', choices: choiceArray, description: 'Please Select One') ]
}
}
}
}
}
samit-kumar-patel, thanks for first example, it helps me

Issue with "from" field using gmail API in Node JS

I have a problem setting the author of a mail in the "from" field of the RFC2822 mail (here the detail).
The problem is that the author does not appear in the received mail. The "from" field I've set looks like this:
MyName: name.surname#gmail.com
But I also tried:
MyName <name.surname#gmail.com>
None of these work, in the received mail the name is still missing looking at the original mail.
This should work because using nodemailer (with Gmail) and the same value for "from" it works. Can someone explain me what's happening? How can I solve?
EDIT: I report the code I am using as asked in one comment.
I separated the call to the API from the part that generates the mail body, so the call is:
function gmailSend(auth, mail){
const gmail = google.gmail({version: 'v1', auth});
const b64mex=mail.b64enc();
return gmail.users.messages.send(
{auth: auth,
userId: 'me',
resource:
{raw: b64mex}
}
);
}
While the parameter "mail" is generated in this way:
function genMail(candidate, clerk_email, supervisor_email){
return new Mail({from: `MyName: name.surname#gmail.com`, to: candidate.email,
subject: "Test Mail", bcc: supervisor_email,
"reply-to": clerk_email}, genMessage(candidate));
}
Mail simply compose an object that has the properties given in its first parameter, while b64enc() puts all in a string respecting the RFC2822 and encodes it base64.
EDIT2: code for Mail class.
class Mail{
constructor(headers, body) {
if(!headers.to)
throw Error("Recipient missing");
if(headers.subject){
const b64subject=new Buffer(headers.subject).toString("base64")
.replace(/\+/g, '-').
replace(/\//g, '_');
headers.subject='=?utf-8?B?'+b64subject+"?=";
}
Object.assign(this, headers);
this.body = body;
}
b64enc(){
const fields = ["Content-Type: text/html; charset=\"UTF-8\"\n",
"MIME-Version: 1.0\n",
"Content-Transfer-Encoding: 7bit\n"];
for(const prop of Object.keys(this)){
if(prop!=="body")
fields.push(`${prop}: ${this[prop]}\n`);
}
fields.push("\n");
fields.push(this.body);
const str=fields.join('');
const encodedMail = new Buffer(str).toString("base64")
.replace(/\+/g, '-').
replace(/\//g, '_');
return encodedMail;
}
}
EDIT3: I add screenshots of desired and actual behaviour:
Desired behaviour, the hidden info are the sender's email and the receiver's one:
Actual behaviour. The difference is that here there is not "MyName".
What is shown in my email client of course is based on the content of "From:" in the plain email. In the first case it is "My name <email address>", in the second it is just "email address".
In order to show a name, and not just the email address, you can format the from field the following way:
from: '"MyName" <name.surname#gmail.com>'

Struggling with post multipart/form-data including file and attributes

I'm using Requests for a program that interfaces with a server that has a well documented API, except for file upload which uses multipart/form-data including file and attributes. Every other request using JSON and that has not been an issue.
The docs say that the header must contain content-type:multipart/form-data but I have realized that requests does that automatically. It then lists a number of text attributes in the form of author.fullName: Heidi Walker and then a file attribute in the form of content: [physical file]
I have a working example in Postman but I can't get it to work with Requests. This is the code I have:
header = {
'session_id':sID,
}
# These are the required text attributes from the API docs + the actual file
fileInfo = {
'author.fullName' : 'Fred',
'category.guid' : 'xxx',
'description' : 'Data Sheet',
'format' : 'PDF',
'private' : 'false',
'storageMethodName' : 'FILE',
'title ' : 'Test Datasheet',
'content': open(path, 'rb')
}
resp = requests.post(url + '/files', headers = header, files = fileInfo)
I keep getting back 400 errors from the server.
Also, is their any way to see the formatted body of the request? So I can check that the boundary tags have been added correctly and compare to what Postman created?
I have been struggling with this for way to long so any help would be greatly appreciated.
Update:
I was able to enable logging with the logging module as outlined on this page: https://requests.readthedocs.io/en/master/api/
Inspecting the body of the request I see:
Content-Disposition: form-data; name="author.fullName"; filename="author.fullName"\r\n\r\nFred\r\n
What I would like to see (working postman example) is:
Content-Disposition: form-data; name=\"author.fullName\"\r\n\r\nFred\r\n
It seems that filename="author.fullName" is being inserted on every line.
Finally got this working, here is the code if anyone else is struggling with this.
multi = MultipartEncoder(
fields={'author.fullName' : 'Automatic Upload',
'category.guid' : 'XXX',
'description' : 'Data Sheet',
'edition' : '01',
'format' : 'PDF',
'private' : 'false',
'storageMethodName' : 'FILE',
'title ' : title,
'content': (fileName, open(path, 'rb'), 'application/pdf')}
)
mpHeader = {
'Content-Type': multi.content_type,
'session_id':sID,
'cache-control': "no-cache",
}
resp = requests.post(url + '/files', headers = mpHeader, data = multi)

node.js nodemailer subject issue

i'm using the nodemailer library to send emails to my users.
The problem is that some special charachter such us "è" or "à" are not visible.
Can i change the encoding of the subject? in the body is already working.
var mailOptionsUtente = {
from: 'my#email.it', // sender address
to: utente.email, // list of receivers
subject: "non è possibile", // Subject line
html: "HTML...."
};
i know you can add encoding option in your object.
See here
https://community.nodemailer.com/
You can add subject encoding options like that :
var subject = 'non è possibile';
var mail = {
...,
subject: {
prepared: true,
value: '=?UTF-8?B?'+new Buffer(subject).toString('base64')+'?='
},
...
};
source : https://github.com/nodemailer/nodemailer/issues/562

Resources