diff --git a/.travis.yml b/.travis.yml
index 26f56aa3..6b6bad91 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,24 +1,21 @@
sudo: false
language: node_js
node_js:
- - '6'
- - '5'
- - '4'
-
+- '11'
+- '10'
+- '8'
cache:
directories:
- - node_modules
+ - node_modules
before_install: npm install -g npm@latest
before_script:
- - npm run lint
- # - npm run build # will need this when we do sauce testing of compiled files
+- npm run lint
script:
- - npm run test-coverage
- # - npm run test-dist # test the compiled files
+- npm run test-coverage
after_success:
- - npm run codecov
+- npm run codecov
before_deploy:
- - npm run build
+- npm run build
deploy:
provider: npm
skip_cleanup: true
@@ -26,4 +23,4 @@ deploy:
tags: true
email: clayreimann@gmail.com
api_key:
- secure: TZHqJ9Kh2Qf0GAVDjEOQ01Ez6rGMYHKwVLOKTbnb7nSzF7iiGNT4UwzvYawm0T9p1k7X1WOqW3l7OEbIwoKl7/9azT4BBJm7qUMRfB9Zio5cL3rKubJVz7+LEEIW4iBeDWLanhUDgy9BO2JKCt8bfp/U2tltgXtu9Fm/UFPALI8=
+ secure: WnLh1m02aF7NvFNILCZ8KsjPuDeSddQI87y8dwAixStr2FhQyz8FIKZN2Qj1N1Q9ZJvBETe5HWs1c9yOjTKBkD0d/eU2hlpnB9WXEFRJVDjiUuMnpAMMvuqTZwYg6kXq5N+of95PX58AYiBiV/qwsdUr/MgjEEYLt5UZgRYQRvE=
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..09827eb1
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,76 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity and expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at . All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
diff --git a/README.md b/README.md
index 919b5eb3..5e5f527f 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
+# Maintainers wanted
+[Apply within](https://github.com/github-tools/github/issues/539)
+
# Github.js
[][npm-package]
@@ -6,7 +9,7 @@
[][travis-ci]
[][codecov]
-Github.js provides a minimal higher-level wrapper around Github's API.
+`Github.js` provides a minimal higher-level wrapper around Github's API.
## Usage
@@ -68,7 +71,7 @@ clayreimann.listStarredRepos(function(err, repos) {
should include updated JSDoc.
## Installation
-Github.js is available from `npm` or [unpkg][unpkg].
+`Github.js` is available from `npm` or [unpkg][unpkg].
```shell
npm install github-api
@@ -83,10 +86,7 @@ npm install github-api
```
## Compatibility
-`Github.js` is tested on Node.js:
-* 6.x
-
-Note: `Github.js` uses Promise, hence it will not work in Node.js < 4 without polyfill.
+`Github.js` is tested on node's LTS and current versions.
[codecov]: https://codecov.io/github/github-tools/github?branch=master
[docs]: http://github-tools.github.io/github/
@@ -94,3 +94,33 @@ Note: `Github.js` uses Promise, hence it will not work in Node.js < 4 without po
[npm-package]: https://www.npmjs.com/package/github-api/
[unpkg]: https://unpkg.com/github-api/
[travis-ci]: https://travis-ci.org/github-tools/github
+
+## Contributing
+
+We welcome contributions of all types! This section will guide you through setting up your development environment.
+
+### Setup
+
+1. [Install Node](https://nodejs.org/en/) version 8,10 or 11. It can often help to use a Node version switcher such as [NVM](https://github.com/nvm-sh/nvm).
+2. Fork this repo to your GitHub account.
+3. Clone the fork to your development machine (`git clone https://github.com/{YOUR_USERNAME}/github`).
+4. From the root of the cloned repo, run `npm install`.
+5. Email jaredrewerts@gmail.com with the subject **GitHub API - Personal Access Token Request**
+
+A personal access token for our test user, @github-tools-test, will be generated for you.
+
+6. Set the environment variable `GHTOOLS_USER` to `github-tools-test`.
+
+`export GHTOOLS_USER=github-tools-test`
+
+7. Set the environment variable `GHTOOLS_PASSWORD` to the personal access token that was generated for you.
+
+`export GHTOOLS_PASSWORD={YOUR_PAT}`
+
+**NOTE** Windows users can use [this guide](http://www.dowdandassociates.com/blog/content/howto-set-an-environment-variable-in-windows-command-line-and-registry/) to learn about setting environment variables on Windows.
+
+### Tests
+
+The main way we write code for `github-api` is using test-driven development. We use Mocha to run our tests. Given that the bulk of this library is just interacting with GitHub's API, nearly all of our tests are integration tests.
+
+To run the test suite, run `npm run test`.
diff --git a/lib/GitHub.js b/lib/GitHub.js
index 59cb94ff..7c3ac24c 100644
--- a/lib/GitHub.js
+++ b/lib/GitHub.js
@@ -34,7 +34,7 @@ class GitHub {
/**
* Create a new Gist wrapper
- * @param {number} [id] - the id for the gist, leave undefined when creating a new gist
+ * @param {string} [id] - the id for the gist, leave undefined when creating a new gist
* @return {Gist}
*/
getGist(id) {
@@ -71,7 +71,7 @@ class GitHub {
/**
* Create a new Repository wrapper
- * @param {string} user - the user who owns the respository
+ * @param {string} user - the user who owns the repository
* @param {string} repo - the name of the repository
* @return {Repository}
*/
@@ -81,7 +81,7 @@ class GitHub {
/**
* Create a new Issue wrapper
- * @param {string} user - the user who owns the respository
+ * @param {string} user - the user who owns the repository
* @param {string} repo - the name of the repository
* @return {Issue}
*/
@@ -117,7 +117,7 @@ class GitHub {
/**
* Create a new Project wrapper
* @param {string} id - the id of the project
- * @return {Markdown}
+ * @return {Project}
*/
getProject(id) {
return new Project(id, this.__auth, this.__apiBase);
diff --git a/lib/Markdown.js b/lib/Markdown.js
index edc346cc..ebfbb512 100644
--- a/lib/Markdown.js
+++ b/lib/Markdown.js
@@ -32,7 +32,7 @@ class Markdown extends Requestable {
* @return {Promise} - the promise for the http request
*/
render(options, cb) {
- return this._request('POST', '/markdown', options, cb);
+ return this._request('POST', '/markdown', options, cb, true);
}
}
diff --git a/lib/Repository.js b/lib/Repository.js
index fb200397..74452dde 100644
--- a/lib/Repository.js
+++ b/lib/Repository.js
@@ -14,7 +14,7 @@ import debug from 'debug';
const log = debug('github:repository');
/**
- * Respository encapsulates the functionality to create, query, and modify files.
+ * Repository encapsulates the functionality to create, query, and modify files.
*/
class Repository extends Requestable {
/**
@@ -188,13 +188,33 @@ class Repository extends Requestable {
*/
listCommits(options, cb) {
options = options || {};
-
+ if (typeof options === 'function') {
+ cb = options;
+ options = {};
+ }
options.since = this._dateToISO(options.since);
options.until = this._dateToISO(options.until);
return this._request('GET', `/repos/${this.__fullname}/commits`, options, cb);
}
+ /**
+ * List the commits on a pull request
+ * @see https://developer.github.com/v3/repos/commits/#list-commits-on-a-repository
+ * @param {number|string} number - the number of the pull request to list the commits
+ * @param {Object} [options] - the filtering options for commits
+ * @param {Requestable.callback} [cb] - will receive the commits information
+ * @return {Promise} - the promise for the http request
+ */
+ listCommitsOnPR(number, options, cb) {
+ options = options || {};
+ if (typeof options === 'function') {
+ cb = options;
+ options = {};
+ }
+ return this._request('GET', `/repos/${this.__fullname}/pulls/${number}/commits`, options, cb);
+ }
+
/**
* Gets a single commit information for a repository
* @see https://developer.github.com/v3/repos/commits/#get-a-single-commit
@@ -231,6 +251,17 @@ class Repository extends Requestable {
return this._request('GET', `/repos/${this.__fullname}/commits/${sha}/statuses`, null, cb);
}
+ /**
+ * Get the combined view of commit statuses for a particular sha, branch, or tag
+ * @see https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref
+ * @param {string} sha - the sha, branch, or tag to get the combined status for
+ * @param {Requestable.callback} cb - will receive the combined status
+ * @returns {Promise} - the promise for the http request
+ */
+ getCombinedStatus(sha, cb) {
+ return this._request('GET', `/repos/${this.__fullname}/commits/${sha}/status`, null, cb);
+ }
+
/**
* Get a description of a git tree
* @see https://developer.github.com/v3/git/trees/#get-a-tree
@@ -334,16 +365,26 @@ class Repository extends Requestable {
* @param {string} parent - the SHA of the parent commit
* @param {string} tree - the SHA of the tree for this commit
* @param {string} message - the commit message
+ * @param {Object} [options] - commit options
+ * @param {Object} [options.author] - the author of the commit
+ * @param {Object} [options.commiter] - the committer
* @param {Requestable.callback} cb - will receive the commit that is created
* @return {Promise} - the promise for the http request
*/
- commit(parent, tree, message, cb) {
+ commit(parent, tree, message, options, cb) {
+ if (typeof options === 'function') {
+ cb = options;
+ options = {};
+ }
+
let data = {
message,
tree,
parents: [parent],
};
+ data = Object.assign({}, options, data);
+
return this._request('POST', `/repos/${this.__fullname}/git/commits`, data, cb)
.then((response) => {
this.__currentTree.sha = response.data.sha; // Update latest commit
@@ -494,6 +535,18 @@ class Repository extends Requestable {
return this._request('POST', `/repos/${this.__fullname}/forks`, null, cb);
}
+ /**
+ * Fork a repository to an organization
+ * @see https://developer.github.com/v3/repos/forks/#create-a-fork
+ * @param {String} org - organization where you'd like to create the fork.
+ * @param {Requestable.callback} cb - will receive the information about the newly created fork
+ * @return {Promise} - the promise for the http request
+ *
+ */
+ forkToOrg(org, cb) {
+ return this._request('POST', `/repos/${this.__fullname}/forks?organization=${org}`, null, cb);
+ }
+
/**
* List a repository's forks
* @see https://developer.github.com/v3/repos/forks/#list-forks
@@ -603,7 +656,7 @@ class Repository extends Requestable {
* @return {Promise} - the promise for the http request
*/
deleteHook(id, cb) {
- return this._request('DELETE', `${this.__fullname}/hooks/${id}`, null, cb);
+ return this._request('DELETE', `/repos/${this.__fullname}/hooks/${id}`, null, cb);
}
/**
@@ -713,6 +766,7 @@ class Repository extends Requestable {
* @return {Promise} - the promise for the http request
*/
writeFile(branch, path, content, message, options, cb) {
+ options = options || {};
if (typeof options === 'function') {
cb = options;
options = {};
diff --git a/lib/Requestable.js b/lib/Requestable.js
index bad111ac..4d6e8d9d 100644
--- a/lib/Requestable.js
+++ b/lib/Requestable.js
@@ -124,7 +124,7 @@ class Requestable {
/**
* if a `Date` is passed to this function it will be converted to an ISO string
- * @param {*} date - the object to attempt to cooerce into an ISO date string
+ * @param {*} date - the object to attempt to coerce into an ISO date string
* @return {string} - the ISO representation of `date` or whatever was passed in if it was not a date
*/
_dateToISO(date) {
@@ -235,7 +235,7 @@ 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.
+ * @param {Object[]} results - the partial results. This argument is intended for internal 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.
*/
@@ -256,9 +256,20 @@ 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);
+ if(nextUrl) {
+ if (!options) {
+ options = {};
+ }
+ options.page = parseInt(
+ nextUrl.match(/([&\?]page=[0-9]*)/g)
+ .shift()
+ .split('=')
+ .pop()
+ );
+ if (!(options && typeof options.page !== 'number')) {
+ log(`getting next page: ${nextUrl}`);
+ return this._requestAllPages(nextUrl, options, cb, results);
+ }
}
if (cb) {
diff --git a/lib/User.js b/lib/User.js
index 3f3b4bb6..a6f22324 100644
--- a/lib/User.js
+++ b/lib/User.js
@@ -81,6 +81,26 @@ class User extends Requestable {
return this._request('GET', this.__getScopedUrl('orgs'), null, cb);
}
+ /**
+ * List followers of a user
+ * @see https://developer.github.com/v3/users/followers/#list-followers-of-a-user
+ * @param {Requestable.callback} [cb] - will receive the list of followers
+ * @return {Promise} - the promise for the http request
+ */
+ listFollowers(cb) {
+ return this._request('GET', this.__getScopedUrl('followers'), null, cb);
+ }
+
+ /**
+ * Lists the people who the authenticated user follows.
+ * @see https://docs.github.com/en/rest/reference/users#list-the-people-the-authenticated-user-follows
+ * @param {Requestable.callback} [cb] - will receive the list of who a user is following
+ * @return {Promise} - the promise for the http request
+ */
+ listFollowing(cb) {
+ return this._request('GET', this.__getScopedUrl('following'), null, cb);
+ }
+
/**
* List the user's gists
* @see https://developer.github.com/v3/gists/#list-a-users-gists
@@ -132,6 +152,23 @@ class User extends Requestable {
return this._requestAllPages(this.__getScopedUrl('starred'), requestOptions, cb);
}
+ /**
+ * Gets the list of starred gists for the user
+ * @see https://developer.github.com/v3/gists/#list-starred-gists
+ * @param {Object} [options={}] - any options to refine the search
+ * @param {Requestable.callback} [cb] - will receive the list of gists
+ * @return {Promise} - the promise for the http request
+ */
+ listStarredGists(options, cb) {
+ options = options || {};
+ if (typeof options === 'function') {
+ cb = options;
+ options = {};
+ }
+ options.since = this._dateToISO(options.since);
+ return this._request('GET', '/gists/starred', options, cb);
+ }
+
/**
* List email addresses for a user
* @see https://developer.github.com/v3/users/emails/#list-email-addresses-for-a-user
@@ -150,7 +187,7 @@ class User extends Requestable {
* @return {Promise} - the promise for the http request
*/
follow(username, cb) {
- return this._request('PUT', `/user/following/${this.__user}`, null, cb);
+ return this._request('PUT', `/user/following/${username}`, null, cb);
}
/**
@@ -161,7 +198,7 @@ class User extends Requestable {
* @return {Promise} - the promise for the http request
*/
unfollow(username, cb) {
- return this._request('DELETE', `/user/following/${this.__user}`, null, cb);
+ return this._request('DELETE', `/user/following/${username}`, null, cb);
}
/**
diff --git a/mocha.opts b/mocha.opts
index 4944011d..0377ab2e 100644
--- a/mocha.opts
+++ b/mocha.opts
@@ -1,3 +1,3 @@
--compilers js:babel-register
---timeout 15000
+--timeout 20000
--slow 5000
diff --git a/package.json b/package.json
index 2ea2eb9a..8e54341a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "github-api",
- "version": "3.1.0",
+ "version": "3.4.0",
"license": "BSD-3-Clause-Clear",
"description": "A higher-level wrapper around the Github API.",
"main": "dist/components/GitHub.js",
@@ -52,7 +52,7 @@
"dist/*"
],
"dependencies": {
- "axios": "^0.15.2",
+ "axios": "^0.21.1",
"debug": "^2.2.0",
"js-base64": "^2.1.9",
"utf8": "^2.1.1"
diff --git a/test/auth.spec.js b/test/auth.spec.js
index bd0d8205..00842ee9 100644
--- a/test/auth.spec.js
+++ b/test/auth.spec.js
@@ -1,7 +1,7 @@
import expect from 'must';
import Github from '../lib/GitHub';
-import testUser from './fixtures/user.json';
+import testUser from './fixtures/user.js';
import {assertSuccessful, assertFailure} from './helpers/callbacks';
describe('Github', function() {
@@ -84,7 +84,7 @@ describe('Github', function() {
it('should fail authentication and return err', function(done) {
user.listNotifications(assertFailure(done, function(err) {
expect(err.response.status).to.be.equal(401, 'Return 401 status for bad auth');
- expect(err.response.data.message).to.equal('Bad credentials');
+ expect(err.response.data.message).to.equal('Requires authentication');
done();
}));
diff --git a/test/dist.spec/index.html b/test/dist.spec/index.html
index da5a21de..b0a32d7b 100644
--- a/test/dist.spec/index.html
+++ b/test/dist.spec/index.html
@@ -12,7 +12,7 @@