diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 2718e64e..3eb49f5a 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -2,6 +2,7 @@ extends: - eslint:recommended - google + parser: babel-eslint parserOptions: ecmaVersion: 6 sourceType: module @@ -25,7 +26,6 @@ MethodDefinition: true spaced-comment: error valid-jsdoc: [error, {requireParamDescription: true}] - env: es6: true node: true diff --git a/.gitignore b/.gitignore index db3cda2f..8917815d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ node_modules/ .DS_Store npm-debug.log sauce.json +package-lock.json diff --git a/.npmignore b/.npmignore index fe969272..e533e1f5 100644 --- a/.npmignore +++ b/.npmignore @@ -5,3 +5,4 @@ lib/ .nyc_output/ .DS_Store sauce.json +package-lock.json diff --git a/.travis.yml b/.travis.yml index 26f56aa3..817aa70f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,8 @@ sudo: false language: node_js node_js: + - '8' - '6' - - '5' - - '4' cache: directories: diff --git a/lib/Repository.js b/lib/Repository.js index d338b261..fbd1db7c 100644 --- a/lib/Repository.js +++ b/lib/Repository.js @@ -436,13 +436,27 @@ class Repository extends Requestable { * List the users who are collaborators on the repository. The currently authenticated user must have * push access to use this method * @see https://developer.github.com/v3/repos/collaborators/#list-collaborators - * @param {Requestable.callback} cb - will receive the list of collaborators + * @param {Requestable.callback} cb - will receive the fetched data * @return {Promise} - the promise for the http request */ getCollaborators(cb) { return this._request('GET', `/repos/${this.__fullname}/collaborators`, null, cb); } + /** + * Adds user as a collaborator on the repository. The currently authenticated user must have admin access for the + * repo to use this method + * @see https://developer.github.com/enterprise/2.10/v3/repos/collaborators/#add-user-as-a-collaborator + * @param {string} username - the user to add as a collaborator + * @param {Object} [options] - collaborator permissions, only applicable on repos in an org + * @param {Object} [options.permission=push] - can be one of: `pull`, `push`, or `admin` + * @param {Requestable.callback} cb - will receive the information about the newly added contributor + * @return {Promise} - the promise for the http request + */ + addCollaborator(username, options, cb) { + return this._request('PUT', `/repos/${this.__fullname}/collaborators/${username}`, options, cb); + } + /** * Check if a user is a collaborator on the repository * @see https://developer.github.com/v3/repos/collaborators/#check-if-a-user-is-a-collaborator @@ -451,7 +465,7 @@ class Repository extends Requestable { * @return {Promise} - the promise for the http request {Boolean} [description] */ isCollaborator(username, cb) { - return this._request('GET', `/repos/${this.__fullname}/collaborators/${username}`, null, cb); + return this._request204or404(`/repos/${this.__fullname}/collaborators/${username}`, null, cb); } /** diff --git a/lib/Requestable.js b/lib/Requestable.js index bad111ac..09c0e47a 100644 --- a/lib/Requestable.js +++ b/lib/Requestable.js @@ -235,15 +235,18 @@ class Requestable { * @param {string} path - the path to request * @param {Object} options - the query parameters to include * @param {Requestable.callback} [cb] - the function to receive the data. The returned data will always be an array. - * @param {Object[]} results - the partial results. This argument is intended for interal use only. * @return {Promise} - a promise which will resolve when all pages have been fetched * @deprecated This will be folded into {@link Requestable#_request} in the 2.0 release. */ - _requestAllPages(path, options, cb, results) { - results = results || []; + async _requestAllPages(path, options, cb) { + let currentPath = path; + let results = []; + let response; + + try { + do { + response = await this._request('GET', currentPath, options); - return this._request('GET', path, options) - .then((response) => { let thisGroup; if (response.data instanceof Array) { thisGroup = response.data; @@ -255,19 +258,18 @@ class Requestable { } results.push(...thisGroup); - const nextUrl = getNextPage(response.headers.link); - if (nextUrl && typeof options.page !== 'number') { - log(`getting next page: ${nextUrl}`); - return this._requestAllPages(nextUrl, options, cb, results); - } + currentPath = getNextPage(response.headers.link); + } while(currentPath); - if (cb) { - cb(null, results, response); - } + if (cb) { + cb(null, results, response); + } - response.data = results; - return response; - }).catch(callbackErrorOrThrow(cb, path)); + response.data = results; + return response; + } catch (err) { + callbackErrorOrThrow(cb, path)(err); + } } } @@ -283,6 +285,7 @@ function methodHasNoBody(method) { function getNextPage(linksHeader = '') { const links = linksHeader.split(/\s*,\s*/); // splits and strips the urls + // TODO: Change this to early abort once it finds the link in question return links.reduce(function(nextUrl, link) { if (link.search(/rel="next"/) !== -1) { return (link.match(/<(.*)>/) || [])[1]; diff --git a/lib/Team.js b/lib/Team.js index f91c9173..67545ae6 100644 --- a/lib/Team.js +++ b/lib/Team.js @@ -90,8 +90,8 @@ class Team extends Requestable { /** * Add a member to the Team - * @see https://developer.github.com/v3/orgs/teams/#add-team-membership - * @param {string} username - can be one of: `all`, `maintainer`, or `member` + * @see https://developer.github.com/v3/orgs/teams/#add-or-update-team-membership + * @param {string} username - user to add or update membership for * @param {object} options - Parameters for adding a team member * @param {string} [options.role=member] - The role that this user should have in the team. Can be one * of: `member`, or `maintainer` diff --git a/package.json b/package.json index 2ea2eb9a..f60bf60a 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,14 @@ }, "babel": { "presets": [ - "es2015" + [ + "env", + { + "targets": { + "node": 6 + } + } + ] ], "plugins": [ [ @@ -59,9 +66,11 @@ }, "devDependencies": { "babel-core": "^6.7.7", + "babel-eslint": "^7.2.3", "babel-plugin-add-module-exports": "^0.2.1", "babel-plugin-istanbul": "3.0.0", "babel-plugin-transform-es2015-modules-umd": "^6.5.0", + "babel-preset-env": "^1.6.0", "babel-preset-es2015": "^6.5.0", "babel-register": "^6.7.2", "babelify": "^7.3.0", diff --git a/test/fixtures/alt-user.json b/test/fixtures/alt-user.json new file mode 100644 index 00000000..f39cb512 --- /dev/null +++ b/test/fixtures/alt-user.json @@ -0,0 +1,3 @@ +{ + "USERNAME": "mtscout6-test" +} diff --git a/test/organization.spec.js b/test/organization.spec.js index 26fd3607..01363e3d 100644 --- a/test/organization.spec.js +++ b/test/organization.spec.js @@ -21,7 +21,9 @@ describe('Organization', function() { }); after(function() { - return github.getProject(createdProject.id).deleteProject(); + if (createdProject) { + return github.getProject(createdProject.id).deleteProject(); + } }); describe('reading', function() { @@ -95,13 +97,10 @@ describe('Organization', function() { })); }); - it('should list the teams in the organization', function() { - return organization.getTeams() - .then(({data}) => { - const hasTeam = data.some((member) => member.slug === testRepoName); - - expect(hasTeam).to.be.true(); - }); + it('should list the teams in the organization', async function() { + const {data} = await organization.getTeams(); + const hasTeam = data.some((member) => member.slug === testRepoName); + expect(hasTeam).to.be.true(); }); it('should create a project', function(done) { diff --git a/test/rate-limit.spec.js b/test/rate-limit.spec.js index c3a5b858..40219fea 100644 --- a/test/rate-limit.spec.js +++ b/test/rate-limit.spec.js @@ -2,7 +2,6 @@ import expect from 'must'; import Github from '../lib/GitHub'; import testUser from './fixtures/user.json'; -import {assertSuccessful} from './helpers/callbacks'; describe('RateLimit', function() { let github; @@ -18,18 +17,15 @@ describe('RateLimit', function() { rateLimit = github.getRateLimit(); }); - it('should get rate limit', function(done) { - rateLimit.getRateLimit(assertSuccessful(done, function(err, rateInfo) { - const rate = rateInfo.rate; + it('should get rate limit', async function() { + const {data: rateInfo} = await rateLimit.getRateLimit(); + const rate = rateInfo.rate; - expect(rate).to.be.an.object(); - expect(rate).to.have.own('limit'); - expect(rate).to.have.own('remaining'); - expect(rate.limit).to.be.a.number(); - expect(rate.remaining).to.be.a.number(); - expect(rate.remaining).to.be.at.most(rateInfo.rate.limit); - - done(); - })); + expect(rate).to.be.an.object(); + expect(rate).to.have.own('limit'); + expect(rate).to.have.own('remaining'); + expect(rate.limit).to.be.a.number(); + expect(rate.remaining).to.be.a.number(); + expect(rate.remaining).to.be.at.most(rateInfo.rate.limit); }); }); diff --git a/test/repository.spec.js b/test/repository.spec.js index ef5101cf..739978e0 100644 --- a/test/repository.spec.js +++ b/test/repository.spec.js @@ -3,6 +3,7 @@ import expect from 'must'; import Github from '../lib/GitHub'; import wait from './helpers/wait'; import testUser from './fixtures/user.json'; +import altUser from './fixtures/alt-user.json'; import loadImage from './fixtures/imageBlob'; import {assertSuccessful, assertFailure} from './helpers/callbacks'; import getTestRepoName from './helpers/getTestRepoName'; @@ -343,8 +344,18 @@ describe('Repository', function() { })); }); - it('should test whether user is collaborator', function(done) { - remoteRepo.isCollaborator(testUser.USERNAME, assertSuccessful(done)); + it('should add repo collaborator', async function() { + expect(await remoteRepo.isCollaborator(altUser.USERNAME)).to.be.false; + await remoteRepo.addCollaborator(altUser.USERNAME); + expect(await remoteRepo.isCollaborator(altUser.USERNAME)).to.be.true; + }); + + it('should test whether user is collaborator', async function() { + expect(await remoteRepo.isCollaborator(testUser.USERNAME)).to.be.true; + }); + + it('should test whether user is not collaborator', async function() { + expect(await remoteRepo.isCollaborator(altUser.USERNAME)).to.be.false; }); it('should write to repo', function(done) { diff --git a/test/team.spec.js b/test/team.spec.js index 8a5ec8be..671418d5 100644 --- a/test/team.spec.js +++ b/test/team.spec.js @@ -1,13 +1,10 @@ +import assert from 'assert'; import expect from 'must'; import Github from '../lib/GitHub'; import testUser from './fixtures/user.json'; -import {assertFailure} from './helpers/callbacks'; import getTestRepoName from './helpers/getTestRepoName'; - -const altUser = { - USERNAME: 'mtscout6-test', -}; +import altUser from './fixtures/alt-user.json'; function createTestTeam() { const name = getTestRepoName(); @@ -145,9 +142,15 @@ describe('Team', function() { // Isolate tests that need a new team per test }); // Test for Team deletion - afterEach(function(done) { - team.deleteTeam() - .then(() => team.getTeam(assertFailure(done))); + afterEach(async function() { + await team.deleteTeam(); + + try { + await team.getTeam(); + assert.fail(undefined, undefined, 'Failed to delete the team'); + } catch (error) { + // Swallow intentionally + } }); it('should update team', function() { @@ -158,13 +161,11 @@ describe('Team', function() { // Isolate tests that need a new team per test }); }); - it('should add membership for a given user', function() { - return team.addMembership(testUser.USERNAME) - .then(({data}) => { - const {state, role} = data; - expect(state === 'active' || state === 'pending').to.be.true(); - expect(role).to.equal('member'); - }); + it('should add membership for a given user', async function() { + const {data: {state, role}} = await team.addMembership(testUser.USERNAME); + expect(state === 'active' || state === 'pending').to.be.true(); + // TODO: This does not appear to match the documentation... + expect(role).to.equal('maintainer'); }); it('should add membership as a maintainer for a given user', function() {
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: