From c09d03b20deac9df629509a008e20a3c7b63b132 Mon Sep 17 00:00:00 2001 From: Alex Kocharin Date: Sun, 10 May 2015 18:23:31 +0300 Subject: [PATCH] add dist-tags endpoints --- lib/index-api.js | 68 +++++++++++++++- lib/local-storage.js | 29 ++++++- lib/storage.js | 13 ++- test/functional/fixtures/tags.json | 22 +++--- test/functional/tags.js | 123 ++++++++++++++++++++++++++++- 5 files changed, 236 insertions(+), 19 deletions(-) diff --git a/lib/index-api.js b/lib/index-api.js index 4f9072bc..58aa50ef 100644 --- a/lib/index-api.js +++ b/lib/index-api.js @@ -170,17 +170,77 @@ module.exports = function(config, auth, storage) { } }) - // tagging a package - app.put('/:package/:tag', can('publish'), media('application/json'), function(req, res, next) { + function tag_package_version(req, res, next) { if (typeof(req.body) !== 'string') return next('route') var tags = {} tags[req.params.tag] = req.body - storage.add_tags(req.params.package, tags, function(err) { + storage.merge_tags(req.params.package, tags, function(err) { if (err) return next(err) res.status(201) return next({ ok: 'package tagged' }) }) + } + + // tagging a package + app.put('/:package/:tag', + can('publish'), media('application/json'), tag_package_version) + + app.post('/-/package/:package/dist-tags/:tag', + can('publish'), media('application/json'), tag_package_version) + + app.put('/-/package/:package/dist-tags/:tag', + can('publish'), media('application/json'), tag_package_version) + + app.delete('/-/package/:package/dist-tags/:tag', can('publish'), function (req, res, next) { + var tags = {} + tags[req.params.tag] = null + storage.merge_tags(req.params.package, tags, function(err) { + if (err) return next(err) + res.status(201) + return next({ ok: 'tag removed' }) + }) + }) + + app.get('/-/package/:package/dist-tags', can('access'), function(req, res, next) { + storage.get_package(req.params.package, { req: req }, function(err, info) { + if (err) return next(err) + + next(info['dist-tags']) + }) + }) + + app.post('/-/package/:package/dist-tags', + can('publish'), media('application/json'), expect_json, + function(req, res, next) { + + storage.merge_tags(req.params.package, req.body, function(err) { + if (err) return next(err) + res.status(201) + return next({ ok: 'tags updated' }) + }) + }) + + app.put('/-/package/:package/dist-tags', + can('publish'), media('application/json'), expect_json, + function(req, res, next) { + + storage.replace_tags(req.params.package, req.body, function(err) { + if (err) return next(err) + res.status(201) + return next({ ok: 'tags updated' }) + }) + }) + + app.delete('/-/package/:package/dist-tags', + can('publish'), media('application/json'), + function(req, res, next) { + + storage.replace_tags(req.params.package, {}, function(err) { + if (err) return next(err) + res.status(201) + return next({ ok: 'tags removed' }) + }) }) // publishing a package @@ -271,7 +331,7 @@ module.exports = function(config, auth, storage) { } function add_tags(tags, cb) { - storage.add_tags(name, tags, cb) + storage.merge_tags(name, tags, cb) } }) diff --git a/lib/local-storage.js b/lib/local-storage.js index 04c1c9f0..cf34aa9f 100644 --- a/lib/local-storage.js +++ b/lib/local-storage.js @@ -251,11 +251,38 @@ Storage.prototype.add_version = function(name, version, metadata, tag, callback) }, callback) } -Storage.prototype.add_tags = function(name, tags, callback) { +Storage.prototype.merge_tags = function(name, tags, callback) { var self = this self.update_package(name, function updater(data, cb) { for (var t in tags) { + if (tags[t] === null) { + delete data['dist-tags'][t] + continue + } + + if (data.versions[tags[t]] == null) { + return cb( Error[404]("this version doesn't exist") ) + } + + Utils.tag_version(data, tags[t], t, self.config) + } + cb() + }, callback) +} + +Storage.prototype.replace_tags = function(name, tags, callback) { + var self = this + + self.update_package(name, function updater(data, cb) { + data['dist-tags'] = {} + + for (var t in tags) { + if (tags[t] === null) { + delete data['dist-tags'][t] + continue + } + if (data.versions[tags[t]] == null) { return cb( Error[404]("this version doesn't exist") ) } diff --git a/lib/storage.js b/lib/storage.js index 2a520915..a099a019 100644 --- a/lib/storage.js +++ b/lib/storage.js @@ -110,8 +110,17 @@ Storage.prototype.add_version = function(name, version, metadata, tag, callback) // // Used storages: local (write) // -Storage.prototype.add_tags = function(name, tag_hash, callback) { - return this.local.add_tags(name, tag_hash, callback) +Storage.prototype.merge_tags = function(name, tag_hash, callback) { + return this.local.merge_tags(name, tag_hash, callback) +} + +// +// Tags a package version with a provided tag +// +// Used storages: local (write) +// +Storage.prototype.replace_tags = function(name, tag_hash, callback) { + return this.local.replace_tags(name, tag_hash, callback) } // diff --git a/test/functional/fixtures/tags.json b/test/functional/fixtures/tags.json index 63487cca..acfca60a 100644 --- a/test/functional/fixtures/tags.json +++ b/test/functional/fixtures/tags.json @@ -1,44 +1,44 @@ { - "name": "testexp_tags", + "name": "__NAME__", "versions": { "0.1.0": { - "name": "testexp_tags", + "name": "__NAME__", "version": "0.1.0", "dist": { "shasum": "fake", - "tarball": "http://localhost:55551/testexp_tags/-/blahblah" + "tarball": "http://localhost:55551/__NAME__/-/blahblah" } }, "0.1.1alpha": { - "name": "testexp_tags", + "name": "__NAME__", "version": "0.1.1alpha", "dist": { "shasum": "fake", - "tarball": "http://localhost:55551/testexp_tags/-/blahblah" + "tarball": "http://localhost:55551/__NAME__/-/blahblah" } }, "0.1.2": { - "name": "testexp_tags", + "name": "__NAME__", "version": "0.1.2", "dist": { "shasum": "fake", - "tarball": "http://localhost:55551/testexp_tags/-/blahblah" + "tarball": "http://localhost:55551/__NAME__/-/blahblah" } }, "0.1.3alpha": { - "name": "testexp_tags", + "name": "__NAME__", "version": "0.1.3alpha", "dist": { "shasum": "fake", - "tarball": "http://localhost:55551/testexp_tags/-/blahblah" + "tarball": "http://localhost:55551/__NAME__/-/blahblah" } }, "1.1": { - "name": "testexp_tags", + "name": "__NAME__", "version": "1.1", "dist": { "shasum": "fake", - "tarball": "http://localhost:55551/testexp_tags/-/blahblah" + "tarball": "http://localhost:55551/__NAME__/-/blahblah" } } }, diff --git a/test/functional/tags.js b/test/functional/tags.js index 286043f6..b90068bc 100644 --- a/test/functional/tags.js +++ b/test/functional/tags.js @@ -18,7 +18,8 @@ module.exports = function() { describe('tags', function() { before(function () { express.get('/testexp_tags', function(req, res) { - res.send(JSON.parse(readfile('fixtures/tags.json'))) + var f = readfile('fixtures/tags.json').toString().replace(/__NAME__/g, 'testexp_tags') + res.send(JSON.parse(f)) }) }) @@ -44,4 +45,124 @@ module.exports = function() { }) }) }) + + describe('dist-tags methods', function() { + before(function () { + express.get('/testexp_tags2', function(req, res) { + var f = readfile('fixtures/tags.json').toString().replace(/__NAME__/g, 'testexp_tags2') + res.send(JSON.parse(f)) + }) + }) + + // populate cache + before(function () { + return server.get_package('testexp_tags2') + .status(200) + }) + + beforeEach(function () { + return server.request({ + method: 'PUT', + uri: '/-/package/testexp_tags2/dist-tags', + json: { + foo: '0.1.0', + bar: '0.1.1alpha', + baz: '0.1.2', + }, + }).status(201).body_ok(/tags updated/) + }) + + it('fetching tags', function () { + return server.request({ + method: 'GET', + uri: '/-/package/testexp_tags2/dist-tags', + }).status(200).then(function (body) { + assert.deepEqual(body, + { foo: '0.1.0', + bar: '0.1.1alpha', + baz: '0.1.2', + latest: '0.1.3alpha' }) + }) + }) + + it('merging tags', function () { + return server.request({ + method: 'POST', + uri: '/-/package/testexp_tags2/dist-tags', + json: { + foo: '0.1.2', + quux: '0.1.0', + }, + }).status(201).body_ok(/updated/).then(function () { + return server.request({ + method: 'GET', + uri: '/-/package/testexp_tags2/dist-tags', + }).status(200).then(function (body) { + assert.deepEqual(body, + { foo: '0.1.2', + bar: '0.1.1alpha', + baz: '0.1.2', + quux: '0.1.0', + latest: '0.1.3alpha' }) + }) + }) + }) + + it('replacing tags', function () { + return server.request({ + method: 'PUT', + uri: '/-/package/testexp_tags2/dist-tags', + json: { + foo: '0.1.2', + quux: '0.1.0', + }, + }).status(201).body_ok(/updated/).then(function () { + return server.request({ + method: 'GET', + uri: '/-/package/testexp_tags2/dist-tags', + }).status(200).then(function (body) { + assert.deepEqual(body, + { foo: '0.1.2', + quux: '0.1.0', + latest: '0.1.3alpha' }) + }) + }) + }) + + it('adding a tag', function () { + return server.request({ + method: 'PUT', + uri: '/-/package/testexp_tags2/dist-tags/foo', + json: '0.1.3alpha', + }).status(201).body_ok(/tagged/).then(function () { + return server.request({ + method: 'GET', + uri: '/-/package/testexp_tags2/dist-tags', + }).status(200).then(function (body) { + assert.deepEqual(body, + { foo: '0.1.3alpha', + bar: '0.1.1alpha', + baz: '0.1.2', + latest: '0.1.3alpha' }) + }) + }) + }) + + it('removing a tag', function () { + return server.request({ + method: 'DELETE', + uri: '/-/package/testexp_tags2/dist-tags/foo', + }).status(201).body_ok(/removed/).then(function () { + return server.request({ + method: 'GET', + uri: '/-/package/testexp_tags2/dist-tags', + }).status(200).then(function (body) { + assert.deepEqual(body, + { bar: '0.1.1alpha', + baz: '0.1.2', + latest: '0.1.3alpha' }) + }) + }) + }) + }) }