feat: add changes api (#1734)
This commit is contained in:
55
controllers/registry/package/changes.js
Normal file
55
controllers/registry/package/changes.js
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var packageService = require('../../../services/package');
|
||||||
|
var lodash = require('lodash');
|
||||||
|
var gather = require('co-gather');
|
||||||
|
|
||||||
|
// GET /-/_changes?since={timestamp}&limit={number}&cursorId={number}
|
||||||
|
// List changes since the timestamp
|
||||||
|
// Similar with https://registry.npmmirror.com/_changes?since=1658974943840
|
||||||
|
// Change types:
|
||||||
|
// 1. ✅ PACKAGE_VERSION_ADDED
|
||||||
|
// 2. ✅ PACKAGE_TAG_ADDED
|
||||||
|
// 3. 🆕 PACKAGE_UNPUBLISHED
|
||||||
|
// 4. 🆕 PACKAGE_VERSION_BLOCKED
|
||||||
|
// 5. ❎ PACKAGE_MAINTAINER_REMOVED
|
||||||
|
// 6. ❎ PACKAGE_MAINTAINER_CHANGED
|
||||||
|
// 7. ❎ PACKAGE_TAG_CHANGED
|
||||||
|
//
|
||||||
|
// Since we don't have the previous data,
|
||||||
|
// We can't compute the reliable seqId
|
||||||
|
// use gmt_modified cinstead of seqId
|
||||||
|
module.exports = function* listSince() {
|
||||||
|
var query = this.query;
|
||||||
|
var since = query.since;
|
||||||
|
var limit = Number(query.limit);
|
||||||
|
|
||||||
|
// ensure limit
|
||||||
|
if (Number.isNaN(limit)) {
|
||||||
|
limit = 1000;
|
||||||
|
}
|
||||||
|
var queryResults = yield gather(
|
||||||
|
[
|
||||||
|
"listVersionSince",
|
||||||
|
"listTagSince",
|
||||||
|
"listUnpublishedModuleSince",
|
||||||
|
"listBlockVersionSince",
|
||||||
|
].map(function (method) {
|
||||||
|
return packageService[method](since, limit);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
var validResults = queryResults.map(function (result) {
|
||||||
|
if (!result.isError) {
|
||||||
|
return result.value;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
|
var results = lodash.orderBy(
|
||||||
|
lodash.flatten(validResults).filter(Boolean),
|
||||||
|
"gmt_modified",
|
||||||
|
"asc"
|
||||||
|
).slice(0, limit);
|
||||||
|
this.body = { results };
|
||||||
|
};
|
||||||
@@ -159,3 +159,10 @@ exports.getOssLicenseUrlFromName = function (name) {
|
|||||||
return licenseMap[name.toLowerCase()] ?
|
return licenseMap[name.toLowerCase()] ?
|
||||||
base + licenseMap[name.toLowerCase()] : base + name;
|
base + licenseMap[name.toLowerCase()] : base + name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.ensureSinceIsDate = function(since) {
|
||||||
|
if (!(since instanceof Date)) {
|
||||||
|
return new Date(Number(since));
|
||||||
|
}
|
||||||
|
return since;
|
||||||
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
"koa-rewrite": "^1.1.2",
|
"koa-rewrite": "^1.1.2",
|
||||||
"koa-rt": "^1.0.0",
|
"koa-rt": "^1.0.0",
|
||||||
"koa-safe-jsonp": "^0.3.1",
|
"koa-safe-jsonp": "^0.3.1",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"markdown-it": "^8.3.2",
|
"markdown-it": "^8.3.2",
|
||||||
"mime": "^1.3.6",
|
"mime": "^1.3.6",
|
||||||
"mini-logger": "^1.1.3",
|
"mini-logger": "^1.1.3",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ var listAll = require('../controllers/registry/package/list_all');
|
|||||||
var listAllPackageVersions = require('../controllers/registry/package/list_versions');
|
var listAllPackageVersions = require('../controllers/registry/package/list_versions');
|
||||||
var listShorts = require('../controllers/registry/package/list_shorts');
|
var listShorts = require('../controllers/registry/package/list_shorts');
|
||||||
var listSince = require('../controllers/registry/package/list_since');
|
var listSince = require('../controllers/registry/package/list_since');
|
||||||
|
var changes = require('../controllers/registry/package/changes');
|
||||||
var listAllVersions = require('../controllers/registry/package/list');
|
var listAllVersions = require('../controllers/registry/package/list');
|
||||||
var listDependents = require('../controllers/registry/package/list_dependents');
|
var listDependents = require('../controllers/registry/package/list_dependents');
|
||||||
var getOneVersion = require('../controllers/registry/package/show');
|
var getOneVersion = require('../controllers/registry/package/show');
|
||||||
@@ -50,10 +51,10 @@ function routes(app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.get('/', jsonp, showTotal);
|
app.get('/', jsonp, showTotal);
|
||||||
|
|
||||||
// before /:name/:version
|
// before /:name/:version
|
||||||
// get all modules, for npm search
|
// get all modules, for npm search
|
||||||
app.get('/-/all', listAll);
|
app.get('/-/all', listAll);
|
||||||
|
app.get('/-/all/changes', changes);
|
||||||
app.get('/-/all/since', listSince);
|
app.get('/-/all/since', listSince);
|
||||||
// get all module names, for auto completion
|
// get all module names, for auto completion
|
||||||
app.get('/-/short', listShorts);
|
app.get('/-/short', listShorts);
|
||||||
|
|||||||
@@ -14,3 +14,10 @@ exports.isPrivatePackage = function (name) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.CHANGE_TYPE = {
|
||||||
|
PACKAGE_TAG_ADDED: 'PACKAGE_TAG_ADDED',
|
||||||
|
PACKAGE_VERSION_ADDED: 'PACKAGE_VERSION_ADDED',
|
||||||
|
PACKAGE_UNPUBLISHED: 'PACKAGE_UNPUBLISHED',
|
||||||
|
PACKAGE_VERSION_BLOCKED: 'PACKAGE_VERSION_BLOCKED'
|
||||||
|
};
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ var models = require('../models');
|
|||||||
var common = require('./common');
|
var common = require('./common');
|
||||||
var libCommon = require('../lib/common');
|
var libCommon = require('../lib/common');
|
||||||
var config = require('../config');
|
var config = require('../config');
|
||||||
|
var { ensureSinceIsDate } = require('../controllers/utils');
|
||||||
|
var { BlockPackageVersion } = require('../models');
|
||||||
var Tag = models.Tag;
|
var Tag = models.Tag;
|
||||||
var User = models.User;
|
var User = models.User;
|
||||||
var Module = models.Module;
|
var Module = models.Module;
|
||||||
@@ -15,6 +17,8 @@ var ModuleDependency = models.ModuleDependency;
|
|||||||
var ModuleUnpublished = models.ModuleUnpublished;
|
var ModuleUnpublished = models.ModuleUnpublished;
|
||||||
var NpmModuleMaintainer = models.NpmModuleMaintainer;
|
var NpmModuleMaintainer = models.NpmModuleMaintainer;
|
||||||
|
|
||||||
|
var CHANGE_TYPE = common.CHANGE_TYPE;
|
||||||
|
|
||||||
// module
|
// module
|
||||||
var _parseRow = function (row) {
|
var _parseRow = function (row) {
|
||||||
if (row.package.indexOf('%7B%22') === 0) {
|
if (row.package.indexOf('%7B%22') === 0) {
|
||||||
@@ -198,6 +202,77 @@ exports.listPublicModuleNamesByUser = function* (username) {
|
|||||||
return names;
|
return names;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.listModelSince = function(Model, attributes, mapper) {
|
||||||
|
return function*(since, limit) {
|
||||||
|
var start = ensureSinceIsDate(since);
|
||||||
|
var findCondition = {
|
||||||
|
attributes: attributes,
|
||||||
|
where: {
|
||||||
|
gmt_modified: {
|
||||||
|
gte: start
|
||||||
|
},
|
||||||
|
},
|
||||||
|
order: [['gmt_modified', 'ASC'], ['id', 'ASC']],
|
||||||
|
};
|
||||||
|
if (limit) {
|
||||||
|
findCondition.limit = limit;
|
||||||
|
}
|
||||||
|
var rows = yield Model.findAll(findCondition);
|
||||||
|
return rows.map(mapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.listTagSince = this.listModelSince(
|
||||||
|
Tag,
|
||||||
|
['id', 'name', 'tag', 'gmt_modified'],
|
||||||
|
function (row) {
|
||||||
|
return {
|
||||||
|
type: CHANGE_TYPE.PACKAGE_TAG_ADDED,
|
||||||
|
id: row.name,
|
||||||
|
changes: [{tag: row.tag}],
|
||||||
|
gmt_modified: row.gmt_modified,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.listVersionSince = this.listModelSince(
|
||||||
|
Module,
|
||||||
|
['id', 'name', 'version', 'gmt_modified'],
|
||||||
|
function (row) {
|
||||||
|
return {
|
||||||
|
type: CHANGE_TYPE.PACKAGE_VERSION_ADDED,
|
||||||
|
id: row.name,
|
||||||
|
changes: [{version: row.version}],
|
||||||
|
gmt_modified: row.gmt_modified,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.listUnpublishedModuleSince = this.listModelSince(
|
||||||
|
ModuleUnpublished,
|
||||||
|
['id', 'name', 'gmt_modified'],
|
||||||
|
function(row) {
|
||||||
|
return {
|
||||||
|
type: CHANGE_TYPE.PACKAGE_UNPUBLISHED,
|
||||||
|
id: row.name,
|
||||||
|
gmt_modified: row.gmt_modified,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.listBlockVersionSince = this.listModelSince(
|
||||||
|
BlockPackageVersion,
|
||||||
|
['id', 'name', 'version', 'gmt_modified'],
|
||||||
|
function(row) {
|
||||||
|
return {
|
||||||
|
type: CHANGE_TYPE.PACKAGE_VERSION_BLOCKED,
|
||||||
|
id: row.name,
|
||||||
|
gmt_modified: row.gmt_modified,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
// start must be a date or timestamp
|
// start must be a date or timestamp
|
||||||
exports.listPublicModuleNamesSince = function* listPublicModuleNamesSince(start) {
|
exports.listPublicModuleNamesSince = function* listPublicModuleNamesSince(start) {
|
||||||
if (!(start instanceof Date)) {
|
if (!(start instanceof Date)) {
|
||||||
|
|||||||
80
test/controllers/registry/package/changes.test.js
Normal file
80
test/controllers/registry/package/changes.test.js
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var should = require('should');
|
||||||
|
var request = require('supertest');
|
||||||
|
var mm = require('mm');
|
||||||
|
var app = require('../../../../servers/registry');
|
||||||
|
var utils = require('../../../utils');
|
||||||
|
var CHANGE_TYPE = require('../../../../services/common').CHANGE_TYPE;
|
||||||
|
|
||||||
|
describe('test/controllers/registry/package/changes.test.js', function () {
|
||||||
|
afterEach(mm.restore);
|
||||||
|
|
||||||
|
var since;
|
||||||
|
before(function (done) {
|
||||||
|
setTimeout(() => {
|
||||||
|
since = Date.now();
|
||||||
|
var pkg = utils.getPackage('@cnpmtest/test_changes', '0.0.1', utils.admin, 'alpha');
|
||||||
|
request(app)
|
||||||
|
.put('/' + pkg.name)
|
||||||
|
.set('authorization', utils.adminAuth)
|
||||||
|
.send(pkg)
|
||||||
|
.expect(201, function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
pkg = utils.getPackage('@cnpmtest/test_changes_gogo', '0.0.2', utils.admin, 'beta');
|
||||||
|
request(app)
|
||||||
|
.put('/' + pkg.name)
|
||||||
|
.set('authorization', utils.adminAuth)
|
||||||
|
.send(pkg)
|
||||||
|
.expect(201, done);
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /-/all/changes', function () {
|
||||||
|
it('should 200', function (done) {
|
||||||
|
request(app)
|
||||||
|
.get("/-/all/changes?since=" + since)
|
||||||
|
.expect(200, function (err, res) {
|
||||||
|
should.not.exist(err);
|
||||||
|
res.body.results.should.be.an.Array();
|
||||||
|
res.body.results
|
||||||
|
.filter(function (item) {
|
||||||
|
return item.type === CHANGE_TYPE.PACKAGE_VERSION_ADDED;
|
||||||
|
})
|
||||||
|
.length.should.equal(2);
|
||||||
|
res.body.results
|
||||||
|
.filter(function (item) {
|
||||||
|
return item.type === CHANGE_TYPE.PACKAGE_VERSION_ADDED;
|
||||||
|
})
|
||||||
|
.length.should.equal(2);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('since should work', function (done) {
|
||||||
|
var now = Date.now();
|
||||||
|
request(app)
|
||||||
|
.get("/-/all/changes?since=" + now + 5000)
|
||||||
|
.expect(200, function (err, res) {
|
||||||
|
should.not.exist(err);
|
||||||
|
res.body.results.should.be.an.Array();
|
||||||
|
res.body.results.length.should.equal(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('limit should work', function (done) {
|
||||||
|
request(app)
|
||||||
|
.get('/-/all/changes?limit=1&since=' + since)
|
||||||
|
.expect(200, function (err, res) {
|
||||||
|
should.not.exist(err);
|
||||||
|
res.body.results.should.be.an.Array();
|
||||||
|
res.body.results.length.should.equal(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -130,6 +130,69 @@ describe('test/services/package.test.js', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('listModelSince()', function () {
|
||||||
|
it('list tags since', function* () {
|
||||||
|
yield utils.createModule('test-listModuleSince-module-0', '1.0.0');
|
||||||
|
yield sleep(2100);
|
||||||
|
var start = Date.now() - 1000;
|
||||||
|
yield utils.createModule('test-listModuleSince-module-1', '1.0.0');
|
||||||
|
yield utils.createModule('test-listModuleSince-module-1', '1.0.1', null, 'beta');
|
||||||
|
yield utils.createModule('test-listModuleSince-module-2', '1.0.0');
|
||||||
|
var tags = yield Package.listTagSince(start);
|
||||||
|
|
||||||
|
var modules = tags.map(function (item) {
|
||||||
|
return { name: item.id, tag: item.changes[0].tag };
|
||||||
|
});
|
||||||
|
|
||||||
|
modules
|
||||||
|
.should.eql([
|
||||||
|
{ name: "test-listModuleSince-module-1", tag: "latest" },
|
||||||
|
{ name: "test-listModuleSince-module-1", tag: "beta" },
|
||||||
|
{ name: "test-listModuleSince-module-2", tag: "latest" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
tags = yield Package.listTagSince(start, 2);
|
||||||
|
modules = tags.map(function (item) {
|
||||||
|
return { name: item.id, tag: item.changes[0].tag};
|
||||||
|
});
|
||||||
|
modules
|
||||||
|
.should.eql([
|
||||||
|
{ name: "test-listModuleSince-module-1", tag: "latest" },
|
||||||
|
{ name: "test-listModuleSince-module-1", tag: "beta" },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('list package version since', function* () {
|
||||||
|
yield utils.createModule('test-listModuleSince-module-0', '1.0.0');
|
||||||
|
yield sleep(2100);
|
||||||
|
var start = Date.now() - 1000;
|
||||||
|
yield utils.createModule('test-listModuleSince-module-1', '1.0.0');
|
||||||
|
yield utils.createModule('test-listModuleSince-module-1', '1.0.1', null, 'beta');
|
||||||
|
yield utils.createModule('test-listModuleSince-module-2', '1.0.0');
|
||||||
|
var tags = yield Package.listVersionSince(start);
|
||||||
|
|
||||||
|
var modules = tags.map(function (item) {
|
||||||
|
return { name: item.id, version: item.changes[0].version };
|
||||||
|
});
|
||||||
|
|
||||||
|
modules
|
||||||
|
.should.eql([
|
||||||
|
{ name: "test-listModuleSince-module-1", version: "1.0.0" },
|
||||||
|
{ name: "test-listModuleSince-module-1", version: "1.0.1" },
|
||||||
|
{ name: "test-listModuleSince-module-2", version: "1.0.0" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
tags = yield Package.listVersionSince(start, 2);
|
||||||
|
modules = tags.map(function (item) {
|
||||||
|
return { name: item.id, version: item.changes[0].version};
|
||||||
|
});
|
||||||
|
modules
|
||||||
|
.should.eql([
|
||||||
|
{ name: "test-listModuleSince-module-1", version: "1.0.0" },
|
||||||
|
{ name: "test-listModuleSince-module-1", version: "1.0.1" },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('listPublicModuleNamesSince(), listAllPublicModuleNames()', function () {
|
describe('listPublicModuleNamesSince(), listAllPublicModuleNames()', function () {
|
||||||
it('should got those module names', function* () {
|
it('should got those module names', function* () {
|
||||||
yield utils.createModule('test-listPublicModuleNamesSince-module-0', '1.0.0');
|
yield utils.createModule('test-listPublicModuleNamesSince-module-0', '1.0.0');
|
||||||
|
|||||||
Reference in New Issue
Block a user