Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Redesign to align with GitHub's conventions #41

Open
wants to merge 53 commits into
base: master
Choose a base branch
from

Conversation

philschatz
Copy link
Owner

This code change leverages the URL patterns GitHub provides and converts the returned JSON into objects which allows nifty daisy-chaining.

Overview

This library closely mirrors the https://developer.github.com/v3 documentation.

For example, GET /repos/:owner/:repo becomes octo.repos(owner, repo).fetch() and POST /repos/:owner/:repo/issues/:number/comments becomes octo.repos(owner, repo).issues(number).comments.create(params).

Promises and Callbacks

This library supports NodeJS-style callbacks as well as Promises.

To use a callback, just specify it as the last argument to a method.
To use a Promise, do not specify a callback and the return value will be a Promise.

Example (get information on a repo):

# Using callbacks
octo.repo('philschatz', 'octokit.js').fetch (err, repo) ->
  console.error(err) if err
  # Do fancy stuff...


# Using Promises
octo.repo('philschatz', 'octokit.js').fetch()
.then (repo) ->
  # Do fancy stuff
.then null, (err) -> console.error(err)

Chaining

You construct the URL by chaining properties and methods together and an async call is made once a verb method is called (see below).

Example:

octo = new Octokit()
repo = octo.repos('philschatz', 'octokit.js')
# Check if the current user is a collaborator on a repo
repo.collaborators.contains(USER)
.then (isCollaborator) ->
  # If not, then star the Repo
  unless isCollaborator
    repo.star.add()
    .then () ->
      # Done!

Or, update a specific comment:

octo = new Octokit(token: ...)
octo.repos('philschatz', 'octokit.js').issues(1).comments(123123).update(body: 'Hello')
.then () ->
  # Done!

The basic structure of these methods is:

  • .foos.fetch({optionalStuff:...}) yields a list of items (possibly paginated)
  • .foos(id).fetch(...) yields a single item (issue, repo, user)
  • .foos.contains(id) tests membership in a list (yields true/false)
  • .foos.create(...) creates a new foo
  • .foos(id).add() adds an existing User/Repo to the list
  • .foos(id).remove() removes a member from a list or deletes the object and yields a boolean indicating success

JSON with methods (Hypermedia)

GitHub provides URL patterns in its JSON responses. These are automatically converted into methods.
For example:

octo.repo('philschatz', 'octokit.js').fetch()
.then (repo) ->
  # GitHub returns a JSON which contains something like compare_url: 'https://..../compare/{head}...{base}
  # This is converted to a method that accepts 2 arguments
  repo.compare(sha1, sha2).fetch()
  .then (comparison) -> # Done!

Paged Results

If a .fetch() returns paged results then nextPage(), previousPage(), firstPage() and lastPage() are added to the returned JSON. For example:

octo.repos('philschatz', 'octokit.js').commits.fetch()
.then (someCommits) ->
  someCommits.nextPage()
  .then (moreCommits) ->
    # Done!

Development

The unit tests are named to illustrate examples of using the API. See travis tests or run npm test to see them.

linkedin/sepia is used to generate recorded results from GitHub and philschatz/sepia.js uses them in the browser. If you are adding tests be sure to include the updated fixtures in the Pull Request.

Overview of Features

  • Convert URL templates to methods Hypermedia
  • Pagination
  • Rate Limiting listeners
  • Conditional Requests (ETags)
  • Tests run on Node and in the browser (using PhantomJS)

Implemented GitHub APIs:

  • Gists: 100%
  • Git Data: 100%
  • Issues: 100%
  • Orgs: 100%
  • Pull Requests: 100%
  • Repos: 100%
  • Users: 100%
  • Events: 100%
  • Search: 100%
  • Misc: 100%

Examples

Here are some examples of code you can write with this library

Global

  • octo.zen.fetch()
  • octo.users.fetch({since})
  • octo.gists.fetch({since})
  • octo.events.fetch({since})
  • octo.notifications.fetch({...})

Search

  • octo.search.repos.fetch({q,sort,order})
  • octo.search.code.fetch({q,sort,order})
  • octo.search.issues.fetch({q,sort,order})
  • octo.search.users.fetch({q,sort,order})

User

  • octo.users(name).fetch()
  • octo.users(name).repos({type,sort,direction})
  • octo.users(name).orgs.fetch()
  • octo.users(name).gists.fetch()
  • octo.users(name).followers.fetch()
  • octo.users(name).following.fetch()
  • octo.users(name).following.contains(name)
  • octo.users(name).keys.fetch()
  • octo.users(name).receivedEvents.fetch({onlyPublic})
  • octo.users(name).events.fetch({onlyPublic})

Me

  • octo.me.fetch()
  • octo.me.update({...})
  • octo.me.repos.fetch({type,sort,direction})
  • octo.me.orgs.fetch()
  • octo.me.followers.fetch()
  • octo.me.following.fetch()
  • octo.me.following.contains(name)
  • octo.me.following(name).add()
  • octo.me.following(name).remove()
  • octo.me.emails.fetch()
  • octo.me.emails.add(emails)
  • octo.me.emails.remove(emails)
  • octo.me.keys.fetch()
  • octo.me.keys.add()
  • octo.me.keys(id).remove()
  • octo.me.key(id).fetch()

Org

  • octo.orgs(name).fetch()
  • octo.orgs(name).update({...})
  • octo.orgs(name).teams.fetch()
  • octo.orgs(name).teams.create({name,repoNames,permission})
  • octo.orgs(name).members.fetch()
  • octo.orgs(name).members.contains(name)
  • octo.orgs(name).members(name).remove()
  • octo.orgs(name).repos.fetch()
  • octo.orgs(name).repos.create(name, {...})

Team

  • octo.teams(id).fetch()
  • octo.teams(id).update({...})
  • octo.teams(id).remove()
  • octo.teams(id).members.fetch()
  • octo.teams(id).members.contains(name)
  • octo.teams(id).members(name).add()
  • octo.teams(id).members(name).remove()
  • octo.teams(id).repos.fetch()
  • octo.teams(id).repos(owner, name).add()
  • octo.teams(id).repos(owner, name).remove()

Repo

  • octo.repos(owner, name).fetch()
  • octo.repos(owner, name).remove()
  • octo.repos(owner, name).update({...})
  • octo.repos(owner, name).readme.fetch()
  • octo.repos(owner, name).forks.create({organization})
  • octo.repos(owner, name).pullRequests.create({...})
  • octo.repos(owner, name).events.fetch()
  • octo.repos(owner, name).issues.events.fetch()
  • octo.repos(owner, name).notifications.fetch({since,...})
  • octo.repos(owner, name).collaborators.fetch()
  • octo.repos(owner, name).collaborators.contains(name)
  • octo.repos(owner, name).collaborators(name).add()
  • octo.repos(owner, name).collaborators(name).remove()
  • octo.repos(owner, name).hooks.fetch()
  • octo.repos(owner, name).hooks.create({name,config,events,active})
  • octo.repos(owner, name).hooks.remove(id)
  • octo.repos(owner, name).hooks(id).fetch()
  • octo.repos(owner, name).hooks(id).update({...}) # un-camelize
  • octo.repos(owner, name).hooks(id).tests.create()
  • octo.repos(owner, name).languages.fetch()
  • octo.repos(owner, name).releases.fetch()
  • octo.repos(owner, name).contents(path, sha?).fetch()
  • octo.repos(owner, name).contents(path, sha).remove(message, branch)
  • octo.networks(owner, name).events.fetch()

Git

  • octo.repos(owner, name).git.refs.create({...})
  • octo.repos(owner, name).git.refs(ref).remove()
  • octo.repos(owner, name).git.refs(ref).fetch()
  • octo.repos(owner, name).git.refs.heads.create()
  • octo.repos(owner, name).git.refs.heads.fetch()
  • octo.repos(owner, name).git.refs.heads(name).update({sha,force})
  • octo.repos(owner, name).git.refs.heads(name).remove()
  • octo.repos(owner, name).git.blobs.create({...})
  • octo.repos(owner, name).git.blobs(sha).fetch()
  • octo.repos(owner, name).git.trees.create({...})
  • octo.repos(owner, name).git.trees(id).fetch({...})
  • octo.repos(owner, name).git.trees(id).update(newTrees)
  • octo.repos(owner, name).git.commits.fetch({...})
  • octo.repos(owner, name).git.commits.create({parents,tree,message})
  • octo.repos(owner, name).git.commit(sha).fetch()

Gists

  • octo.gists.fetch()
  • octo.gists.create({...})
  • octo.gists(id).fetch()
  • octo.gists(id).update({...})
  • octo.gists(id).remove()
  • octo.gists(id).forks.create()
  • octo.gists(id).star.contains(USERNAME)
  • octo.gists(id).star.add()
  • octo.gists(id).star.remove()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant