Skip to content

Commit 5ae032b

Browse files
committed
Merge pull request #485 from CodeNow/notifications-cleanups
Notifications cleanups
2 parents 416581c + c5d7207 commit 5ae032b

File tree

15 files changed

+194
-93
lines changed

15 files changed

+194
-93
lines changed

configs/.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ CAYLEY="http://localhost:64210"
3434
REDIS_NAMESPACE="runnable:api:"
3535
DNS_JOB_QUEUE_INTERVAL=200
3636
DNS_JOB_QUEUE_INTERVAL_DELETE=60000
37-
SLACK_BOT_IMAGE="https://avatars0.githubusercontent.com/u/2828361?v=3&s=200"
37+
SLACK_BOT_IMAGE="https://avatars0.githubusercontent.com/u/2335750?v=3&s=200"
3838
SLACK_BOT_USERNAME="runnabot"
3939
HIPCHAT_BOT_USERNAME="runnabot"
4040
ENABLE_BUILDS_ON_GIT_PUSH=false

lib/middlewares/notifications/index.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ var fs = require('fs');
55
var inflect = require('i')();
66
var createClassMiddleware = require('../create-class-middleware');
77

8-
var apiMiddlewares = module.exports = {};
8+
var notificationsMiddlewares = module.exports = {};
99

1010
// this file automatically generates middlewares from the models/notifications folder
1111
// if they donot exist in the middlewares/notifications folder
@@ -19,7 +19,7 @@ fs.readdirSync(notificationsMiddlewaresDir).forEach(function (filename) {
1919
var lower = filename.replace(/\.js$/, '').toLowerCase();
2020
var middleware = require(path.join(notificationsMiddlewaresDir, filename));
2121
var camel = inflect.camelize(inflect.underscore(lower), false);
22-
apiMiddlewares[camel] = middleware;
22+
notificationsMiddlewares[camel] = middleware;
2323
});
2424

2525

@@ -29,9 +29,9 @@ var modelsIncludes = ['index.js'];
2929
fs.readdirSync(notificationsModelsDir).forEach(function (filename) {
3030
if (!~modelsIncludes.indexOf(filename)) { return; }
3131
var lower = filename.replace(/\.js$/, '').toLowerCase();
32-
if (apiMiddlewares[lower]) { return; }
32+
if (notificationsMiddlewares[lower]) { return; }
3333

3434
var Model = require(path.join(notificationsModelsDir, filename));
3535
var camel = inflect.camelize(inflect.underscore(lower), false);
36-
apiMiddlewares[camel] = createClassMiddleware(camel, Model);
36+
notificationsMiddlewares[camel] = createClassMiddleware(camel, Model);
3737
});

lib/models/notifications/hipchat.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,29 @@ var util = require('util');
33
var HipChatClient = require('hipchat-client');
44
var Notifier = require('./notifier');
55

6-
76
// settings should have `api_token` and `room_id` properties.
8-
// NOTE: should we do validation here?
97
function HipChat (settings) {
108
Notifier.call(this, 'hipchat', settings);
119
this.hipchatClient = new HipChatClient(settings.authToken);
1210
}
1311

1412
util.inherits(HipChat, Notifier);
1513

16-
HipChat.prototype.send = function (text, cb) {
14+
HipChat.prototype.send = function (message, cb) {
1715
this.hipchatClient.api.rooms.message({
1816
room_id: this.settings.roomId,
1917
from: process.env.HIPCHAT_BOT_USERNAME,
2018
message_format: 'html',
21-
message: text,
19+
message: message,
2220
color: 'purple'
2321
}, cb);
2422
};
2523

24+
HipChat.prototype.makeOnInstancesMessage = function(githubPushInfo, instances) {
25+
githubPushInfo.instances = instances;
26+
githubPushInfo.domain = process.env.DOMAIN;
27+
return this.onInstancesTpl(githubPushInfo);
28+
};
29+
30+
2631
module.exports = HipChat;

lib/models/notifications/notifier.js

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,21 @@ Handlebars.registerHelper('moreChangesSlack', function(repo, commitLog) {
2424

2525

2626
Handlebars.registerHelper('encode', function (str) {
27-
return encodeURIComponent(str);
27+
return encodeURIComponent(str);
2828
});
2929

30+
/**
31+
* Slack requires light escaping with just 3 rules:
32+
* & replaced with &
33+
* < replaced with &lt;
34+
* > replaced with &gt;
35+
*/
36+
var ampRegExp = new RegExp('&', 'g');
37+
var ltRegExp = new RegExp('<', 'g');
38+
var gtRegExp = new RegExp('>', 'g');
39+
Handlebars.registerHelper('slackEscape', function (str) {
40+
return str.replace(ampRegExp, '&amp;').replace(ltRegExp, '&lt;').replace(gtRegExp, '&gt;');
41+
});
3042

3143
var onBuildTpls = {};
3244
var onInstanceTpls = {};
@@ -55,27 +67,34 @@ function createTpl (tplPath) {
5567

5668

5769
// should be implemented in the subclass
58-
Notifier.prototype.send = function (/* text, cb */) {
70+
Notifier.prototype.send = function (/* message, cb */) {
71+
throw new Error('Not implemented');
72+
};
73+
74+
Notifier.prototype.makeOnBuildMessage = function(githubPushInfo) {
75+
githubPushInfo.domain = process.env.DOMAIN;
76+
return this.onBuildTpl(githubPushInfo);
77+
};
78+
79+
// should be implemented in the subclass
80+
Notifier.prototype.makeOnInstancesMessage = function(/* githubPushInfo, instances */) {
5981
throw new Error('Not implemented');
6082
};
6183

6284
// Notify when image was build and ready to be run
6385
Notifier.prototype.notifyOnBuild = function (githubPushInfo, cb) {
6486
debug('fill context version for', githubPushInfo);
65-
githubPushInfo.domain = process.env.DOMAIN;
66-
var text = this.onBuildTpl(githubPushInfo);
67-
this.send(text, cb);
87+
var message = this.makeOnBuildMessage(githubPushInfo);
88+
this.send(message, cb);
6889
};
6990

7091
// Notify when image was build and deployed to instance
7192
Notifier.prototype.notifyOnInstances = function (githubPushInfo, instances, cb) {
7293
debug('fill context version for', githubPushInfo);
7394
if (instances && instances.length > 0) {
7495
debug('notify on instances', instances);
75-
githubPushInfo.instances = instances;
76-
githubPushInfo.domain = process.env.DOMAIN;
77-
var text = this.onInstancesTpl(githubPushInfo);
78-
this.send(text, cb);
96+
var message = this.makeOnInstancesMessage(githubPushInfo, instances);
97+
this.send(message, cb);
7998
}
8099
else {
81100
// do nothing

lib/models/notifications/slack.js

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,52 @@ var Notifier = require('./notifier');
55

66

77
// settings should have `webhookUrl` property.
8-
// NOTE: should we do validation here?
98
function Slack (settings) {
109
Notifier.call(this, 'slack', settings);
1110
this.slackClient = slack(settings.webhookUrl);
11+
this.runnableNotify = this.slackClient.extend({
12+
username: process.env.SLACK_BOT_USERNAME,
13+
icon_url: process.env.SLACK_BOT_IMAGE
14+
});
1215
}
1316

1417
util.inherits(Slack, Notifier);
1518

16-
Slack.prototype.send = function (text, cb) {
19+
20+
Slack.prototype.send = function (message, cb) {
21+
this.runnableNotify(message, cb);
22+
};
23+
24+
Slack.prototype.makeOnInstancesMessage = function(githubPushInfo, instances) {
25+
githubPushInfo.instances = instances;
26+
githubPushInfo.domain = process.env.DOMAIN;
27+
var text = this.onInstancesTpl(githubPushInfo);
28+
var instancesLinks = instances.map(instanceToLink);
29+
var fields = instancesLinks.map(istanceToAttachment);
1730
var opts = {
1831
text: text,
19-
username: process.env.SLACK_BOT_USERNAME,
20-
icon_url: process.env.SLACK_BOT_IMAGE
32+
attachments: [
33+
{
34+
fallback: instancesLinks.join('\n'),
35+
color: '#5b3777',
36+
fields: fields
37+
}
38+
]
2139
};
22-
this.slackClient.send(opts, cb);
40+
return opts;
2341
};
2442

43+
44+
45+
function istanceToAttachment (link) {
46+
return {
47+
value: link
48+
};
49+
}
50+
51+
function instanceToLink(instance) {
52+
return '<http://' + process.env.DOMAIN + '/' + instance.owner.username +
53+
'/' + instance.name + '|' + instance.name + '>';
54+
}
55+
2556
module.exports = Slack;

lib/routes/actions/github.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ var pushSessionUser = {
3333
permissionLevel: 5,
3434
accounts: {
3535
github: {
36-
id: 'githubPushInfo.user.id',
37-
token: 'runnableToken'
36+
id: 'githubPushInfo.user.id'
3837
}
3938
}
4039
};

lib/routes/instances/containers/index.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,3 @@ app.get('/instances/:id/containers',
3333
findInstance,
3434
mw.res.json('instance.containers'));
3535

36-
/**
37-
* Polling route used by frontend to determine if a new build was pushed
38-
* @event GET rest/instances/:id/containers
39-
* @memberof module:rest/instances/:id/containers */
40-
app.get('/instances/:id/build',
41-
findInstance,
42-
mw.res.json('instance.build')); // buildId as string

lib/routes/instances/index.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ app.get('/instances/',
242242
mw.query({or: [
243243
'owner', 'shortHash', 'name', '["contextVersion.appCodeVersions.repo"]'
244244
]}).require(),
245-
// Note: be careful pick does not work like the others,
245+
// Note: be careful pick does not work like the others,
246246
// pick only works with keys and not keypaths!
247247
mw.query('owner', 'shortHash', 'name' ,
248248
'owner.github', 'contextVersion.appCodeVersions.repo').pick(),
@@ -347,6 +347,18 @@ app.get('/instances/:id',
347347
instances.model.populateModels(),
348348
mw.res.json('instance'));
349349

350+
351+
/**
352+
* Polling route used by frontend to determine if a new build was pushed
353+
* @event GET rest/instances/:id/containers
354+
* @memberof module:rest/instances/:id/containers */
355+
app.get('/instances/:id/build',
356+
findInstance,
357+
flow.or(
358+
me.isOwnerOf('instance'),
359+
me.isModerator),
360+
mw.res.json('instance.build')); // buildId as string
361+
350362
/**
351363
* acquire host locks for oldName and newName
352364
*/

templates/hipchat_on_build.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
{{user.login}}'s <a href="{{headCommit.url}}">changes</a> ({{headCommit.message}}{{{moreChangesHipchat repo commitLog}}}) to {{repo}} ({{branch}}) are ready.
2-
<a href="http://{{domain}}/{{owner.login}}/boxSelection/{{repoName}}/{{branch}}/{{encode headCommit.message}}/{{headCommit.id}}">Choose a server to run {{branch}}</a>.
2+
<a href="http://{{domain}}/{{owner.login}}/boxSelection/{{repoName}}/{{encode branch}}/{{encode headCommit.message}}/{{headCommit.id}}">Choose a server to run {{branch}}</a>.

templates/hipchat_on_instances.hbs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{{user.login}}'s <a href="{{headCommit.url}}">changes</a> ({{headCommit.message}}{{{moreChangesHipchat repo commitLog}}}) to {{repo}} ({{branch}}) are deployed on servers:
1+
{{user.login}}'s <a href="{{headCommit.url}}">changes</a> ({{headCommit.message}}{{{moreChangesHipchat repo commitLog}}}) to {{repo}} ({{branch}}) are deployed on servers:<br/>
22
{{#each instances}}
3-
<a href="http://{{../domain}}/{{this.owner.username}}/{{this.name}}">{{this.name}}</a></br>
4-
{{/each}}.
3+
<a href="http://{{../domain}}/{{this.owner.username}}/{{this.name}}">{{this.name}}</a><br/>
4+
{{/each}}

0 commit comments

Comments
 (0)