github_api 0.3.9 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,38 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :get
5
+ uri: https://api.github.com:443/repos/peter-murach/github/teams
6
+ body:
7
+ headers:
8
+ accept-encoding:
9
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
10
+ response: !ruby/struct:VCR::Response
11
+ status: !ruby/struct:VCR::ResponseStatus
12
+ code: 404
13
+ message: Not Found
14
+ headers:
15
+ server:
16
+ - nginx/1.0.4
17
+ date:
18
+ - Tue, 03 Jan 2012 16:15:19 GMT
19
+ content-type:
20
+ - application/json; charset=utf-8
21
+ transfer-encoding:
22
+ - chunked
23
+ connection:
24
+ - keep-alive
25
+ status:
26
+ - 404 Not Found
27
+ x-ratelimit-limit:
28
+ - "5000"
29
+ etag:
30
+ - "\"e66a7a6c91e2c26803f3f49feb7a883f\""
31
+ x-ratelimit-remaining:
32
+ - "4997"
33
+ content-encoding:
34
+ - gzip
35
+ body: !binary |
36
+ H4sIAAAAAAAAA6tWyk0tLk5MT1WyUvLLL1Fwyy/NS1GqBQB8+Ys1FwAAAA==
37
+
38
+ http_version: "1.1"
@@ -0,0 +1,28 @@
1
+ Feature: Accessing Repos Main API
2
+ In order to interact with github repositories
3
+ GithubAPI gem
4
+ Should return the expected results depending on passed parameters
5
+
6
+ Scenario: Returning all repository branches
7
+ Given I have "Github::Repos" instance
8
+ And I am looking for "branches" with the following params:
9
+ | user | repo |
10
+ | peter-murach | github |
11
+ And I make request within a cassette named "repos/branches"
12
+ Then the response should be "200"
13
+
14
+ Scenario: Returning all repository tags
15
+ Given I have "Github::Repos" instance
16
+ And I am looking for "tags" with the following params:
17
+ | user | repo |
18
+ | peter-murach | github |
19
+ And I make request within a cassette named "repos/tags"
20
+ Then the response should be "200"
21
+
22
+ Scenario: Returning all repositories for the user
23
+ Given I have "Github::Repos" instance
24
+ And I am looking for "list_repos" with the following params:
25
+ | user |
26
+ | peter-murach |
27
+ And I make request with hash params within a cassette named "repos/tags"
28
+ Then the response should be "200"
@@ -0,0 +1,11 @@
1
+ Before do
2
+ step "I have github instance"
3
+ end
4
+
5
+ When /^(.*) within a cassette named "([^"]*)"$/ do |step_to_call, cassette_name|
6
+ VCR.use_cassette(cassette_name) { step step_to_call }
7
+ end
8
+
9
+ Then /^the response should be "([^"]*)"$/ do |expected_response|
10
+ @response.status.should eql expected_response.to_i
11
+ end
@@ -2,6 +2,14 @@ Given /^I have github instance$/ do
2
2
  @github = Github.new
3
3
  end
4
4
 
5
+ Given /^I have "([^"]*)" instance$/ do |api_classes|
6
+ constant = Object
7
+ api_classes.split('::').each do |api_class|
8
+ constant = constant.const_get api_class
9
+ end
10
+ @instance = constant.new
11
+ end
12
+
5
13
  When /^I fetch "([^"]*)"$/ do |method|
6
14
  @response = @github.send(method.to_sym)
7
15
  end
@@ -9,3 +17,18 @@ end
9
17
  When /^I will have access to "([^"]*)" API$/ do |api|
10
18
  @response.class.to_s.should match api
11
19
  end
20
+
21
+ When /^I am looking for "([^"]*)" with the following params:$/ do |method, table|
22
+ table.hashes.each do |attributes|
23
+ @method = method.to_sym
24
+ @attributes = attributes
25
+ end
26
+ end
27
+
28
+ When /^I make request$/ do
29
+ @response = @instance.send @method, *@attributes.values
30
+ end
31
+
32
+ When /^I make request with hash params$/ do
33
+ @response = @instance.send @method, @attributes
34
+ end
@@ -1,6 +1,12 @@
1
+ require 'vcr'
2
+
1
3
  VCR.config do |conf|
2
4
  conf.stub_with :webmock
3
5
  conf.cassette_library_dir = 'features/cassettes'
4
6
  conf.default_cassette_options = { :record => :new_episodes }
5
7
  conf.filter_sensitive_data('<***>') { ''}
6
8
  end
9
+
10
+ VCR.cucumber_tags do |t|
11
+ t.tag '@live', :record => :all
12
+ end
data/lib/github_api.rb CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'github_api/version'
4
4
  require 'github_api/configuration'
5
+ require 'github_api/constants'
6
+ require 'github_api/utils/url'
5
7
  require 'github_api/connection'
6
8
 
7
9
  module Github
@@ -12,7 +14,12 @@ module Github
12
14
  #
13
15
  # @return [Github::Client]
14
16
  def new(options = {}, &block)
15
- Github::Client.new(options, &block)
17
+ @@api_client = Github::Client.new(options, &block)
18
+ end
19
+
20
+ # Returns handle for the client instance
21
+ def api_client
22
+ @@api_client
16
23
  end
17
24
 
18
25
  # Delegate to Github::Client
@@ -68,6 +75,9 @@ module Github
68
75
  :CoreExt => 'core_ext',
69
76
  :MimeType => 'mime_type',
70
77
  :Authorization => 'authorization',
71
- :Authorizations => 'authorizations'
78
+ :Authorizations => 'authorizations',
79
+ :PageLinks => 'page_links',
80
+ :PageIterator => 'page_iterator',
81
+ :PagedRequest => 'paged_request'
72
82
 
73
83
  end # Github
@@ -18,8 +18,9 @@ module Github
18
18
  include Request
19
19
 
20
20
  VALID_API_KEYS = [
21
- :per_page,
22
- :pagination
21
+ 'page',
22
+ 'per_page',
23
+ 'jsonp_callback'
23
24
  ]
24
25
 
25
26
  attr_reader *Configuration::VALID_OPTIONS_KEYS
@@ -61,10 +62,13 @@ module Github
61
62
  end
62
63
  end
63
64
 
64
- # Responds to attribute query
65
+ # Responds to attribute query or attribute clear
65
66
  def method_missing(method, *args, &block) # :nodoc:
66
- if method.to_s =~ /^(.*)\?$/
67
+ case method.to_s
68
+ when /^(.*)\?$/
67
69
  return !self.send($1.to_s).nil?
70
+ when /^clear_(.*)$/
71
+ self.send("#{$1.to_s}=", nil)
68
72
  else
69
73
  super
70
74
  end
@@ -123,7 +127,7 @@ module Github
123
127
  case params
124
128
  when Hash
125
129
  params.keys.each do |k, v|
126
- unless keys.include? k
130
+ unless (keys.include?(k) or VALID_API_KEYS.include?(k))
127
131
  params.delete(k)
128
132
  else
129
133
  _filter_params_keys(keys, params[k])
@@ -25,9 +25,9 @@ module Github
25
25
  def default_options(options={}) # :nodoc:
26
26
  {
27
27
  :headers => {
28
- 'Accept' => '*/*', #accepts,
29
- 'User-Agent' => user_agent,
30
- 'Content-Type' => 'application/x-www-form-urlencoded'
28
+ :accept => '*/*', #accepts,
29
+ :user_agent => user_agent,
30
+ :content_type => 'application/x-www-form-urlencoded'
31
31
  },
32
32
  :ssl => { :verify => false },
33
33
  :url => endpoint
@@ -49,7 +49,7 @@ module Github
49
49
 
50
50
  @connection ||= begin
51
51
  Faraday.new(merged_options.merge(connection_options)) do |builder|
52
- puts options.inspect
52
+ puts options.inspect if ENV['DEBUG']
53
53
 
54
54
  builder.use Faraday::Request::JSON
55
55
  builder.use Faraday::Request::Multipart
@@ -0,0 +1,38 @@
1
+ module Github
2
+ module Constants
3
+ extend self
4
+
5
+ # Response headers
6
+ RATELIMIT_REMAINING = 'X-RateLimit-Remaining'.freeze
7
+
8
+ RATELIMIT_LIMIT = 'X-RateLimit-Limit'.freeze
9
+
10
+ CONTENT_TYPE = 'Content-Type'.freeze
11
+
12
+ CONTENT_LENGTH = 'content-length'.freeze
13
+
14
+ # Link headers
15
+ HEADER_LINK = "Link".freeze
16
+
17
+ HEADER_NEXT = "X-Next".freeze
18
+
19
+ HEADER_LAST = "X-Last".freeze
20
+
21
+ META_REL = "rel".freeze
22
+
23
+ META_LAST = "last".freeze
24
+
25
+ META_NEXT = "next".freeze
26
+
27
+ META_FIRST = "first".freeze
28
+
29
+ META_PREV = "prev".freeze
30
+
31
+ PARAM_PAGE = "page".freeze
32
+
33
+ PARAM_PER_PAGE = "per_page".freeze
34
+
35
+ PARAM_START_PAGE = "start_page".freeze
36
+
37
+ end # Constants
38
+ end # Github
@@ -5,7 +5,7 @@ module Github
5
5
  attr_reader :response_message, :response_headers
6
6
 
7
7
  def initialize(message, headers)
8
- @response_message = message
8
+ @response_message = message
9
9
  super message
10
10
  end
11
11
 
@@ -21,11 +21,14 @@ module Github
21
21
  class Unauthorised < Error; end
22
22
 
23
23
  # Raised when Github returns the HTTP status code 403
24
- class Forbidden < Error; end
24
+ class Forbidden < Error; end
25
25
 
26
26
  # Raised when Github returns the HTTP status code 404
27
27
  class ResourceNotFound < Error; end
28
28
 
29
+ # Raised when Github returns the HTTP status code 422
30
+ class UnprocessableEntity < Error; end
31
+
29
32
  # Raised when Github returns the HTTP status code 500
30
33
  class InternalServerError < Error; end
31
34
 
@@ -0,0 +1,118 @@
1
+ # encoding: utf-8
2
+
3
+ require 'github_api/utils/url'
4
+
5
+ module Github
6
+ class PageIterator
7
+ include Github::Constants
8
+ include Github::Utils::Url
9
+ include Github::PagedRequest
10
+
11
+ # Query string separator
12
+ QUERY_STR_SEP = '?'.freeze
13
+
14
+ # Setup attribute accesor for all the link types
15
+ ATTRIBUTES = [ META_FIRST, META_NEXT, META_PREV, META_LAST ]
16
+
17
+ ATTRIBUTES.each do |attr|
18
+ attr_accessor :"#{attr}_page_uri", :"#{attr}_page"
19
+ end
20
+
21
+ def initialize(env)
22
+ @links = Github::PageLinks.new(env[:response_headers])
23
+ update_page_links @links
24
+ end
25
+
26
+ def has_next?
27
+ next_page == 0 || !next_page_uri.nil?
28
+ end
29
+
30
+ def first
31
+ return nil unless first_page_uri
32
+ response = page_request first_page_uri.split(QUERY_STR_SEP)[0],
33
+ 'per_page' => parse_per_page_number(first_page_uri)
34
+ update_page_links response.links
35
+ response
36
+ end
37
+
38
+ def next
39
+ return nil unless has_next?
40
+
41
+ response = page_request next_page_uri.split(QUERY_STR_SEP)[0],
42
+ 'page' => next_page,
43
+ 'per_page'=> parse_per_page_number(next_page_uri)
44
+ update_page_links response.links
45
+ response
46
+ end
47
+
48
+ def prev
49
+ return nil unless prev_page_uri
50
+ response = page_request prev_page_uri.split(QUERY_STR_SEP)[0],
51
+ 'page' => prev_page,
52
+ 'per_page'=> parse_per_page_number(prev_page_uri)
53
+ update_page_links response.links
54
+ response
55
+ end
56
+
57
+ def last
58
+ return nil unless last_page_uri
59
+ response = page_request last_page_uri.split(QUERY_STR_SEP)[0],
60
+ 'page' => last_page,
61
+ 'per_page' => parse_per_page_number(last_page_uri)
62
+ update_page_links response.links
63
+ response
64
+ end
65
+
66
+ # Returns the result for a specific page.
67
+ def get_page(page_number)
68
+ # Find URI that we can work with, if we cannot get the first or the
69
+ # last page URI then there is only one page.
70
+ page_uri = first_page_uri || last_page_uri
71
+ return nil unless page_uri
72
+
73
+ response = page_request page_uri.split(QUERY_STR_SEP)[0],
74
+ 'page' => page_number,
75
+ 'per_page' => parse_per_page_number(page_uri)
76
+ update_page_links response.links
77
+ response
78
+ end
79
+
80
+
81
+ private
82
+
83
+ def parse_per_page_number(uri) # :nodoc:
84
+ parse_page_params(uri, PARAM_PER_PAGE)
85
+ end
86
+
87
+ def parse_page_number(uri) # :nodoc:
88
+ parse_page_params(uri, PARAM_PAGE)
89
+ end
90
+
91
+ # Extracts query string parameter for given name
92
+ def parse_page_params(uri, attr) # :nodoc:
93
+ return -1 if uri.nil? || uri.empty?
94
+ parsed = nil
95
+ begin
96
+ parsed = URI.parse(uri)
97
+ rescue URI::Error => e
98
+ return -1
99
+ end
100
+ param = parse_query_for_param(parsed.query, attr)
101
+ return -1 if param.nil? || param.empty?
102
+ begin
103
+ return param.to_i
104
+ rescue ArgumentError => err
105
+ return -1
106
+ end
107
+ end
108
+
109
+ # Wholesale update of all link attributes
110
+ def update_page_links(links) # :nodoc:
111
+ ATTRIBUTES.each do |attr|
112
+ self.send(:"#{attr}_page_uri=", links.send(:"#{attr}"))
113
+ self.send(:"#{attr}_page=", parse_page_number(links.send(:"#{attr}")))
114
+ end
115
+ end
116
+
117
+ end # PageIterator
118
+ end # Github
@@ -0,0 +1,45 @@
1
+ module Github
2
+ # Determines the links in the current response link header to be used
3
+ # to find the links to other pages of request responses. These will
4
+ # only be present if the result set size exceeds the per page limit.
5
+ class PageLinks
6
+ include Github::Constants
7
+
8
+ DELIM_LINKS = ",".freeze # :nodoc:
9
+
10
+ # Hold the extracted values for URI from the Link header
11
+ # for the first, last, next and previous page.
12
+ attr_accessor :first, :last, :next, :prev
13
+
14
+ # Parses links from executed request
15
+ #
16
+ def initialize(response_headers)
17
+ link_header = response_headers[HEADER_LINK]
18
+ if link_header
19
+ return unless link_header =~ /(next|first|last|prev)/
20
+
21
+ link_header.split(DELIM_LINKS).each do |link|
22
+ if link.strip =~ /<([^>]+)>; rel=\"([^\"]+)\"/
23
+ url_part, meta_part = $1, $2
24
+ next if !url_part || !meta_part
25
+ case meta_part
26
+ when META_FIRST
27
+ self.first = url_part
28
+ when META_LAST
29
+ self.last = url_part
30
+ when META_NEXT
31
+ self.next = url_part
32
+ when META_PREV
33
+ self.prev = url_part
34
+ end
35
+ end
36
+ end
37
+ else
38
+ # When on the first page
39
+ self.next = response_headers[HEADER_NEXT]
40
+ self.last = response_headers[HEADER_LAST]
41
+ end
42
+ end
43
+
44
+ end # PageLinks
45
+ end # Github