Comparing version 0.1.4 to 0.2.0
@@ -8,3 +8,3 @@ var Q = require('q'), | ||
this.wsapiUrl = format('%s/slm/webservice/%s', options.server, options.apiVersion); | ||
this.httpRequest = request.defaults(options.requestOptions); | ||
this.httpRequest = request.defaults(options.requestOptions || {}); | ||
this._hasKey = options.requestOptions && | ||
@@ -11,0 +11,0 @@ options.requestOptions.headers && |
@@ -32,4 +32,4 @@ /** | ||
requestOptions: { | ||
jar: true, | ||
json: true, | ||
gzip: true, | ||
headers: { | ||
@@ -50,3 +50,4 @@ 'X-RallyIntegrationLibrary': format('%s v%s', pkgInfo.description, pkgInfo.version), | ||
zsessionid: apiKey | ||
} | ||
}, | ||
jar: false | ||
} | ||
@@ -61,3 +62,4 @@ }, options); | ||
sendImmediately: false | ||
} | ||
}, | ||
jar: true | ||
} | ||
@@ -271,2 +273,56 @@ }, options); | ||
function collectionPost(options, operation, callback) { | ||
var deferred = Q.defer(); | ||
this.request.post(_.merge({ | ||
url: refUtils.getRelative(options.ref) + '/' + options.collection + '/' + operation, | ||
json: {CollectionItems: options.data} | ||
}, options.requestOptions, | ||
optionsToRequestOptions(options)), function(error, result) { | ||
if (error) { | ||
deferred.reject(error); | ||
} else { | ||
deferred.resolve(result); | ||
} | ||
}); | ||
return deferred.promise.nodeify(callback); | ||
} | ||
/** | ||
Adds items to a collection | ||
@param {object} options - The add options (required) | ||
- @member {string} ref - The ref of the collection to update, e.g. /user/12345 (required) | ||
- @member {string} collection - The name of the collection to update, e.g. 'TeamMemberships (required) | ||
- @member {object} data - [{_ref: objectRef}, {Name:"Joe"}], things to be added to the collection (required) | ||
- @member {string/string[]} fetch - the fields to include on the returned records | ||
- @member {object} scope - the default scoping to use. if not specified server default will be used. | ||
- @member {ref} scope.workspace - the workspace | ||
- @member {object} requestOptions - Additional options to be applied to the request: https://github.com/mikeal/request (optional) | ||
@param {function} callback - A callback to be called when the operation completes | ||
- @param {string[]} errors - Any errors which occurred | ||
- @param {object} result - the operation result | ||
@return {promise} | ||
*/ | ||
RestApi.prototype.add = function(options, callback) { | ||
return collectionPost.call(this, options, 'add', callback); | ||
}; | ||
/** | ||
Remove items from a collection | ||
@param {object} options - The remove options (required) | ||
- @member {string} ref - The ref of the collection to update, e.g. /user/12345 (required) | ||
- @member {string} collection - The name of the collection to update, e.g. 'TeamMemberships (required) | ||
- @member {object} data - [{_ref: objectRef}], where the objectRefs are to be removed from the collection (required) | ||
- @member {string/string[]} fetch - the fields to include on the returned records | ||
- @member {object} scope - the default scoping to use. if not specified server default will be used. | ||
- @member {ref} scope.workspace - the workspace | ||
- @member {object} requestOptions - Additional options to be applied to the request: https://github.com/mikeal/request (optional) | ||
@param {function} callback - A callback to be called when the operation completes | ||
- @param {string[]} errors - Any errors which occurred | ||
- @param {object} result - the operation result | ||
@return {promise} | ||
*/ | ||
RestApi.prototype.remove = function(options, callback) { | ||
return collectionPost.call(this, options, 'remove', callback); | ||
}; | ||
module.exports = RestApi; |
{ | ||
"name": "rally", | ||
"version": "0.1.4", | ||
"version": "0.2.0", | ||
"description": "Rally REST Toolkit for Node.js", | ||
@@ -20,10 +20,10 @@ "contributors": [ | ||
"dependencies": { | ||
"request": "2.29.x", | ||
"q": "0.9.7", | ||
"request": "2.51.x", | ||
"q": "1.1.x", | ||
"lodash": "2.4.x" | ||
}, | ||
"devDependencies": { | ||
"mocha": "1.15.x", | ||
"should": "2.1.x", | ||
"sinon": "1.7.x" | ||
"mocha": "1.21.x", | ||
"should": "3.3.x", | ||
"sinon": "1.12.x" | ||
}, | ||
@@ -30,0 +30,0 @@ "author": "Kyle Morse", |
@@ -82,6 +82,6 @@ var should = require('should'), | ||
initArgs.requestOptions.headers.should.eql({ | ||
'X-RallyIntegrationLibrary': 'Rally REST Toolkit for Node.js v0.1.4', | ||
'X-RallyIntegrationLibrary': 'Rally REST Toolkit for Node.js v0.2.0', | ||
'X-RallyIntegrationName': 'Rally REST Toolkit for Node.js', | ||
'X-RallyIntegrationVendor': 'Rally Software, Inc.', | ||
'X-RallyIntegrationVersion': '0.1.4' | ||
'X-RallyIntegrationVersion': '0.2.0' | ||
}); | ||
@@ -97,2 +97,3 @@ restApi.request.should.be.exactly(request.init.firstCall.returnValue); | ||
requestOptions.headers.zsessionid.should.eql(key); | ||
requestOptions.jar.should.eql(false); | ||
restApi.request.should.be.exactly(request.init.firstCall.returnValue); | ||
@@ -108,2 +109,3 @@ }); | ||
requestOptions.headers.zsessionid.should.eql(key); | ||
requestOptions.jar.should.eql(false); | ||
restApi.request.should.be.exactly(request.init.firstCall.returnValue); | ||
@@ -487,3 +489,3 @@ }); | ||
this.get.restore(); | ||
this.get = sinon.stub(request.Request.prototype, 'get', function(options) { | ||
sinon.stub(request.Request.prototype, 'get', function(options) { | ||
var start = options.qs.start, | ||
@@ -494,2 +496,5 @@ pageSize = options.qs.pagesize; | ||
}); | ||
afterEach(function(){ | ||
request.Request.prototype.get.restore(); | ||
}); | ||
@@ -576,3 +581,203 @@ it('should return 1 page if no limit specified', function(done) { | ||
}); | ||
describe('add', function() { | ||
it('translates request options', function() { | ||
var restApi = new RestApi(); | ||
restApi.add({ | ||
ref: '/defect/1234', | ||
data: [{_ref: '/defect/2345'}], | ||
collection: 'Duplicates', | ||
scope: {workspace: '/workspace/1234'}, | ||
fetch: ['FormattedID'], | ||
requestOptions: { | ||
qs: {foo: 'bar'} | ||
} | ||
}); | ||
this.post.callCount.should.eql(1); | ||
var args = this.post.firstCall.args[0]; | ||
args.qs.workspace.should.eql('/workspace/1234'); | ||
args.qs.fetch.should.eql('FormattedID'); | ||
args.qs.foo.should.eql('bar'); | ||
}); | ||
it('generates correct post request', function() { | ||
var restApi = new RestApi(); | ||
var callback = sinon.stub(); | ||
restApi.add({ | ||
ref: '/defect/1234', | ||
data: [{_ref: '/defect/2345'}], | ||
collection: 'Duplicates' | ||
}, callback); | ||
this.post.callCount.should.eql(1); | ||
var args = this.post.firstCall.args; | ||
args[0].url.should.eql('/defect/1234/Duplicates/add'); | ||
args[0].json.should.eql({CollectionItems: [{_ref: '/defect/2345'}]}); | ||
}); | ||
it('calls back with result', function(done) { | ||
this.post.yieldsAsync(null, {Errors: [], Warnings: [], Results: [{_ref: '/defect/2345'}]}); | ||
var restApi = new RestApi(); | ||
restApi.add({ | ||
ref: '/defect/1234', | ||
data: [{_ref: '/defect/2345'}], | ||
collection: 'Duplicates' | ||
}, function(error, result) { | ||
should.not.exist(error); | ||
result.Errors.should.eql([]); | ||
result.Warnings.should.eql([]); | ||
result.Results.should.eql([{_ref: '/defect/2345'}]); | ||
done(); | ||
}); | ||
}); | ||
it('resolves promise with result', function(done) { | ||
this.post.yieldsAsync(null, {Errors: [], Warnings: [], Results: [{_ref: '/defect/2345'}]}); | ||
var restApi = new RestApi(); | ||
var onError = sinon.stub(); | ||
restApi.add({ | ||
ref: '/defect/1234', | ||
data: [{_ref: '/defect/2345'}], | ||
collection: 'Duplicates' | ||
}).then(function(result) { | ||
onError.callCount.should.eql(0); | ||
result.Errors.should.eql([]); | ||
result.Warnings.should.eql([]); | ||
result.Results.should.eql([{_ref: '/defect/2345'}]); | ||
done(); | ||
}, onError).done(); | ||
}); | ||
it('calls back with error', function(done) { | ||
var error = 'Error!'; | ||
this.post.yieldsAsync([error], null); | ||
var restApi = new RestApi(); | ||
restApi.add({ | ||
ref: '/defect/1234', | ||
data: [{_ref: '/defect/2345'}], | ||
collection: 'Duplicates' | ||
}, function(err, result) { | ||
err.should.eql([error]); | ||
should.not.exist(result); | ||
done(); | ||
}); | ||
}); | ||
it('rejects promise with error', function(done) { | ||
var error = 'Error!'; | ||
this.post.yieldsAsync([error], null); | ||
var restApi = new RestApi(); | ||
var onSuccess = sinon.stub(); | ||
restApi.add({ | ||
ref: '/defect/1234', | ||
data: [{_ref: '/defect/2345'}], | ||
collection: 'Duplicates' | ||
}).then(onSuccess, function(err) { | ||
onSuccess.callCount.should.eql(0); | ||
err.should.eql([error]); | ||
done(); | ||
}).done(); | ||
}); | ||
}); | ||
describe('remove', function() { | ||
it('translates request options', function() { | ||
var restApi = new RestApi(); | ||
restApi.remove({ | ||
ref: '/defect/1234', | ||
data: [{_ref: '/defect/2345'}], | ||
collection: 'Duplicates', | ||
scope: {workspace: '/workspace/1234'}, | ||
fetch: ['FormattedID'], | ||
requestOptions: { | ||
qs: {foo: 'bar'} | ||
} | ||
}); | ||
this.post.callCount.should.eql(1); | ||
var args = this.post.firstCall.args[0]; | ||
args.qs.workspace.should.eql('/workspace/1234'); | ||
args.qs.fetch.should.eql('FormattedID'); | ||
args.qs.foo.should.eql('bar'); | ||
}); | ||
it('generates correct post request', function() { | ||
var restApi = new RestApi(); | ||
var callback = sinon.stub(); | ||
restApi.remove({ | ||
ref: '/defect/1234', | ||
data: [{_ref: '/defect/2345'}], | ||
collection: 'Duplicates' | ||
}, callback); | ||
this.post.callCount.should.eql(1); | ||
var args = this.post.firstCall.args; | ||
args[0].url.should.eql('/defect/1234/Duplicates/remove'); | ||
args[0].json.should.eql({CollectionItems: [{_ref: '/defect/2345'}]}); | ||
}); | ||
it('calls back with result', function(done) { | ||
this.post.yieldsAsync(null, {Errors: [], Warnings: []}); | ||
var restApi = new RestApi(); | ||
restApi.remove({ | ||
ref: '/defect/1234', | ||
data: [{_ref: '/defect/2345'}], | ||
collection: 'Duplicates' | ||
}, function(error, result) { | ||
should.not.exist(error); | ||
result.Errors.should.eql([]); | ||
result.Warnings.should.eql([]); | ||
done(); | ||
}); | ||
}); | ||
it('resolves promise with result', function(done) { | ||
this.post.yieldsAsync(null, {Errors: [], Warnings: []}); | ||
var restApi = new RestApi(); | ||
var onError = sinon.stub(); | ||
restApi.remove({ | ||
ref: '/defect/1234', | ||
data: [{_ref: '/defect/2345'}], | ||
collection: 'Duplicates' | ||
}).then(function(result) { | ||
onError.callCount.should.eql(0); | ||
result.Errors.should.eql([]); | ||
result.Warnings.should.eql([]); | ||
done(); | ||
}, onError).done(); | ||
}); | ||
it('calls back with error', function(done) { | ||
var error = 'Error!'; | ||
this.post.yieldsAsync([error], null); | ||
var restApi = new RestApi(); | ||
restApi.remove({ | ||
ref: '/defect/1234', | ||
data: [{_ref: '/defect/2345'}], | ||
collection: 'Duplicates' | ||
}, function(err, result) { | ||
err.should.eql([error]); | ||
should.not.exist(result); | ||
done(); | ||
}); | ||
}); | ||
it('rejects promise with error', function(done) { | ||
var error = 'Error!'; | ||
this.post.yieldsAsync([error], null); | ||
var restApi = new RestApi(); | ||
var onSuccess = sinon.stub(); | ||
restApi.remove({ | ||
ref: '/defect/1234', | ||
data: [{_ref: '/defect/2345'}], | ||
collection: 'Duplicates' | ||
}).then(onSuccess, function(err) { | ||
onSuccess.callCount.should.eql(0); | ||
err.should.eql([error]); | ||
done(); | ||
}).done(); | ||
}); | ||
}); | ||
}); | ||
}); |
105082
2026
+ Addedbl@0.9.5(transitive)
+ Addedcaseless@0.8.0(transitive)
+ Addedcore-util-is@1.0.3(transitive)
+ Addedform-data@0.2.0(transitive)
+ Addedhawk@1.1.1(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedisarray@0.0.1(transitive)
+ Addedmime-db@1.12.0(transitive)
+ Addedmime-types@1.0.22.0.14(transitive)
+ Addedoauth-sign@0.5.0(transitive)
+ Addedq@1.1.2(transitive)
+ Addedqs@2.3.3(transitive)
+ Addedreadable-stream@1.0.34(transitive)
+ Addedrequest@2.51.0(transitive)
+ Addedstring_decoder@0.10.31(transitive)
+ Addedstringstream@0.0.6(transitive)
+ Addedtldts@6.1.77(transitive)
+ Addedtldts-core@6.1.77(transitive)
+ Addedtough-cookie@5.1.1(transitive)
+ Addedtunnel-agent@0.4.3(transitive)
- Removedform-data@0.1.4(transitive)
- Removedhawk@1.0.0(transitive)
- Removedmime@1.2.11(transitive)
- Removedoauth-sign@0.3.0(transitive)
- Removedpunycode@2.3.1(transitive)
- Removedq@0.9.7(transitive)
- Removedqs@0.6.6(transitive)
- Removedrequest@2.29.0(transitive)
- Removedtough-cookie@0.9.15(transitive)
- Removedtunnel-agent@0.3.0(transitive)
Updatedq@1.1.x
Updatedrequest@2.51.x