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:
parent
2208b4ef51
commit
1ca5298707
4 changed files with 96 additions and 23 deletions
|
@ -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
|
|
@ -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});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue