This set of scripts was developped to provide an easy way to post process build results for Jenkins or other continuous integration system.
It relies on the excellent node-email-templates to render HTML formatted emails, and nodemailer for sending.
Templates are fetched from git/gist repository, and are executed in the context of the build data passed to downstream Job.
Note email-templates is require
d but not installed by this package.
If you wish to get full featureset from email-templates, you need the
package locally by running npm install email-templates
. The system
will fallback to this implementation. May help on
systems where installing juice is
a problem.
Module:
var Mailer = require('gistmailer');
var mailer = new Mailer();
mailer
.service('Gmail')
.auth({ name: '[email protected]', pass: 'password' })
.url('https://gist.github.com/mklabs/eb28e58ac28a8d3ab845')
.to('[email protected]')
.file('./build.json')
.run(function(err) {
if (!err) return;
console.error('Error running mailer', err);
process.exit(1);
});
Command:
Usage: gistmailer [options] <file>
Options:
-h, --help output usage information
-V, --version output the version number
-u, --user [user] SMTP auth user configuration
-p, --pass [pass] SMTP auth password configuration
-s, --service [type] One of the nodemailer service
-H, --host [host] SMTP hostname (not needed with service)
-P, --port [port] SMTP port (not needed with service)
-u, --url [url] Full GIT clone url, or a gist ID
-t, --to [to] Destination email
Scripts
# Iterates over JOB_MAILS
$ npm run gistmailer send
# Send email based on environment variables
$ [email protected] npm run gistmailer asserts
Use env vars, useful for CI based run. They'll overwrite any CLI arguments / flags.
UPSTREAM_DATA
- Absolute path to build dataMAIL_USER
- The email auth credential for usernameMAIL_PASSWORD
- The email auth credential for passwordMAIL_SERVICE
- One of the well known smtp services for nodemailerMAIL_HOST
- SMTP hostname server (not needed withservice
)MAIL_PORT
- SMTP port (defaults to 25, not needed withservice
)
See https://github.com/andris9/Nodemailer#setting-up-smtp
job/jenkins.xml
file is a Jenkins Job template that can be used to quickly
setup a Job to automatically send mail based on upstream data.
# Install plugins. Change name=mailer to change the job name
$ curl -X POST -H 'Content-Type: application/xml' $JEKINS_URL/createItem?name=mailer --data-binary @scripts/jenkins.xml
It has the following job parameters (then available as environment variable to shell scripts):
JOB_MAILS
- List of destination emails for any failed asserts, space separated.MAIL_SERVICE
- https://github.com/andris9/Nodemailer#well-known-services-for-smtpMAIL_USER
- SMTP auth userMAIL_PASSWORD
- SMTP auth passwordMAIL_SUBJECT
- Email subjectUPSTREAM_DATA
- Just for test the default value. Passed from upstream. Absolute path to the build data (includingasserts
)TEMPLATE_URL
- Full Git clone URL, or a gist id (Default: eb28e58ac28a8d3ab845)DEBUG
- Debug lvl option
The build.json
file used is following the above structure. The
relevant build properties used here is asserts
.
[{
url: "Relevant URL (can be the Job URL)"
asserts: {
rules: {
assertKey: value
},
failedCount: 0,
failedAsserts: []
}
}, {
url: "Relevant URL (can be the Job URL)"
asserts: {
rules: {
assertKey: value,
anotherOne: value
},
failedCount: 0,
failedAsserts: []
}
}]
Git#init.
this.git = new Git();
Git#directory.
this.git = new Git();
assert.equal(this.git.directory(), path.join('./tmp/templates/default'));
assert.equal(this.git.directory('foo'), path.join('./tmp/templates/foo'));
assert.equal(this.git.directory(url), path.join('./tmp/templates/eb28e58ac28a8d3ab845'));
Clones url.
this.git = this.git || new Git();
this.git.clone(url, done);
and init template.
fs.stat(this.git.directory(url), done);
Mailer#init.
var mailer = new Mailer();
// Config
mailer
.file(path.join(__dirname, 'fixtures/build.json'))
.url(url)
.to('[email protected]')
.service('Gmail')
.auth({ name: 'foo', pass: 'bar' });
assert.deepEqual(mailer.config(), {
service: 'Gmail',
auth: {
name: 'foo',
pass: 'bar'
}
});
props well.
var obj = Object.create({});
props.forEach(prop(obj));
props.forEach(assertProp(obj));
Object.create.
var obj = Object.create({});
prop(obj)('src');
prop(obj)('dest');
prop(obj)('output');
obj
.src('file.json')
.dest('tmp/output.json')
.output('log/stdout.log')
assert.equal(obj.src(), 'file.json');
assert.equal(obj.dest(), 'tmp/output.json');
assert.equal(obj.output(), 'log/stdout.log');
new Stuff().
function Stuff() {}
prop(Stuff.prototype)('src');
prop(Stuff.prototype)('dest');
prop(Stuff.prototype)('output');
var stuff = new Stuff();
stuff
.src('file.json')
.dest('tmp/output.json')
.output('log/stdout.log')
assert.equal(stuff.src(), 'file.json');
assert.equal(stuff.dest(), 'tmp/output.json');
assert.equal(stuff.output(), 'log/stdout.log');
Hash.
var obj = {};
prop(obj)('src');
prop(obj)('dest');
prop(obj)('output');
obj
.src('file.json')
.dest('tmp/output.json')
.output('log/stdout.log')
assert.equal(obj.src(), 'file.json');
assert.equal(obj.dest(), 'tmp/output.json');
assert.equal(obj.output(), 'log/stdout.log');
_prop - default.
var obj = {};
prop(obj)('file');
obj.file('file.json');
assert.equal(obj.file(), 'file.json');
assert.equal(obj._file, 'file.json');
attr - use this.attributes hash.
var obj = {};
prop(obj, { strategy: 'attr' })('file');
obj.file('file.json');
assert.equal(obj.file(), 'file.json');
assert.equal(obj.attributes.file, 'file.json');
obj = {};
prop(obj, { strategy: prop.attr })('file');
obj.file('file.json');
assert.equal(obj.file(), 'file.json');
assert.equal(obj.attributes.file, 'file.json');
custom.
// Using this.options object
function opts(name, value) {
this.options = this.options || {};
if (!value) return this.options[name];
this.options[name] = value;
return this;
}
var obj = {};
prop(obj, { strategy: opts })('file');
obj.file('file.json');
assert.equal(obj.file(), 'file.json');
assert.equal(obj.options.file, 'file.json');
Validate inputs.
var obj = {};
prop(obj, {
validate: function (name, value) {
if (!value) return;
if (!value.name) return;
if (!value.pass) return;
return true;
}
})('auth');
obj.auth({ foo: 'bar' });
assert.ok(typeof obj.auth() === 'undefined');
obj.auth({
name: 'foo',
pass: 'bar'
});
assert.deepEqual(obj.auth(), { name: 'foo', pass: 'bar' });
- [] rename into notif-mailer, build notif module
...