diff --git a/.travis.yml b/.travis.yml index acb6bb9..b8fa5f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,24 +1,7 @@ language: node_js -sudo: true +sudo: false node_js: - - "5" - "4" - -env: - - CXX=g++-4.8 -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.8 - -cache: - directories: - - node_modules - -after_script: - - npm run lint - - npm run coverage - - npm run publish-coverage + - "5" + diff --git a/lib/github.js b/lib/github.js index c5017aa..0fd8569 100644 --- a/lib/github.js +++ b/lib/github.js @@ -15,6 +15,7 @@ module.exports = function (options) { opts = extend(opts, options) opts.cache = seneca.make$('github') + opts.cache.load$() seneca.add('role:github,cmd:get', cmdGet) seneca.add('role:info,req:part', aliasGet) @@ -32,24 +33,32 @@ function cmdGet (msg, done) { if (err) return done(err) if (github && !msg.update) { - return done(null, github) + return done(null, github.data$(github)) } Request.get({url: registry, gzip: true}, (err, res, body) => { if (err) return done(err) - var data = JSON.parse(body) + var data = null + + try {data = JSON.parse(body)} + catch (e) {return done(e)} + var distTags = data['dist-tags'] || {} var latest = ((data.versions || {})[distTags.latest]) || {} var repository = latest.repository || {} var url = repository.url || '' - var matches = /[\/:]([^\/:]+?)[\/:]([^\/]+?)(\.git)*$/.exec(url) || [] + var matches = /[\/:]([^\/:]+?)[\/:]([^\/]+?)(\.git)*$/.exec(url) var params = { name: msg.name, url: url, - user: matches[1] || '', - repo: matches[2] || '' + user: matches[1] || null, + repo: matches[2] || null + } + + if (!params.user || !params.repo) { + return done(new Error('not found on npm')) } queryGithub(params, done) @@ -66,7 +75,7 @@ function aliasGet (msg, done) { payload.data = data seneca.act('role:info,res:part,part:github', payload) - done() + done(null, {ok: true}) }) } @@ -106,9 +115,9 @@ function queryGithub (msg, done) { cached: Date.now() } - function complete (err) { + function complete (err, data) { if (err) return done(err) - else done(null, data) + else done(null, data.data$(data)) } cache.load$(msg.name, (err, cached) => { diff --git a/package.json b/package.json index 88017fa..5cbd7a1 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,9 @@ "scripts": { "start": "node srv/start.js", "isolated": "GITHUB_ISOLATED=true node srv/start.js", - "lint": "lab test -dL" + "lint": "lab -P test -dL", + "test": "lab -m 5000 -t 75 -v -P test", + "cov": "lab -s -P test -r lcov | coveralls" }, "main": "lib/github.js", "keywords": [ @@ -33,7 +35,7 @@ "license": "MIT", "dependencies": { "github4": "0.5.4", - "request": "2.69.0", + "request": "2.70.0", "seneca": "2.0.0", "seneca-balance-client": "0.4.0", "seneca-entity": "0.0.1", @@ -45,10 +47,11 @@ "toolbag-plugin-udp-reporter": "1.0.0" }, "devDependencies": { - "code": "2.1.0", + "code": "2.2.0", + "coveralls": "2.11.9", "eslint-config-seneca": "1.1.2", "eslint-plugin-hapi": "4.0.0", - "eslint-plugin-standard": "1.3.1", - "lab": "8.2.0" + "eslint-plugin-standard": "1.3.2", + "lab": "10.3.1" } } diff --git a/test/github.test.js b/test/github.test.js index 6a296a0..c15cc14 100644 --- a/test/github.test.js +++ b/test/github.test.js @@ -2,66 +2,137 @@ var Lab = require('lab') var Code = require('code') -var Seneca = require('seneca') +var Proxyquire = require('proxyquire') +var NpmFakeData = require('./npm-data') var lab = exports.lab = Lab.script() - var describe = lab.describe var it = lab.it var expect = Code.expect -var Github = require('..') +var NpmProxy = { + request: { + get: (opts, done) => { + if (opts.url.includes('seneca')) { + done(null, {}, JSON.stringify(NpmFakeData)) + } + else { + done(new Error('npm error'), null, null) + } + } + } +} -/* - * Notice: For travis/CI, tests have been configured with a token provided by - * https://github.com/thekemkid. However, This is a read only token which will - * only be able to read from public repos. You can create a similar token in - * your github settings > personal access tokens > generate new token. You do - * not have to enable any special permissions for this token. - */ -describe('nodezoo-github', function () { - it('Fired the get pattern', function (done) { - var seneca = Seneca({ log: 'silent' }) - seneca.use(Github, { token: process.env.GITHUB_TOKEN }) +var Seneca = Proxyquire('seneca', {}) +var Github = Proxyquire('..', NpmProxy) - seneca.ready(function () { - seneca.act({ role: 'github', cmd: 'get', name: 'nodejs/node.git', giturl: 'git@github.com:nodejs/node.git' }, function (err, res) { - expect(err).to.not.exist() - expect(res.user).to.equal('nodejs') - expect(res.repo).to.equal('node') - expect(res.id).to.equal('nodejs/node.git') - done() - }) +function createInstance (done) { + var params = { + log: 'silent', + strict: 'false', + errhandler: (err) => { + if (err.at) done(err) + } + } + + return Seneca(params) + .use('entity') + .use(Github, {token: process.env.GITHUB_TOKEN}) +} + +describe('A valid "role:github,cmd:get" call', () => { + it('has data and no error', (done) => { + var seneca = createInstance(done) + var payload = {name: 'seneca'} + + seneca.act(`role:github,cmd:get`, payload, (err, reply) => { + expect(err).to.not.exist() + expect(reply).to.exist() + done() }) }) - it('Fired the query pattern', function (done) { - var seneca = Seneca({ log: 'silent' }) - seneca.use(Github, { token: process.env.GITHUB_TOKEN }) + it('returns cached data', (done) => { + var seneca = createInstance(done) + var payload = {name: 'seneca'} + + seneca.act(`role:github,cmd:get`, payload, (err, reply) => { + expect(err).to.not.exist() - seneca.ready(function () { - seneca.act({ role: 'github', cmd: 'query', name: 'nodejs/node.git', user: 'nodejs', repo: 'node' }, function (err, res) { + var cachedOne = reply.cached + + seneca.act(`role:github,cmd:get`, payload, (err, reply) => { expect(err).to.not.exist() - expect(res.user).to.equal('nodejs') - expect(res.repo).to.equal('node') - expect(res.id).to.equal('nodejs/node.git') + + var cachedTwo = reply.cached + + expect(cachedOne).to.equal(cachedTwo) done() }) }) }) - it('Fired the parse pattern', function (done) { - var seneca = Seneca({ log: 'silent' }) - seneca.use(Github, { token: process.env.GITHUB_TOKEN }) + it('can return non-cached data', (done) => { + var seneca = createInstance(done) + var payload = {name: 'seneca'} + + seneca.act(`role:github,cmd:get`, payload, (err, reply) => { + expect(err).to.not.exist() - seneca.ready(function () { - seneca.act({ role: 'github', cmd: 'parse', giturl: 'git@github.com:nodejs/node.git' }, function (err, res) { + var cachedOne = reply.cached + payload.update = true + + seneca.act(`role:github,cmd:get`, payload, (err, reply) => { expect(err).to.not.exist() - expect(res.user).to.equal('nodejs') - expect(res.repo).to.equal('node') + + var cachedTwo = reply.cached + + expect(cachedOne).to.be.below(cachedTwo) done() }) }) }) }) + +describe('An invalid "role:github,cmd:get" call', () => { + it('has an error and no data', (done) => { + var seneca = createInstance(done) + var payload = {name: 'shooobydoobydooboop'} + + seneca.act(`role:github,cmd:get`, payload, (err, reply) => { + expect(err).to.exist() + expect(reply).to.not.exist() + done() + }) + }) +}) + +describe('A valid "role:info,req:part" call', () => { + it('has no error and has data', (done) => { + var seneca = createInstance(done) + var payload = {name: 'seneca'} + + seneca.act(`role:info,req:part`, payload, (err, reply) => { + expect(err).to.not.exist() + expect(reply).to.exist() + done() + }) + }) + + it('responds via "role:info,res:part"', (done) => { + var seneca = createInstance(done) + var payload = {name: 'seneca'} + + seneca.add(`role:info,res:part`, (msg, cb) => { + expect(msg).to.exist() + cb() + done() + }) + + seneca.act(`role:info,req:part`, payload, (err, reply) => { + expect(err).to.not.exist() + expect(reply).to.exist() + }) + }) +}) diff --git a/test/npm-data.js b/test/npm-data.js new file mode 100644 index 0000000..b515733 --- /dev/null +++ b/test/npm-data.js @@ -0,0 +1,119 @@ +module.exports = { + '_id': 'seneca-entity', + '_rev': '3-1a2d436a902cdfaa820f4da8aeeeb4f1', + 'name': 'seneca-entity', + 'description': 'Entity plugin for seneca', + 'dist-tags': { + 'latest': '0.0.1' + }, + 'versions': { + '0.0.1': { + 'name': 'seneca-entity', + 'description': 'Entity plugin for seneca', + 'keywords': [ + 'seneca', + 'plugin' + ], + 'version': '0.0.1', + 'license': 'MIT', + 'homepage': 'http://senecajs.org', + 'author': { + 'name': 'Richard Rodger', + 'url': 'http://richardrodger.com/' + }, + 'dependencies': { + 'eraro': '0.4.1', + 'jsonic': '0.2.2', + 'lodash': '4.0.1' + }, + 'main': 'entity.js', + 'engines': { + 'node': '>=0.10.0' + }, + 'files': [ + 'LICENSE', + 'README.md', + 'lib', + 'entity.js' + ], + 'repository': { + 'type': 'git', + 'url': 'git+https://github.com/senecajs/seneca-entity.git' + }, + 'scripts': { + 'test': 'lab -v -P test -L -t 80', + 'test-html': 'lab -v -P test -L -t 80 -r html > testcov.html', + 'lint': 'lab -P test -dL' + }, + 'devDependencies': { + 'code': '1.5.0', + 'eslint-config-seneca': '1.1.2', + 'eslint-plugin-standard': '1.3.1', + 'joi': '6.10.x', + 'lab': '6.2.x' + }, + 'gitHead': '61371232af57ee37c573cfc114096088def6f478', + 'bugs': { + 'url': 'https://github.com/senecajs/seneca-entity/issues' + }, + '_id': 'seneca-entity@0.0.1', + '_shasum': '184d2251666938639364256836e6d16db2f8f729', + '_from': '.', + '_npmVersion': '3.3.12', + '_nodeVersion': '5.4.1', + '_npmUser': { + 'name': 'wyatt', + 'email': 'wpreul@gmail.com' + }, + 'dist': { + 'shasum': '184d2251666938639364256836e6d16db2f8f729', + 'tarball': 'https://registry.npmjs.org/seneca-entity/-/seneca-entity-0.0.1.tgz' + }, + 'maintainers': [ + { + 'name': 'wyatt', + 'email': 'wpreul@gmail.com' + } + ], + '_npmOperationalInternal': { + 'host': 'packages-5-east.internal.npmjs.com', + 'tmp': 'tmp/seneca-entity-0.0.1.tgz_1455650942742_0.4798124579247087' + }, + 'directories': {} + } + }, + 'readme': '# seneca-entity\nEntity plugin for seneca\n', + 'maintainers': [ + { + 'name': 'rjrodger', + 'email': 'richard.rodger@nearform.com' + }, + { + 'name': 'wyatt', + 'email': 'wpreul@gmail.com' + } + ], + 'time': { + 'modified': '2016-03-07T21:07:05.021Z', + 'created': '2016-02-16T18:49:09.329Z', + '0.0.0': '2016-02-16T18:49:09.329Z', + '0.0.1': '2016-02-16T19:29:05.114Z' + }, + 'homepage': 'http://senecajs.org', + 'keywords': [ + 'seneca', + 'plugin' + ], + 'repository': { + 'type': 'git', + 'url': 'git+https://github.com/senecajs/seneca-entity.git' + }, + 'author': { + 'name': 'Richard Rodger', + 'url': 'http://richardrodger.com/' + }, + 'bugs': { + 'url': 'https://github.com/senecajs/seneca-entity/issues' + }, + 'license': 'MIT' +}