0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2024-12-16 21:56:25 -05:00

feat: added information about package publisher for notifications

This commit is contained in:
Ilya Zaytsev 2018-06-10 10:15:44 +07:00
parent 2208b4ef51
commit 1ca5298707
4 changed files with 96 additions and 23 deletions

View file

@ -38,6 +38,32 @@ notify:
content: '{"color":"green","message":"New package published: * {{ name }}*","notify":true,"message_format":"text"}' content: '{"color":"green","message":"New package published: * {{ name }}*","notify":true,"message_format":"text"}'
``` ```
### Publisher information
You can access to the package publisher information in the `content` of a webhook using the `publisher` object.
See below the `publisher` object type:
```
{
name: string,
groups: string[],
real_groups: string[]
}
```
An example:
```
notify:
method: POST
headers: [{'Content-Type': 'application/json'}]
endpoint: https://usagge.hipchat.com/v2/room/3729485/notification?auth_token=mySecretToken
content: '{"color":"green","message":"New package published: * {{ name }}*. Publisher name: * {{ publisher.name }} *.","notify":true,"message_format":"text"}'
```
**Note:** it's not possible to get the publisher information if the `package.json` file already has the `publisher` property.
## Configuration ## Configuration
Property | Type | Required | Support | Default | Description Property | Type | Required | Support | Default | Description
@ -47,4 +73,4 @@ packagePattern| string | No | all | | Only run this notification if the package
packagePatternFlags| string | No | all | | Any flags to be used with the regular expression packagePatternFlags| string | No | all | | Any flags to be used with the regular expression
headers| array/object | Yes | all | | If this endpoint requires specific headers, set them here as an array of key: value objects. headers| array/object | Yes | all | | If this endpoint requires specific headers, set them here as an array of key: value objects.
endpoint| string | Yes | all | | set the URL endpoint for this call endpoint| string | Yes | all | | set the URL endpoint for this call
content| string | Yes | all | | any [handlebar](https://handlebarsjs.com/) expressions content| string | Yes | all | | any [handlebar](https://handlebarsjs.com/) expressions

View file

@ -91,7 +91,7 @@ export default function(router: Router, auth: IAuth, storage: IStorageHandler, c
if (err) { if (err) {
return next(err); return next(err);
} }
notify(metadata, config); notify(metadata, config, req.remote_user);
res.status(201); res.status(201);
return next({ok: ok_message, success: true}); return next({ok: ok_message, success: true});
}); });

View file

@ -3,7 +3,7 @@ const request = require('request');
const _ = require('lodash'); const _ = require('lodash');
const logger = require('./logger'); const logger = require('./logger');
const handleNotify = function(metadata, notifyEntry) { const handleNotify = function(metadata, notifyEntry, publisherInfo) {
let regex; let regex;
if (metadata.name && notifyEntry.packagePattern) { if (metadata.name && notifyEntry.packagePattern) {
// FUTURE: comment out due https://github.com/verdaccio/verdaccio/pull/108#issuecomment-312421052 // FUTURE: comment out due https://github.com/verdaccio/verdaccio/pull/108#issuecomment-312421052
@ -15,7 +15,12 @@ const handleNotify = function(metadata, notifyEntry) {
} }
const template = Handlebars.compile(notifyEntry.content); const template = Handlebars.compile(notifyEntry.content);
const content = template( metadata );
// don't override 'publisher' if package.json already has that
if (!metadata.publisher) {
metadata = {...metadata, publisher: publisherInfo};
}
const content = template(metadata);
const options = { const options = {
body: content, body: content,
@ -28,7 +33,7 @@ const handleNotify = function(metadata, notifyEntry) {
if (Object.is(item, item)) { if (Object.is(item, item)) {
for (const key in item) { for (const key in item) {
if (item.hasOwnProperty(key)) { if (item.hasOwnProperty(key)) {
header[key] = item[key]; header[key] = item[key];
} }
} }
} }
@ -40,20 +45,20 @@ const handleNotify = function(metadata, notifyEntry) {
options.method = notifyEntry.method; options.method = notifyEntry.method;
if ( notifyEntry.endpoint ) { if (notifyEntry.endpoint) {
options.url = notifyEntry.endpoint; options.url = notifyEntry.endpoint;
} }
return new Promise(( resolve, reject) => { return new Promise((resolve, reject) => {
request(options, function(err, response, body) { request(options, function(err, response, body) {
if (err || response.statusCode >= 400) { if (err || response.statusCode >= 400) {
const errorMessage = _.isNil(err) ? response.statusMessage : err; const errorMessage = _.isNil(err) ? response.statusMessage : err;
logger.logger.error({err: errorMessage}, ' notify error: @{err.message}' ); logger.logger.error({err: errorMessage}, ' notify error: @{err.message}');
reject(errorMessage); reject(errorMessage);
} else { } else {
logger.logger.info({content: content}, 'A notification has been shipped: @{content}'); logger.logger.info({content: content}, 'A notification has been shipped: @{content}');
if (body) { if (body) {
logger.logger.debug({body: body}, ' body: @{body}' ); logger.logger.debug({body: body}, ' body: @{body}');
} }
resolve(_.isNil(body) === false ? body : null); resolve(_.isNil(body) === false ? body : null);
} }
@ -61,13 +66,13 @@ const handleNotify = function(metadata, notifyEntry) {
}); });
}; };
const notify = function(metadata, config) { const notify = function(metadata, config, publisherInfo) {
if (config.notify) { if (config.notify) {
if (config.notify.content) { if (config.notify.content) {
return handleNotify(metadata, config.notify); return handleNotify(metadata, config.notify, publisherInfo);
} else { } else {
// multiple notifications endpoints PR #108 // multiple notifications endpoints PR #108
return Promise.all(_.map(config.notify, (key) => handleNotify(metadata, key))); return Promise.all(_.map(config.notify, (key) => handleNotify(metadata, key, publisherInfo)));
} }
} }
}; };

View file

@ -12,10 +12,14 @@ export default function(express) {
'Content-Type': HEADERS.JSON 'Content-Type': HEADERS.JSON
}], }],
endpoint: "http://localhost:55550/api/notify", endpoint: "http://localhost:55550/api/notify",
content: '{"color":"green","message":"New package published: * {{ name }}*","notify":true,"message_format":"text"}' content: '{"color":"green","message":"New package published: * {{ name }}*. Publisher name: * {{ publisher.name }} *.","notify":true,"message_format":"text"}'
} }
}; };
const publisherInfo = {
name: "publisher-name-test"
};
describe('notifications', () => { describe('notifications', () => {
beforeAll(function () { beforeAll(function () {
@ -33,10 +37,14 @@ export default function(express) {
name: "pkg-test" name: "pkg-test"
}; };
notify(metadata, config).then(function (body) { notify(metadata, config, publisherInfo).then(function (body) {
const jsonBody = JSON.parse(body); const jsonBody = JSON.parse(body);
assert.ok(`New package published: * ${metadata.name}*` === jsonBody.message, assert.ok(
'Body notify message should be equal'); `New package published: * ${metadata.name}*. Publisher name: * ${
publisherInfo.name
} *.` === jsonBody.message,
"Body notify message should be equal"
);
done(); done();
}, function (err) { }, function (err) {
assert.fail(err); assert.fail(err);
@ -54,10 +62,14 @@ export default function(express) {
'Content-Type': HEADERS.JSON 'Content-Type': HEADERS.JSON
}; };
notify(metadata, configMultipleHeader).then(function (body) { notify(metadata, configMultipleHeader, publisherInfo).then(function (body) {
const jsonBody = JSON.parse(body); const jsonBody = JSON.parse(body);
assert.ok(`New package published: * ${metadata.name}*` === jsonBody.message, assert.ok(
'Body notify message should be equal'); `New package published: * ${metadata.name}*. Publisher name: * ${
publisherInfo.name
} *.` === jsonBody.message,
"Body notify message should be equal"
);
done(); done();
}, function (err) { }, function (err) {
assert.fail(err); assert.fail(err);
@ -85,11 +97,15 @@ export default function(express) {
multipleNotificationsEndpoint.notify.push(notificationSettings); multipleNotificationsEndpoint.notify.push(notificationSettings);
} }
notify(metadata, multipleNotificationsEndpoint).then(function (body) { notify(metadata, multipleNotificationsEndpoint, publisherInfo).then(function (body) {
body.forEach(function(notification) { body.forEach(function(notification) {
const jsonBody = JSON.parse(notification); const jsonBody = JSON.parse(notification);
assert.ok(`New package published: * ${metadata.name}*` === jsonBody.message, assert.ok(
'Body notify message should be equal'); `New package published: * ${metadata.name}*. Publisher name: * ${
publisherInfo.name
} *.` === jsonBody.message,
"Body notify message should be equal"
);
}); });
done(); done();
}, function (err) { }, function (err) {
@ -105,7 +121,7 @@ export default function(express) {
const configFail = _.cloneDeep(config); const configFail = _.cloneDeep(config);
configFail.notify.endpoint = "http://localhost:55550/api/notify/bad"; configFail.notify.endpoint = "http://localhost:55550/api/notify/bad";
notify(metadata, configFail).then(function () { notify(metadata, configFail, publisherInfo).then(function () {
assert.equal(false, 'This service should fails with status code 400'); assert.equal(false, 'This service should fails with status code 400');
done(); done();
}, function (err) { }, function (err) {
@ -114,5 +130,31 @@ export default function(express) {
}); });
}); });
test("publisher property should not be overridden if it exists in metadata", done => {
const metadata = {
name: "pkg-test",
publisher: {
name: "existing-publisher-name"
}
};
notify(metadata, config, publisherInfo).then(
function(body) {
const jsonBody = JSON.parse(body);
assert.ok(
`New package published: * ${metadata.name}*. Publisher name: * ${
metadata.publisher.name
} *.` === jsonBody.message,
"Body notify message should be equal"
);
done();
},
function(err) {
assert.fail(err);
done();
}
);
});
}); });
} }