Socket
Socket
Sign inDemoInstall

@pact-foundation/pact-node

Package Overview
Dependencies
Maintainers
4
Versions
187
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@pact-foundation/pact-node - npm Package Compare versions

Comparing version 4.4.4 to 4.5.0

.editorconfig

28

package.json
{
"name": "@pact-foundation/pact-node",
"version": "4.4.4",
"version": "4.5.0",
"description": "A wrapper for the Ruby version of Pact to work within Node",

@@ -42,9 +42,9 @@ "main": "./src/pact.js",

"@pact-foundation/pact-provider-verifier": "0.1.1",
"bunyan": "^1.8.0",
"bunyan": "^1.8.1",
"bunyan-prettystream": "^0.1.3",
"check-types": "~6.0.0",
"check-types": "~7.0.0",
"commander": "^2.9.0",
"mkdirp": "^0.5.1",
"q": "^1.4.1",
"request": "^2.69.0",
"request": "^2.72.0",
"underscore": "^1.8.3",

@@ -59,14 +59,14 @@ "unixify": "^0.2.1",

"basic-auth": "^1.0.4",
"body-parser": "^1.15.1",
"chai": "^3.2.0",
"body-parser": "^1.15.2",
"chai": "^3.5.0",
"chai-as-promised": "^5.3.0",
"cors": "^2.7.1",
"cross-env": "^1.0.7",
"express": "^4.13.4",
"jscs": "^2.1.0",
"mocha": "^2.2.5",
"nodemon": "^1.4.1",
"rewire": "^2.5.1",
"rimraf": "^2.4.2",
"sinon": "^1.15.4"
"cross-env": "^1.0.8",
"express": "^4.14.0",
"jscs": "^3.0.6",
"mocha": "^2.5.3",
"nodemon": "^1.9.2",
"rewire": "^2.5.2",
"rimraf": "^2.5.3",
"sinon": "^1.17.4"
},

@@ -73,0 +73,0 @@ "scripts": {

@@ -83,3 +83,4 @@ <img src="https://raw.githubusercontent.com/pact-foundation/pact-logo/master/media/logo-black.png" width="200">

pactBrokerUsername: <String>, // Username for Pact Broker basic authentication. Optional
pactBrokerPassword: <String> // Password for Pact Broker basic authentication. Optional
pactBrokerPassword: <String> // Password for Pact Broker basic authentication. Optional,
tags: <Array>, // An array of Strings to tag the Pacts being published. Optional
};

@@ -86,0 +87,0 @@

@@ -23,3 +23,3 @@ /* global describe:true, before:true, after:true, it:true, global:true, process:true */

});
describe("Set Log Level", function () {

@@ -64,3 +64,3 @@ context("when setting a log level", function () {

dirPath;
beforeEach(function () {

@@ -67,0 +67,0 @@ dirPath = path.resolve(__dirname, '../.tmp/' + Math.floor(Math.random() * 1000));

@@ -10,35 +10,17 @@ 'use strict';

q = require('q'),
http = require('request'),
request = q.denodeify(require('request')),
urlJoin = require('url-join');
function Publisher(pactBroker, pactUrls, consumerVersion, pactBrokerUsername, pactBrokerPassword) {
this.options = {};
this.options.pactBroker = pactBroker;
this.options.pactUrls = pactUrls;
this.options.pactBrokerUsername = pactBrokerUsername;
this.options.pactBrokerPassword = pactBrokerPassword;
this.options.consumerVersion = consumerVersion;
function Publisher(pactBroker, pactUrls, consumerVersion, pactBrokerUsername, pactBrokerPassword, tags) {
this._options = {};
this._options.pactBroker = pactBroker;
this._options.pactUrls = pactUrls;
this._options.pactBrokerUsername = pactBrokerUsername;
this._options.pactBrokerPassword = pactBrokerPassword;
this._options.consumerVersion = consumerVersion;
this._options.tags = tags;
}
// Given Pact Options and a Pact File, construct a Pact URL used to
// PUT/POST to the Pact Broker.
var constructPutUrl = function(options, data) {
if (!_.has(options, 'pactBroker')) {
throw new Error("Cannot construct Pact publish URL: 'pactBroker' not specified");
}
if (!_.isObject(options)
|| !_.has(data, 'consumer')
|| !_.has(data, 'provider')
|| !_.has(data.consumer, 'name')
|| !_.has(data.provider, 'name')) {
throw new Error("Invalid Pact file given. " +
"Unable to parse consumer and provider name");
}
return urlJoin(options.pactBroker, 'pacts/provider', data.provider.name, 'consumer', data.consumer.name, 'version', options.consumerVersion)
};
Publisher.prototype.publish = function () {
var options = this.options;
var options = this._options;
logger.info('Publishing pacts to broker at: ' + options.pactBroker);

@@ -67,57 +49,11 @@

// Return a merge of all promises...
return q.all(_.map(uris, function (uri) {
// Authentication
var auth = null;
if (options.pactBrokerUsername && options.pactBrokerPassword) {
auth = {
user: options.pactBrokerUsername,
pass: options.pactBrokerPassword
}
}
try {
var deferred = q.defer();
// Promise to update provider/consumer
var getPactCollaborators;
// Parse the Pact file to extract consumer/provider names
if (/\.json$/.test(uri)) {
var readFile = q.nfbind(fs.readFile);
getPactCollaborators = readFile(uri, 'utf8')
.then(function(data) {
return JSON.parse(data)
}, function(err) {
return q.reject(err);
})
} else {
var request = q.denodeify(http);
var config = {
uri: uri,
method: 'GET',
headers: {
'Accept': 'application/json'
},
json: true,
auth: auth
};
getPactCollaborators = request(config)
.then(function(data) {
var body = data[0].body;
if (data[0].statusCode != 200) {
return q.reject(new Error('Cannot GET ' + uri + '. Nested exception: ' + body))
}
return body;
}, function(err) {
return q.reject(err);
})
}
return getPactCollaborators
.then(function(data) {
var url = constructPutUrl(options, data);
var config = {
uri: url,
return q.allSettled(
_.chain(uris)
.map(function (uri) {
return getPactFile(options, uri);
})
.map(function (file) {
return file.then(function (data) {
return callPact(options, {
uri: constructPutUrl(options, data),
method: 'PUT',

@@ -128,30 +64,139 @@ headers: {

},
body: data,
json: true,
auth: auth
};
body: data
}).fail(function (err) {
return q.reject(new Error('Unable to publish Pact to Broker. ' + err.message));
});
});
http(config, function (error, response) {
if (!error && response.statusCode == 200) {
deferred.resolve();
} else {
if (error != null) {
deferred.reject(error);
} else {
deferred.reject(new Error('Unable to publish Pact to Broker: ' + response.statusCode));
})
.map(function (publish) {
return publish.then(function (data) {
if (!options.tags.length) {
return data;
}
return q.allSettled(_.map(options.tags, function (tag) {
return callPact(options, {
uri: constructTagUrl(options, tag, data),
method: 'PUT',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}
}).fail(function () {
return q.reject(new Error('Could not tag Pact with tag "' + tag + '"'));
});
})).then(function (results) {
_.each(results, function (result) {
if (result.state !== "fulfilled") {
logger.warn(result.reason);
}
});
return data;
});
});
})
.value()
).then(function (results) {
var reject = false;
results = _.map(results, function (result) {
if (result.state === "fulfilled") {
return result.value;
} else {
reject = true;
return result.reason;
}
});
return reject ? q.reject(results) : results;
});
};
return deferred.promise;
}, function(err) {
return q.reject(err);
})
function callPact(options, config) {
config = _.extend({
uri: options.pactBroker ? options.pactBroker : 'http://localhost',
method: 'GET',
headers: {
'Accept': 'application/json'
},
json: true
}, config);
} catch (e) {
return q.reject("Invalid Pact file: " + uri + ". Nested exception: " + e.message);
// Authentication
if (options.pactBrokerUsername && options.pactBrokerPassword) {
config.auth = {
user: options.pactBrokerUsername,
pass: options.pactBrokerPassword
}
}))
};
}
return request(config).then(function (data) {
return data[0]; // return response only
}).then(function (response) {
if (response.statusCode < 200 || response.statusCode >= 300) {
return q.reject(new Error('Failed http call to pact broker. \nCode: ' + response.statusCode + '\nBody: ' + response.body));
}
return response.body;
});
}
function getPactFile(options, uri) {
// Parse the Pact file to extract consumer/provider names
if (/\.json$/.test(uri)) {
var readFile = q.denodeify(fs.readFile);
return readFile(uri, 'utf8')
.then(function (data) {
return JSON.parse(data);
}, function (err) {
return q.reject("Invalid Pact file: " + uri + ". Nested exception: " + err.message);
})
} else {
return callPact(options, {
uri: uri
}).fail(function (err) {
return q.reject(new Error('Cannot GET ' + uri + '. Nested exception: ' + err.message))
});
}
}
// Given Pact Options and a Pact File, construct a Pact URL used to
// PUT/POST to the Pact Broker.
function constructPutUrl(options, data) {
if (!_.has(options, 'pactBroker')) {
throw new Error("Cannot construct Pact publish URL: 'pactBroker' not specified");
}
if (!_.has(options, 'consumerVersion')) {
throw new Error("Cannot construct Pact publish URL: 'consumerVersion' not specified");
}
if (!_.isObject(options)
|| !_.has(data, 'consumer')
|| !_.has(data, 'provider')
|| !_.has(data.consumer, 'name')
|| !_.has(data.provider, 'name')) {
throw new Error("Invalid Pact file given. " +
"Unable to parse consumer and provider name");
}
return urlJoin(options.pactBroker, 'pacts/provider', data.provider.name, 'consumer', data.consumer.name, 'version', options.consumerVersion)
}
function constructTagUrl(options, tag, data) {
if (!_.has(options, 'pactBroker')) {
throw new Error("Cannot construct Pact Tag URL: 'pactBroker' not specified");
}
if (!_.has(options, 'consumerVersion')) {
throw new Error("Cannot construct Pact Tag URL: 'consumerVersion' not specified");
}
if (!_.isObject(options)
|| !_.has(data, 'consumer')
|| !_.has(data.consumer, 'name')) {
throw new Error("Invalid Pact file given. " +
"Unable to parse consumer name");
}
return urlJoin(options.pactBroker, 'pacticipants', data.consumer.name, 'version', options.consumerVersion, 'tags', tag)
}
// Creates a new instance of the pact server with the specified option

@@ -162,2 +207,3 @@ module.exports = function (options) {

options.pactUrls = options.pactUrls || [];
options.tags = options.tags || [];

@@ -202,3 +248,3 @@ if (options.pactUrls) {

return new Publisher(options.pactBroker, options.pactUrls, options.consumerVersion, options.pactBrokerUsername, options.pactBrokerPassword);
return new Publisher(options.pactBroker, options.pactUrls, options.consumerVersion, options.pactBrokerUsername, options.pactBrokerPassword, options.tags);
};

@@ -12,2 +12,3 @@ /* global describe:true, before:true, after:true, it:true, global:true, process:true */

constructPutUrl = publisher.__get__('constructPutUrl'),
constructTagUrl = publisher.__get__('constructTagUrl'),
broker = require('../test/integration/brokerMock.js'),

@@ -104,9 +105,9 @@ chaiAsPromised = require("chai-as-promised");

it("should return a PUT url", function () {
var options = { 'pactBroker': 'http://foo' };
var options = { 'pactBroker': 'http://foo', 'consumerVersion': '1' };
var data = { 'consumer': { 'name': 'consumerName' }, 'provider': { 'name': 'providerName' } };
expect(constructPutUrl(options, data)).to.eq('http://foo/pacts/provider/providerName/consumer/consumerName/version/');
expect(constructPutUrl(options, data)).to.eq('http://foo/pacts/provider/providerName/consumer/consumerName/version/1');
});
});
context("when given an invalid config object", function () {
it("should return a PUT url", function () {
it("should throw Error when pactBroker is not specified", function () {
var options = { 'someotherurl': 'http://foo' };

@@ -118,6 +119,13 @@ var data = { 'consumer': { 'name': 'consumerName' }, 'provider': { 'name': 'providerName' } };

});
it("should throw Error when consumerVersion is not specified", function () {
var options = { 'pactBroker': 'http://foo' };
var data = { 'consumer': { 'name': 'consumerName' }, 'provider': { 'name': 'providerName' } };
expect(function() {
constructPutUrl(options, data);
}).to.throw(Error, "Cannot construct Pact publish URL: 'consumerVersion' not specified");
});
});
context("when given an invalid pact file (no consumer/provider keys)", function () {
it("should return a PUT url", function () {
var options = { 'pactBroker': 'http://foo' };
var options = { 'pactBroker': 'http://foo', 'consumerVersion': '1' };
var data = { };

@@ -131,3 +139,3 @@ expect(function() {

it("should return a PUT url", function () {
var options = { 'pactBroker': 'http://foo' };
var options = { 'pactBroker': 'http://foo', 'consumerVersion': '1' };
var data = { 'consumer': {}, 'provider': {} };

@@ -140,2 +148,46 @@ expect(function() {

});
context("constructTagUrl", function () {
context("when given a valid config object and pact JSON", function () {
it("should return a PUT url", function () {
var options = { 'pactBroker': 'http://foo', consumerVersion: '1.0' };
var data = { 'consumer': { 'name': 'consumerName' } };
expect(constructTagUrl(options, 'test', data)).to.eq('http://foo/pacticipants/consumerName/version/1.0/tags/test');
});
});
context("when given an invalid config object", function () {
it("should throw Error when pactBroker is not specified", function () {
var options = { 'someotherurl': 'http://foo', consumerVersion: '1.0' };
var data = { 'consumer': { 'name': 'consumerName' } };
expect(function() {
constructTagUrl(options, data);
}).to.throw(Error, "Cannot construct Pact Tag URL: 'pactBroker' not specified");
});
it("should throw Error when consumerVersion is not specified", function () {
var options = { 'pactBroker': 'http://foo' };
var data = { 'consumer': { 'name': 'consumerName' }, 'provider': { 'name': 'providerName' } };
expect(function() {
constructTagUrl(options, data);
}).to.throw(Error, "Cannot construct Pact Tag URL: 'consumerVersion' not specified");
});
});
context("when given an invalid pact file (no consumer key)", function () {
it("should return a PUT url", function () {
var options = { 'pactBroker': 'http://foo', consumerVersion: '1.0' };
var data = { };
expect(function() {
constructTagUrl(options, data);
}).to.throw(Error, "Invalid Pact file given. Unable to parse consumer name");
});
});
context("when given an invalid pact file (no name keys)", function () {
it("should return a PUT url", function () {
var options = { 'pactBroker': 'http://foo', consumerVersion: '1.0' };
var data = { 'consumer': {} };
expect(function() {
constructTagUrl(options, data);
}).to.throw(Error, "Invalid Pact file given. Unable to parse consumer name");
});
});
});
});

@@ -21,5 +21,12 @@ var cors = require('cors'),

}
res.json(req.body);
res.status(201).json(req.body);
};
var tagPactFunction = function (req, res) {
if (_.isEmpty(req.params.consumer) || _.isEmpty(req.params.version) || _.isEmpty(req.params.tag)) {
return res.sendStatus(400);
}
res.sendStatus(201);
};
// Let's add Auth for good measure

@@ -50,2 +57,6 @@ var auth = function (req, res, next) {

// Tagging
server.put('/pacticipants/:consumer/version/:version/tags/:tag', tagPactFunction);
server.put('/auth/pacticipants/:consumer/version/:version/tags/:tag', tagPactFunction);
module.exports = server;

@@ -45,2 +45,15 @@ /* global describe:true, before:true, after:true, it:true, global:true, process:true */

});
it("should successfully tag all Pacts with 'test' and 'latest'", function () {
var publisher = publisherFactory({
pactBroker: pactBrokerBaseUrl,
pactUrls: [path.resolve(__dirname, 'integration/publish/publish-success.json')],
consumerVersion: "1.0.0",
tags: ['test', 'latest']
});
expect(publisher).to.be.a('object');
expect(publisher).to.respondTo('publish');
return expect(publisher.publish()).to.eventually.be.fulfilled;
});
});

@@ -113,2 +126,18 @@ context("and the Pact file is invalid", function () {

});
it("should successfully tag all Pacts sent with 'test' and 'latest'", function () {
var publisher = publisherFactory({
pactBroker: pactBrokerBaseUrl,
pactUrls: [path.resolve(__dirname, 'integration/publish/pactDirTests')],
consumerVersion: "1.0.0",
tags: ['test', 'latest']
});
expect(publisher).to.be.a('object');
expect(publisher).to.respondTo('publish');
return expect(publisher.publish()
.then(function (res) {
expect(res.length).to.eq(2);
})).to.eventually.be.fulfilled;
});
});

@@ -144,2 +173,13 @@

});
it("should successfully tag all Pacts sent with 'test' and 'latest'", function () {
var publisher = publisherFactory({
pactBroker: pactBrokerBaseUrl,
pactUrls: [pactBrokerBaseUrl + '/somepact'],
consumerVersion: "1.0.0",
tags: ['test', 'latest']
});
return expect(publisher.publish()).to.eventually.be.fulfilled;
});
});

@@ -159,4 +199,4 @@

})
.catch(function(err) {
expect(err.message).to.contain("Nested exception: Cannot GET /somepacturlthatdoesntexist")
.catch(function(results) {
expect(results[0].message).to.contain("Cannot GET /somepacturlthatdoesntexist")
})

@@ -177,4 +217,4 @@ });

})
.catch(function(err) {
expect(err.message).to.contain("Invalid Pact file given. Unable to parse consumer and provider name");
.catch(function(results) {
expect(results[0].message).to.contain("Invalid Pact file given. Unable to parse consumer and provider name");
})

@@ -181,0 +221,0 @@ });

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc