• Stars
    star
    1,132
  • Rank 39,536 (Top 0.9 %)
  • Language
    Ruby
  • License
    MIT License
  • Created over 12 years ago
  • Updated 12 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Ruby interface to GitHub API
github api logo

GithubAPI Gitter

Gem Version Build Status Maintainability Coverage Status Inline docs

Website | Wiki | RDocs

A Ruby client for the official GitHub API.

Supports all the API methods. It's built in a modular way. You can either instantiate the whole API wrapper Github.new or use parts of it i.e. Github::Client::Repos.new if working solely with repositories is your main concern. Intuitive query methods allow you easily call API endpoints.

Features

  • Intuitive GitHub API interface navigation.
  • It's comprehensive. You can request all GitHub API resources.
  • Modular design allows for working with parts of API.
  • Fully customizable including advanced middleware stack construction.
  • Supports OAuth2 authorization.
  • Flexible argument parsing. You can write expressive and natural queries.
  • Requests pagination with convenient DSL and automatic options.
  • Easy error handling split for client and server type errors.
  • Supports multithreaded environment.
  • Custom media type specification through the 'media' parameter.
  • Request results caching
  • Fully tested with unit and feature tests hitting the live api.

Installation

Install the gem by running

gem install github_api

or put it in your Gemfile and run bundle install

gem "github_api"

Contents

1 Usage

To start using the gem, you can either perform requests directly on Github namespace:

Github.repos.list user: 'piotrmurach'

or create a new client instance like so

github = Github.new

and then call api methods, for instance, to list a given user repositories do

github.repos.list user: 'piotrmurach'

1.1 API Navigation

The github_api closely mirrors the GitHub API hierarchy. For example, if you want to create a new file in a repository, look up the GitHub API spec. In there you will find contents sub category underneath the repository category. This would translate to the request:

github = Github.new
github.repos.contents.create 'piotrmurach', 'finite_machine', 'hello.rb',
                             path: 'hello.rb',
                             content: "puts 'hello ruby'"

The whole library reflects the same api navigation. Therefore, if you need to list releases for a repository do:

github.repos.releases.list 'piotrmurach', 'finite_machine'

or to list a user's followers:

github.users.followers.list 'piotrmurach'

The code base has been extensively documented with examples of how to use each method. Please refer to the documentation under the Github::Client class name.

Alternatively, you can find out which methods are supported by an api by calling actions on a class or instance. For example, in order to find out available endpoints for Github::Client::Repos::Contents api call actions method:

Github::Client::Repos::Contents.actions
=> [:archive, :create, :delete, :find, :get, :readme, :update]

1.2 Modularity

The code base is modular. This means that you can work specifically with a given part of GitHub API. If you want to only work with activity starring API do the following:

starring = Github::Client::Activity::Starring.new oauth_token: token
starring.star 'piotrmurach', 'github'

Please refer to the documentation and look under Github::Client to see all available classes.

1.3 Arguments

The github_api library allows for flexible argument parsing.

Arguments can be passed directly inside the method called. The required arguments are passed in first, followed by optional parameters supplied as hash options:

issues = Github::Client::Issues.new
issues.milestones.list 'piotrmurach', 'github', state: 'open'

In the previous example, the order of arguments is important. However, each method also allows you to specify required arguments using hash symbols and thus remove the need for ordering. Therefore, the same example could be rewritten like so:

issues = Github::Client::Issues.new
issues.milestones.list user: 'piotrmurach', repo: 'github', state: 'open'

Furthermore, required arguments can be passed during instance creation:

issues = Github::Client::Issues.new user: 'piotrmurach', repo: 'github'
issues.milestones.list state: 'open'

Similarly, the required arguments for the request can be passed inside the current scope such as:

issues = Github::Client::Issues.new
issues.milestones(user: 'piotrmurach', repo: 'github').list state: 'open'

But why limit ourselves? You can mix and match arguments, for example:

issues = Github::Client::Issues.new user: 'piotrmurach'
issues.milestones(repo: 'github').list
issues.milestones(repo: 'tty').list

You can also use a bit of syntactic sugar whereby "username/repository" can be passed as well:

issues = Github::Client::Issues.new
issues.milestones('piotrmurach/github').list
issues.milestones.list 'piotrmurach/github'

Finally, use the with scope to clearly denote your requests

issues = Github::Client::Issues.new
issues.milestones.with(user: 'piotrmurach', repo: 'github').list

Please consult the method documentation or GitHub specification to see which arguments are required and what are the option parameters.

1.4 Response Querying

The response is of type Github::ResponseWrapper and allows traversing all the json response attributes like method calls. In addition, if the response returns more than one resource, these will be automatically yielded to the provided block one by one.

For example, when request is issued to list all the branches on a given repository, each branch will be yielded one by one:

repos = Github::Client::Repos.new
repos.branches user: 'piotrmurach', repo: 'github' do |branch|
  puts branch.name
end

1.4.1 Response Body

The ResponseWrapper allows you to call json attributes directly as method calls. there is no magic here, all calls are delegated to the response body. Therefore, you can directly inspect request body by calling body method on the ResponseWrapper like so:

response = repos.branches user: 'piotrmurach', repo: 'github'
response.body  # => Array of branches

1.4.2 Response Headers

Each response comes packaged with methods allowing for inspection of HTTP start line and headers. For example, to check for rate limits and status codes do:

response = Github::Client::Repos.branches 'piotrmurach', 'github'
response.headers.ratelimit_limit     # "5000"
response.headers.ratelimit_remaining # "4999"
response.headers.status              # "200"
response.headers.content_type        # "application/json; charset=utf-8"
response.headers.etag                # "\"2c5dfc54b3fe498779ef3a9ada9a0af9\""
response.headers.cache_control       # "public, max-age=60, s-maxage=60"

1.4.3 Response Success

If you want to verify if the response was success, namely, that the 200 code was returned call the success? like so:

response = Github::Client::Repos.branches 'piotrmurach', 'github'
response.success?  # => true

1.5 Request Headers

It is possible to specify additional header information which will be added to the final request.

For example, to set etag and X-Poll_Interval headers, use the :headers hash key inside the :options hash like in the following:

events = Github::Client::Activity::Events.new
events.public headers: {
    'X-Poll-Interval': 60,
    'ETag': "a18c3bded88eb5dbb5c849a489412bf3"
  }

1.5.1 Media Types

In order to set custom media types for a request use the accept header. By using the :accept key you can determine media type like in the example:

issues = Github::Client::Issues.new
issues.get 'piotrmurach', 'github', 108, accept: 'application/vnd.github.raw'

2 Configuration

The github_api provides ability to specify global configuration options. These options will be available to all api calls.

2.1 Basic

The configuration options can be set by using the configure helper

Github.configure do |c|
  c.basic_auth = "login:password"
  c.adapter    = :typheous
  c.user       = 'piotrmurach'
  c.repo       = 'finite_machine'
end

Alternatively, you can configure the settings by passing a block to an instance like:

Github.new do |c|
  c.endpoint    = 'https://github.company.com/api/v3'
  c.site        = 'https://github.company.com'
  c.upload_endpoint = 'https://github.company.com/api/uploads'
end

or simply by passing hash of options to an instance like so

github = Github.new basic_auth: 'login:password',
                    adapter: :typheous,
                    user: 'piotrmurach',
                    repo: 'finite_machine'

The following is the full list of available configuration options:

adapter            # Http client used for performing requests. Default :net_http
auto_pagination    # Automatically traverse requests page links. Default false
basic_auth         # Basic authentication in form login:password.
client_id          # Oauth client id.
client_secret      # Oauth client secret.
connection_options # Hash of connection options.
endpoint           # Enterprise API endpoint. Default: 'https://api.github.com'
oauth_token        # Oauth authorization token.
org                # Global organization used in requests if none provided
per_page           # Number of items per page. Max of 100. Default 30.
repo               # Global repository used in requests in none provided
site               # enterprise API web endpoint
ssl                # SSL settings in hash form.
user               # Global user used for requests if none provided
user_agent         # Custom user agent name. Default 'Github API Ruby Gem'

2.2 Advanced

The github_api will use the default middleware stack which is exposed by calling stack on a client instance. However, this stack can be freely modified with methods such as insert, insert_after, delete and swap. For instance, to add your CustomMiddleware do:

Github.configure do |c|
  c.stack.insert_after Github::Response::Helpers, CustomMiddleware
end

Furthermore, you can build your entire custom stack and specify other connection options such as adapter by doing:

Github.new do |c|
  c.adapter :excon

  c.stack do |builder|
    builder.use Github::Response::Helpers
    builder.use Github::Response::Jsonize
  end
end

2.3 SSL

By default requests over SSL are set to OpenSSL::SSL::VERIFY_PEER. However, you can turn off peer verification by

github = Github.new ssl: { verify: false }

If your client fails to find CA certs, you can pass other SSL options to specify exactly how the information is sourced

ssl: {
  client_cert: "/usr/local/www.example.com/client_cert.pem"
  client_key:  "/user/local/www.example.com/client_key.pem"
  ca_file:     "example.com.cert"
  ca_path:     "/etc/ssl/"
}

For instance, download CA root certificates from Mozilla cacert and point ca_file at your certificate bundle location. This will allow the client to verify the github.com ssl certificate as authentic.

2.4 Caching

Caching is supported through the faraday-http-cache gem.

Add the gem to your Gemfile:

gem 'faraday-http-cache'

You can now configure cache parameters as follows

Github.configure do |config|
  config.stack = proc do |builder|
    builder.use Faraday::HttpCache, store: Rails.cache
  end
end

More details on the available options can be found in the gem's own documentation: https://github.com/plataformatec/faraday-http-cache#faraday-http-cache

3 Authentication

3.1 Basic

To start making requests as authenticated user you can use your GitHub username and password like so

Github.new basic_auth: 'login:password'

Though this method is convenient you should strongly consider using OAuth for improved security reasons.

3.2 Authorizations API

3.2.1 For a User

To create an access token through the GitHub Authorizations API, you are required to pass your basic credentials and scopes you wish to have for the authentication token.

github = Github.new basic_auth: 'login:password'
github.auth.create scopes: ['repo'], note: 'admin script'

You can add more than one scope from the user, public_repo, repo, gist or leave the scopes parameter out, in which case, the default read-only access will be assumed (includes public user profile info, public repo info, and gists).

3.2.2 For an App

Furthermore, to create auth token for an application you need to pass :app argument together with :client_id and :client_secret parameters.

github = Github.new basic_auth: 'login:password'
github.auth.app.create 'client-id', scopes: ['repo']

In order to revoke auth token(s) for an application you must use basic authentication with client_id as login and client_secret as password.

github = Github.new basic_auth: "client_id:client_secret"
github.auth.app.delete 'client-id'

Revoke a specific app token.

github.auth.app.delete 'client-id', 'access-token'

3.3 Scopes

You can check OAuth scopes you have by:

github = Github.new oauth_token: 'token'
github.scopes.list    # => ['repo']

or inidividually for a given user:

github = Github.new
github.scopes.list 'token'

To list the scopes that the particular GitHub API action checks for do:

repos = Github::Client::Repos.new
response = repos.list user: 'piotrmurach'
response.headers.accepted_oauth_scopes  # => ['delete_repo', 'repo', 'public_repo']

To understand what each scope means refer to documentation

3.4 Application OAuth

In order to authenticate your app through OAuth2 on GitHub you need to

You can use convenience methods to help you achieve this using GithubAPI gem:

github = Github.new client_id: '...', client_secret: '...'
github.authorize_url redirect_uri: 'http://localhost', scope: 'repo'
# => "https://github.com/login/oauth/authorize?scope=repo&response_type=code&client_id='...'&redirect_uri=http%3A%2F%2Flocalhost"

After you get your authorization code, call to receive your access_token

token = github.get_token( authorization_code )

Once you have your access token, configure your github instance following instructions under Configuration.

Note: If you are working locally (i.e. your app URL and callback URL are localhost), do not specify a :redirect_uri otherwise you will get a redirect_uri_mismatch error.

3.5 Two-Factor

In order to use Two-Factor authentication you need provide X-GitHub-OTP: required; :2fa-type header.

You can add headers during initialization:

Github.new do |config|
  config.basic_auth         = "user:password"
  config.connection_options = {headers: {"X-GitHub-OTP" => '2fa token'}}
end

or per request:

github = Github.new basic_auth: 'login:password'
github.oauth.create scopes: ["public_repo"],
                    headers: {"X-GitHub-OTP" => "2fa token"}

4 Pagination

Any request that returns multiple items will be paginated to 30 items by default. You can specify custom page and per_page query parameters to alter default behavior. For instance:

repos    = Github::Client::Repos.new
response = repos.list user: 'wycats', per_page: 10, page: 5

Then you can query the pagination information included in the link header by:

response.links.first  # Shows the URL of the first page of results.
response.links.next   # Shows the URL of the immediate next page of results.
response.links.prev   # Shows the URL of the immediate previous page of results.
response.links.last   # Shows the URL of the last page of results.

In order to iterate through the entire result set page by page, you can use convenience methods:

response.each_page do |page|
  page.each do |repo|
    puts repo.name
  end
end

or use has_next_page? and next_page helper methods like in the following:

while response.has_next_page?
  ... process response ...
  res.next_page
end

One can also navigate straight to the specific page by:

res.count_pages  # Number of pages
res.page 5       # Requests given page if it exists, nil otherwise
res.first_page   # Get first page
res.next_page    # Get next page
res.prev_page    # Get previous page
res.last_page    # Get last page

4.1 Auto pagination

You can retrieve all pages in one invocation by passing the auto_pagination option like so:

github = Github.new auto_pagination: true

Depending at what stage you pass the auto_pagination it will affect all or only a single request. For example, in order to auto paginate all Repository API methods do:

Github::Сlient::Repos.new auto_pagination: true

However, to only auto paginate results for a single request do:

Github::Client::Repos.new.list user: '...', auto_pagination: true

5 Error Handling

The generic error class Github::Error::GithubError will handle both the client (Github::Error::ClientError) and service (Github::Error::ServiceError) side errors.

For instance in your code you can catch errors like

begin
  # Do something with github_api gem
rescue Github::Error::GithubError => e
  puts e.message
  if e.is_a? Github::Error::ServiceError
    # handle GitHub service errors such as 404
  elsif e.is_a? Github::Error::ClientError
    # handle client errors e.i. missing required parameter in request
  end
end

5.1 Client Error

Any time Github client has a problem sending request a Github::Error::ClientError is raised that will provide a summary of the problem and possible solutions.

5.2 Service Error

When the Github client receives a HTTP response from GitHub service that indicates error then Github::Error::ServiceError is raised.

There are number of specific error types such as Github::Error::NotAcceptable when 406 status code is returned.

5.2.1 Data

When Github::Error::ServiceError is raised you can call data to access it payload in JSON format.

5.2.2 Error messages

Anytime there are error messages provided with Github::Error::ServiceError you can access them by calling error_messages helper.

6 Examples

6.1 Rails

A Rails controller that allows a user to authorize their GitHub account and then performs a request.

class GithubController < ApplicationController

  def authorize
    address = github.authorize_url redirect_uri: 'http://...', scope: 'repo'
    redirect_to address
  end

  def callback
    authorization_code = params[:code]
    access_token = github.get_token authorization_code
    access_token.token   # => returns token value
  end

  private

   def github
    @github ||= Github.new client_id: '...', client_secret: '...'
   end
end

6.2 Manipulating Files

In order to be able to create/update/remove files you need to use Contents API like so:

contents = Github::Client::Repos::Contents.new oauth_token: '...'

Having instantiated the contents, to create a file do:

contents.create 'username', 'repo_name', 'full_path_to/file.ext',
  path: 'full_path_to/file.ext',
  message: 'Your commit message',
  content: 'The contents of your file'

Content is all Base64 encoded to/from the API, and when you create a file it encodes it automatically for you.

To update a file, first you need to find the file so you can get the SHA you're updating off of:

file = contents.find path: 'full_path_to/file.ext'

Then update the file just like you do with creating:

contents.update 'username', 'repo_name', 'full_path_to/file.ext',
  path: 'full_path_to/file.ext'
  message: 'Your commit message',
  content: 'The contents to be updated',
  sha: file.sha

Finally to remove a file, find the file so you can get the SHA you're removing:

file = contents.find path: 'full_path_to/file.ext'

Then delete the file like so:

github.delete 'username', 'tome-of-knowledge', 'full_path_to/file.ext',
  path: 'full_path_to/file.ext',
  message: 'Your Commit Message',
  sha: file.sha

7 Testing

The test suite is split into two groups, live and mock.

The live tests are in the features folder and exercise the GitHub API directly by making live requests and then caching responses with VCR in directory named features\cassettes. For details on how to get set up, please navigate to the features folder.

To run all feature tests do:

bundle exec rake features

The mock tests are in the spec folder and their primary concern is to test the gem internals without the hindrance of external calls.

To run all specs do:

bundle exec rake spec

Finally to run all tests do:

bundle exec rake

Development

Questions or problems? Please post them on the issue tracker. You can contribute changes by forking the project and submitting a pull request. You can ensure the tests are passing by running bundle and rake.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/piotrmurach/github. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

Copyright

Copyright (c) 2011 Piotr Murach. See LICENSE.txt for further details.

More Repositories

1

tty

Toolkit for developing sleek command line apps.
Ruby
2,472
star
2

tty-prompt

A beautiful and powerful interactive command line prompt
Ruby
1,418
star
3

finite_machine

A minimal finite state machine with a straightforward syntax.
Ruby
802
star
4

pastel

Terminal output styling with intuitive and clean API.
Ruby
628
star
5

rspec-benchmark

Performance testing matchers for RSpec
Ruby
584
star
6

tty-spinner

A terminal spinner for tasks that have non-deterministic time frame.
Ruby
421
star
7

tty-progressbar

Display a single or multiple progress bars in the terminal.
Ruby
415
star
8

loaf

Manages and displays breadcrumb trails in Rails app - lean & mean.
Ruby
404
star
9

tty-command

Execute shell commands with pretty output logging and capture stdout, stderr and exit status.
Ruby
397
star
10

tty-markdown

Convert a markdown document or text into a terminal friendly output.
Ruby
303
star
11

tty-logger

A readable, structured and beautiful logging for the terminal
Ruby
291
star
12

github_cli

GitHub on your command line. Use your terminal, not the browser.
Ruby
264
star
13

tty-table

A flexible and intuitive table generator
Ruby
183
star
14

tty-box

Draw various frames and boxes in your terminal window
Ruby
177
star
15

awesome-ruby-cli-apps

A curated list of awesome command-line applications in Ruby.
Ruby
159
star
16

rack-policy

Rack middleware for the EU ePrivacy Directive compliance in Ruby Web Apps
Ruby
147
star
17

tty-pie

Draw pie charts in your terminal window
Ruby
138
star
18

necromancer

Conversion from one object type to another with a bit of black magic.
Ruby
135
star
19

strings

A set of useful functions for transforming strings.
Ruby
127
star
20

coinpare

Compare cryptocurrency trading data across multiple exchanges and blockchains in the comfort of your terminal
Ruby
109
star
21

tty-exit

Terminal exit codes.
Ruby
100
star
22

strings-case

Convert strings between different cases.
Ruby
95
star
23

tty-reader

A set of methods for processing keyboard input in character, line and multiline modes.
Ruby
85
star
24

tty-option

A declarative command-line parser
Ruby
84
star
25

merkle_tree

A merkle tree is a data structure used for efficiently summarizing sets of data, often one-time signatures.
Ruby
83
star
26

tty-screen

Terminal screen detection - cross platform, major ruby interpreters
Ruby
83
star
27

verse

[DEPRECATED] Text transformations
Ruby
71
star
28

tty-cursor

Terminal cursor movement and manipulation of cursor properties such as visibility
Ruby
68
star
29

supervision

Write distributed systems that are resilient and self-heal.
Ruby
66
star
30

tty-file

File manipulation utility methods
Ruby
65
star
31

tty-config

A highly customisable application configuration interface for building terminal tools.
Ruby
61
star
32

benchmark-trend

Measure performance trends of Ruby code
Ruby
59
star
33

tty-font

Terminal fonts
Ruby
58
star
34

lex

Lex is an implementation of lex tool in Ruby.
Ruby
56
star
35

tty-tree

Print directory or structured data in a tree like format
Ruby
56
star
36

strings-truncation

Truncate strings with fullwidth characters and ANSI codes.
Ruby
49
star
37

tty-pager

Terminal output paging - cross-platform, major ruby interpreters
Ruby
39
star
38

tty-color

Terminal color capabilities detection
Ruby
35
star
39

slideck

Present Markdown-powered slide decks in the terminal.
Ruby
34
star
40

strings-inflection

Convert between singular and plural forms of English nouns
Ruby
31
star
41

tty-link

Hyperlinks in your terminal
Ruby
31
star
42

tty-platform

Operating system detection
Ruby
29
star
43

tty-sparkline

Sparkline charts for terminal applications.
Ruby
29
star
44

tty-editor

Opens a file or text in the user's preferred editor
Ruby
27
star
45

communist

Library for mocking CLI calls to external APIs
Ruby
25
star
46

splay_tree

A self-balancing binary tree optimised for fast access to frequently used nodes.
Ruby
24
star
47

equatable

Allows ruby objects to implement equality comparison and inspection methods.
Ruby
24
star
48

minehunter

Terminal mine hunting game.
Ruby
23
star
49

rotation.js

Responsive and mobile enabled jQuery plugin to help create rotating content.
JavaScript
22
star
50

strings-numeral

Express numbers as string numerals
Ruby
20
star
51

strings-ansi

Handle ANSI escape codes in strings
Ruby
19
star
52

benchmark-malloc

Trace memory allocations and collect stats
Ruby
19
star
53

tty-which

Cross-platform implementation of Unix `which` command
Ruby
17
star
54

tty-runner

A command routing tree for terminal applications
Ruby
12
star
55

benchmark-perf

Benchmark execution time and iterations per second
Ruby
12
star
56

impact

Ruby backend for Impact.js framework
Ruby
8
star
57

queen

English language linter to hold your files in high esteem.
Ruby
8
star
58

pastel-cli

CLI tool for intuitive terminal output styling
Ruby
7
star
59

dotfiles

Configuration files for Unix tools
Vim Script
7
star
60

tty-markdown-cli

CLI tool for displaying nicely formatted Markdown documents in the terminal
Ruby
7
star
61

static_deploy

Automate deployment of static websites
Ruby
6
star
62

tenpin

Terminal tenpin bowling game
Ruby
4
star
63

tytus

Helps you manage page titles in your Rails app.
Ruby
3
star
64

tty.github.io

TTY toolkit website.
SCSS
2
star
65

peter-murach.github.com

Personal webpage
JavaScript
2
star
66

wc.rb

A Ruby clone of Unix wc utility.
Ruby
2
star
67

exportable

Rails plugin to ease exporting tasks.
Ruby
1
star
68

capistrano-git-stages

Multistage capistrano git tags
Ruby
1
star
69

tabster

Ruby
1
star
70

leek

Cucumber steps and RSpec expectations for command line apps
Ruby
1
star
71

unicorn.github.io

Website for the github_api and github_cli ruby gems.
CSS
1
star
72

tty-color-cli

CLI tool for terminal color capabilities detection
Ruby
1
star
73

finite_machine.github.io

Website for finite_machine Ruby gem
SCSS
1
star
74

strings-wrapping

Wrap strings with fullwidth characters and ANSI codes
Ruby
1
star