diff --git a/lib/GitHub.js b/lib/GitHub.js index 944fc868..29645c7e 100644 --- a/lib/GitHub.js +++ b/lib/GitHub.js @@ -15,6 +15,7 @@ import Repository from './Repository'; import Organization from './Organization'; import Team from './Team'; import Markdown from './Markdown'; +import Watching from './Watching'; /** * GitHub encapsulates the functionality to create various API wrapper objects. @@ -113,6 +114,14 @@ class GitHub { return new Markdown(this.__auth, this.__apiBase); } + /** + * Create a new Watching wrapper + * @return {Watching} + */ + watching() { + return new Watching(this.__auth, this.__apiBase); + } + /** * Computes the full repository name * @param {string} user - the username (or the full name) diff --git a/lib/Watching.js b/lib/Watching.js new file mode 100644 index 00000000..ae7b9a4e --- /dev/null +++ b/lib/Watching.js @@ -0,0 +1,95 @@ +/** + * @file + * @copyright 2016 Matt Smith (Development Seed) + * @license Licensed under {@link https://spdx.org/licenses/BSD-3-Clause-Clear.html BSD-3-Clause-Clear}. + * Github.js is freely distributable. + */ + +import Requestable from './Requestable'; +import debug from 'debug'; +const log = debug('github:watching'); + +/** + * Watching a Repository registers the user to receive notifications on new discussions, as well as events in the user's + * activity feed. + */ +export default class Watching extends Requestable { + /** + * Watching wrapper + * @param {Requestable.auth} [auth] - information required to authenticate to Github + * @param {string} [apiBase=https://api.github.com] - the base Github API URL + */ + constructor(auth, apiBase) { + super(auth, apiBase); + } + + /** + * Get Watchers for repo + * @see https://developer.github.com/v3/activity/watching/#list-watchers + * @param {string} owner - username or organization + * @param {string} repo - repo name + * @param {Requestable.callback} [cb] - list of watchers + * @return {Promise} - the promise for the http request + */ + listWatchers(owner, repo, cb) { + log(`Fetching watchers for ${owner}/${repo}`); + return this._requestAllPages(`/repos/${owner}/${repo}/subscribers`, undefined, cb); + } + + /** + * Subscribe to repo + * @see https://developer.github.com/v3/activity/watching/#set-a-repository-subscription + * @param {string} owner - username or organization + * @param {string} repo - repo name + * @param {Requestable.callback} [cb] - subscription status + * @return {Promise} - the promise for the http request + */ + subscribe(owner, repo, cb) { + log(`Subscribing to ${owner}/${repo}`); + return this._setSubscription(owner, repo, true, cb); + } + + /** + * Ignore a repo + * @see https://developer.github.com/v3/activity/watching/#set-a-repository-subscription + * @param {string} owner - username or organization + * @param {string} repo - repo name + * @param {Requestable.callback} [cb] - subscription status + * @return {Promise} - the promise for the http request + */ + ignore(owner, repo, cb) { + log(`Ignoring ${owner}/${repo}`); + return this._setSubscription(owner, repo, false, cb); + } + + /** + * Remove all subscription settings for repo + * @see https://developer.github.com/v3/activity/watching/#delete-a-repository-subscription + * @param {string} owner - username or organization + * @param {string} repo - repo name + * @param {Requestable.callback} [cb] - subscription status + * @return {Promise} - the promise for the http request + */ + removeSubscription(owner, repo, cb) { + log(`Removing subscription settings for ${owner}/${repo}`); + return this._request204or404(`/repos/${owner}/${repo}/subscription`, undefined, cb, 'DELETE'); + } + + /** + * General subscription method + * @private + * @see https://developer.github.com/v3/activity/watching/#set-a-repository-subscription + * @param {string} owner - username or organization + * @param {string} repo - repo name + * @param {boolean} subscribed - subscribed or ignored + * @param {Requestable.callback} [cb] - subscription status + * @return {Promise} - the promise for the http request + */ + _setSubscription(owner, repo, subscribed, cb) { + log(`Subscribing to ${owner}/${repo}`); + return this._request('PUT', `/repos/${owner}/${repo}/subscription`, { + subscribed, + ignored: !subscribed + }, cb); + } +} diff --git a/test/fixtures/alt-user.json b/test/fixtures/alt-user.json new file mode 100644 index 00000000..20cfd701 --- /dev/null +++ b/test/fixtures/alt-user.json @@ -0,0 +1,4 @@ +{ + "USERNAME": "mtscout6-test", + "PASSWORD": "test1324" +} diff --git a/test/team.spec.js b/test/team.spec.js index 1f712617..ce0cef5c 100644 --- a/test/team.spec.js +++ b/test/team.spec.js @@ -2,13 +2,10 @@ import expect from 'must'; import Github from '../lib/GitHub'; import testUser from './fixtures/user.json'; +import altUser from './fixtures/alt-user.json'; import {assertFailure} from './helpers/callbacks'; import getTestRepoName from './helpers/getTestRepoName'; -const altUser = { - USERNAME: 'mtscout6-test' -}; - function createTestTeam() { const name = getTestRepoName(); diff --git a/test/watching.spec.js b/test/watching.spec.js new file mode 100644 index 00000000..2a04b927 --- /dev/null +++ b/test/watching.spec.js @@ -0,0 +1,79 @@ +import expect from 'must'; + +import Github from '../lib/GitHub'; +import testUser from './fixtures/user.json'; +import altUser from './fixtures/alt-user.json'; +import getTestRepoName from './helpers/getTestRepoName'; + +describe('Watching', function() { + const testRepoName = getTestRepoName(); + let githubUser; + let githubAltUser; + let organization; + + before(function() { + githubUser = new Github({ + username: testUser.USERNAME, + password: testUser.PASSWORD, + auth: 'basic' + }); + + githubAltUser = new Github({ + username: altUser.USERNAME, + password: altUser.PASSWORD, + auth: 'basic' + }); + + organization = githubUser.getOrganization(testUser.ORGANIZATION); + + const options = { + name: testRepoName, + description: 'test repo watchers', + homepage: 'https://github.com/', + private: false, + has_issues: false, // eslint-disable-line + has_wiki: false, // eslint-disable-line + has_downloads: false // eslint-disable-line + }; + + return organization.createRepo(options); + }); + + it('should list watchers', function() { + return githubUser.watching() + .listWatchers(testUser.ORGANIZATION, 'fixed-test-repo-1') + .then(({data}) => { + const watchers = data.map((x) => x.login); + expect(watchers).must.include('mikedeboertest'); + }); + }); + + it('should add a subscription to a repo', function() { + const watching = githubAltUser.watching(); + + return watching.subscribe(testUser.ORGANIZATION, testRepoName) + .then(({data}) => { + expect(data.subscribed).to.be.true(); + expect(data.ignored).to.be.false(); + }); + }); + + it('should ignore a repo', function() { + const watching = githubAltUser.watching(); + + return watching.ignore(testUser.ORGANIZATION, testRepoName) + .then(({data}) => { + expect(data.subscribed).to.be.false(); + expect(data.ignored).to.be.true(); + }); + }); + + it('should remove subscription settings', function() { + const watching = githubAltUser.watching(); + + return watching.removeSubscription(testUser.ORGANIZATION, testRepoName) + .then((result) => { + expect(result).to.be.true(); + }); + }); +});