github_api 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +51 -20
- data/lib/github_api.rb +3 -1
- data/lib/github_api/api.rb +8 -2
- data/lib/github_api/authorization.rb +52 -0
- data/lib/github_api/cache_control.rb +19 -0
- data/lib/github_api/configuration.rb +8 -11
- data/lib/github_api/connection.rb +18 -36
- data/lib/github_api/gists/comments.rb +17 -5
- data/lib/github_api/issues.rb +9 -1
- data/lib/github_api/issues/comments.rb +15 -4
- data/lib/github_api/mime_type.rb +55 -0
- data/lib/github_api/pull_requests.rb +14 -0
- data/lib/github_api/pull_requests/comments.rb +10 -0
- data/lib/github_api/repos/collaborators.rb +41 -19
- data/lib/github_api/repos/commits.rb +108 -43
- data/lib/github_api/repos/forks.rb +32 -13
- data/lib/github_api/request.rb +12 -3
- data/lib/github_api/request/caching.rb +33 -0
- data/lib/github_api/version.rb +1 -1
- data/spec/fixtures/repos/collaborators.json +8 -0
- data/spec/fixtures/repos/commit.json +53 -0
- data/spec/fixtures/repos/commit_comment.json +16 -0
- data/spec/fixtures/repos/commit_comments.json +18 -0
- data/spec/fixtures/repos/commits.json +27 -0
- data/spec/fixtures/{repos_list.json → repos/fork.json} +0 -0
- data/spec/fixtures/repos/forks.json +29 -0
- data/spec/fixtures/repos/repo_comments.json +18 -0
- data/spec/github/authorization_spec.rb +71 -0
- data/spec/github/mime_type_spec.rb +70 -0
- data/spec/github/repos/collaborators_spec.rb +166 -3
- data/spec/github/repos/commits_spec.rb +421 -2
- data/spec/github/repos/forks_spec.rb +101 -3
- data/spec/github/repos/watching_spec.rb +6 -0
- data/spec/github_spec.rb +8 -4
- metadata +17 -9
- data/lib/github_api/api/extract_options.rb +0 -17
- data/lib/github_api/api/mime.rb +0 -5
- data/spec/fixtures/collaborators_list.json +0 -6
- data/spec/fixtures/commits_list.json +0 -25
- data/spec/fixtures/repos_branches_list.json +0 -7
data/README.rdoc
CHANGED
@@ -12,7 +12,7 @@ Grab the gem by issuing
|
|
12
12
|
|
13
13
|
or in your Gemfile
|
14
14
|
|
15
|
-
gem "github_api", "~> 0.2.
|
15
|
+
gem "github_api", "~> 0.2.1"
|
16
16
|
|
17
17
|
== Usage
|
18
18
|
|
@@ -20,20 +20,12 @@ Create a new client instance
|
|
20
20
|
|
21
21
|
@github = Github.new
|
22
22
|
|
23
|
-
At this stage you can also supply various configuration parameters, such as :user, :repo, :org, :oauth_token, :login, :password or :basic_auth
|
24
|
-
which are used thoughtout the API
|
23
|
+
At this stage you can also supply various configuration parameters, such as :user, :repo, :org, :oauth_token, :login, :password or :basic_auth which are used thoughtout the API
|
25
24
|
|
26
25
|
@github = Github.new :user => 'peter-murach', :repo => 'github-api'
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
* visit https://github.com/account/applications/ and register your app
|
31
|
-
* authorize your credentials https://github.com/login/oauth/authorize
|
32
|
-
* get your token https://github.com/login/oauth/access_token
|
27
|
+
You can authenticate either using OAuth authentication convenience methods(see section OAuth) or through basic authentication by passing your login and password credentials
|
33
28
|
|
34
|
-
Once you have your consumer and token keys, configure your github instance following instructions under Configuration.
|
35
|
-
|
36
|
-
You can also use basic authentication by passing your login and password credentials
|
37
29
|
@github = Github.new :login => 'peter-murach', :password => '...'
|
38
30
|
|
39
31
|
or use convenience method:
|
@@ -85,7 +77,7 @@ All method calls form ruby like sentences and allow for intuitive api navigation
|
|
85
77
|
|
86
78
|
@github = Github.new :oauth_token => '...'
|
87
79
|
@github.users.following 'wycats' # => returns users that 'wycats' is following
|
88
|
-
@github.users.following
|
80
|
+
@github.users.following 'wycats' # => returns true if following, otherwise false
|
89
81
|
|
90
82
|
For specification on all available methods go to http://developer.github.com/v3/ or
|
91
83
|
read the rdoc, all methods are documented there with examples of usage.
|
@@ -106,14 +98,35 @@ or organisation name, allow you to switch the way the data is returned to you, f
|
|
106
98
|
puts file.path
|
107
99
|
end
|
108
100
|
|
101
|
+
== OAuth
|
102
|
+
|
103
|
+
In order to authenticate the user through OAuth2 on GitHub you need to
|
104
|
+
|
105
|
+
* visit https://github.com/account/applications/ and register your app
|
106
|
+
|
107
|
+
* authorize your credentials https://github.com/login/oauth/authorize
|
108
|
+
You can use convenience methods to help you achieve this that come with this gem:
|
109
|
+
|
110
|
+
@github = Github.new :client_id => '...', :client_secret => '...'
|
111
|
+
@github.authorize_url :redirect_uri => 'http://localhost', :scope => 'repo'
|
112
|
+
# => "https://github.com/login/oauth/authorize?scope=repo&response_type=code&client_id='...'&redirect_uri=http%3A%2F%2Flocalhost"
|
113
|
+
|
114
|
+
After you get your authorization code, call to receive your access_token
|
115
|
+
|
116
|
+
token = github.get_token( authorization_code )
|
117
|
+
|
118
|
+
Once you have your access token, configure your github instance following instructions under Configuration.
|
119
|
+
|
109
120
|
== MIME Types
|
110
121
|
|
111
|
-
|
122
|
+
Issues, PullRequests and few other API leverage custom mime types which are <tt>:json</tt>, <tt>:blob</tt>, <tt>:raw</tt>, <tt>:text</tt>, <tt>:html</tt>, <tt>:full</tt>. By default <tt>:raw</tt> is used.
|
112
123
|
|
113
124
|
In order to pass a mime type with your request do
|
114
125
|
|
115
|
-
@github = Github.new
|
116
|
-
@github
|
126
|
+
@github = Github.new
|
127
|
+
@github.pull_requests.pull_requests 'peter-murach', 'github', :mime_type => :full
|
128
|
+
|
129
|
+
Your header will contain 'Accept: "application/vnd.github-pull.full+json"' which in turn returns raw, text and html representations in response body.
|
117
130
|
|
118
131
|
== Configuration
|
119
132
|
|
@@ -132,6 +145,12 @@ or
|
|
132
145
|
|
133
146
|
All parameters can be overwirtten as per method call. By passing parameters hash...
|
134
147
|
|
148
|
+
== Caching
|
149
|
+
|
150
|
+
Each <tt>get</tt> request by default is not going to be cached. In order to set the cache do... If no cache type is provided a default memoization is done.
|
151
|
+
|
152
|
+
Github.cache do...
|
153
|
+
|
135
154
|
== Examples
|
136
155
|
|
137
156
|
Some api methods require input parameters, these are added simply as a hash properties, for instance
|
@@ -156,17 +175,29 @@ Query requests instead of http responses return boolean values
|
|
156
175
|
@github = Github.new
|
157
176
|
@github.orgs.public_member? 'github', 'technoweenie' # => true
|
158
177
|
|
159
|
-
==
|
178
|
+
== Rails Example
|
179
|
+
|
180
|
+
A Rails controller that allows a user to authorize their GitHub account and then perform request.
|
160
181
|
|
161
|
-
|
182
|
+
class GithubController < ApplicationController
|
183
|
+
|
184
|
+
def authorize
|
185
|
+
github = Github.new :client_id => '...', :client_secret => '...'
|
186
|
+
address = github.authorize_url :redirect_uri => 'http://...', :scope => 'repo'
|
187
|
+
redirect_to address
|
188
|
+
end
|
189
|
+
|
190
|
+
def callback
|
191
|
+
authorization_code = params[:code]
|
192
|
+
token = github.get_token authorization_code
|
193
|
+
access_token = token.token
|
194
|
+
end
|
195
|
+
end
|
162
196
|
|
163
197
|
== TODO
|
164
198
|
|
165
|
-
* Add support for mime types
|
166
199
|
* Add request caching - local filestore?, http caching?.
|
167
|
-
* Add oauth2 helper methods.
|
168
200
|
* Add response processing methods
|
169
|
-
* Add helper methods to return iterators over most common collections.
|
170
201
|
* Add response set helper methods e.i. pagination.
|
171
202
|
* Add DSL falvoured api access
|
172
203
|
|
data/lib/github_api.rb
CHANGED
data/lib/github_api/api.rb
CHANGED
@@ -3,12 +3,16 @@
|
|
3
3
|
require 'github_api/configuration'
|
4
4
|
require 'github_api/connection'
|
5
5
|
require 'github_api/request'
|
6
|
+
require 'github_api/mime_type'
|
6
7
|
require 'github_api/core_ext/hash'
|
7
8
|
require 'github_api/core_ext/array'
|
8
9
|
|
9
10
|
module Github
|
11
|
+
|
10
12
|
# @private
|
11
13
|
class API
|
14
|
+
include Authorization
|
15
|
+
include MimeType
|
12
16
|
include Connection
|
13
17
|
include Request
|
14
18
|
|
@@ -37,7 +41,7 @@ module Github
|
|
37
41
|
send("#{key}=", options[key])
|
38
42
|
end
|
39
43
|
_process_basic_auth(options[:basic_auth])
|
40
|
-
|
44
|
+
client if client_id? && client_secret?
|
41
45
|
end
|
42
46
|
|
43
47
|
private
|
@@ -143,7 +147,9 @@ module Github
|
|
143
147
|
end
|
144
148
|
end
|
145
149
|
|
146
|
-
def
|
150
|
+
def _merge_mime_type(resource, params) # :nodoc:
|
151
|
+
params['resource'] = resource
|
152
|
+
params['mime_type'] = params['mime_type'] || :raw
|
147
153
|
end
|
148
154
|
|
149
155
|
# TODO add to core extensions
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Github
|
4
|
+
module Authorization
|
5
|
+
|
6
|
+
attr_accessor :scopes
|
7
|
+
|
8
|
+
# Setup OAuth2 instance
|
9
|
+
def client
|
10
|
+
@client ||= ::OAuth2::Client.new(client_id, client_secret,
|
11
|
+
:site => 'https://github.com',
|
12
|
+
:authorize_url => 'login/oauth/authorize',
|
13
|
+
:token_url => 'login/oauth/access_token'
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Strategy token
|
18
|
+
def auth_code
|
19
|
+
_verify_client
|
20
|
+
@client.auth_code
|
21
|
+
end
|
22
|
+
|
23
|
+
# Sends authorization request to GitHub.
|
24
|
+
# = Parameters
|
25
|
+
# * <tt>:redirect_uri</tt> - Required string.
|
26
|
+
# * <tt>:scope</tt> - Optional string. Comma separated list of scopes.
|
27
|
+
# Available scopes:
|
28
|
+
# * (no scope) - public read-only access (includes public user profile info, public repo info, and gists).
|
29
|
+
# * <tt>user</tt> - DB read/write access to profile info only.
|
30
|
+
# * <tt>public_repo</tt> - DB read/write access, and Git read access to public repos.
|
31
|
+
# * <tt>repo</tt> - DB read/write access, and Git read access to public and private repos.
|
32
|
+
# * <tt>gist</tt> - write access to gists.
|
33
|
+
#
|
34
|
+
def authorize_url(params = {})
|
35
|
+
_verify_client
|
36
|
+
@client.auth_code.authorize_url(params)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Makes request to token endpoint and retrieves access token value
|
40
|
+
def get_token(authorization_code, params = {})
|
41
|
+
_verify_client
|
42
|
+
@client.auth_code.get_token(authorization_code, params)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def _verify_client # :nodoc:
|
48
|
+
raise ArgumentError, 'Need to provide client_id and client_secret' unless client_id? && client_secret?
|
49
|
+
end
|
50
|
+
|
51
|
+
end # Authorization
|
52
|
+
end # Github
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Github
|
2
|
+
module CacheOptions
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def self.option_accessor(key)
|
6
|
+
defined_method("#{key}=") { |value| }
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def initialize_options(options={})
|
12
|
+
@default_options = {
|
13
|
+
'type' => :memoization,
|
14
|
+
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -9,10 +9,9 @@ module Github
|
|
9
9
|
:client_secret,
|
10
10
|
:oauth_token,
|
11
11
|
:endpoint,
|
12
|
-
:
|
13
|
-
:resource,
|
12
|
+
:mime_type,
|
14
13
|
:user_agent,
|
15
|
-
:
|
14
|
+
:connection_options,
|
16
15
|
:repo,
|
17
16
|
:user,
|
18
17
|
:login,
|
@@ -47,12 +46,11 @@ module Github
|
|
47
46
|
# The value sent in the http header for 'User-Agent' if none is set
|
48
47
|
DEFAULT_USER_AGENT = "Github Ruby Gem #{Github::VERSION::STRING}".freeze
|
49
48
|
|
50
|
-
|
49
|
+
# By default the <tt>Accept</tt> header will make a request for <tt>JSON</tt>
|
50
|
+
DEFAULT_MIME_TYPE = :json
|
51
51
|
|
52
|
-
# By default
|
53
|
-
|
54
|
-
|
55
|
-
DEFAULT_FARADAY_OPTIONS = {}
|
52
|
+
# By default uses the Faraday connection options if none is set
|
53
|
+
DEFAULT_CONNECTION_OPTIONS = {}
|
56
54
|
|
57
55
|
# By default, don't set user name
|
58
56
|
DEFAULT_USER = nil
|
@@ -84,9 +82,8 @@ module Github
|
|
84
82
|
self.oauth_token = DEFAULT_OAUTH_TOKEN
|
85
83
|
self.endpoint = DEFAULT_ENDPOINT
|
86
84
|
self.user_agent = DEFAULT_USER_AGENT
|
87
|
-
self.
|
88
|
-
self.
|
89
|
-
self.resource = DEFAULT_RESOURCE
|
85
|
+
self.connection_options = DEFAULT_CONNECTION_OPTIONS
|
86
|
+
self.mime_type = DEFAULT_MIME_TYPE
|
90
87
|
self.user = DEFAULT_USER
|
91
88
|
self.repo = DEFAULT_REPO
|
92
89
|
self.login = DEFAULT_LOGIN
|
@@ -11,55 +11,38 @@ require 'github_api/request/basic_auth'
|
|
11
11
|
module Github
|
12
12
|
module Connection
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
:issuecomment => 'vnd.github-issuecomment.',
|
18
|
-
:commitcomment => 'vnd.github-commitcomment',
|
19
|
-
:pull => 'vnd.github-pull.',
|
20
|
-
:pullcomment => 'vnd.github-pullcomment.',
|
21
|
-
:gistcomment => 'vnd.github-gistcomment.'
|
22
|
-
}
|
23
|
-
|
24
|
-
# Mime types used by resources
|
25
|
-
RESOURCE_MIME_TYPES = {
|
26
|
-
:raw => 'raw+json',
|
27
|
-
:text => 'text+json',
|
28
|
-
:html => 'html+json',
|
29
|
-
:full => 'html+full'
|
30
|
-
}
|
31
|
-
|
32
|
-
BLOB_MIME_TYPES = {
|
33
|
-
:raw => 'vnd.github-blob.raw',
|
34
|
-
:json => 'json'
|
35
|
-
}
|
36
|
-
|
37
|
-
def default_faraday_options()
|
14
|
+
private
|
15
|
+
|
16
|
+
def header_options() # :nodoc:
|
38
17
|
{
|
39
18
|
:headers => {
|
40
|
-
'Accept'
|
41
|
-
'User-Agent'
|
19
|
+
'Accept' => '*/*', #accepts,
|
20
|
+
'User-Agent' => user_agent,
|
21
|
+
'Content-Type' => 'application/x-www-form-urlencoded'
|
42
22
|
},
|
43
23
|
:ssl => { :verify => false },
|
44
24
|
:url => endpoint
|
45
25
|
}
|
46
26
|
end
|
47
27
|
|
48
|
-
|
49
|
-
|
50
|
-
# Create cache hash and store connection there and then pass it to @connection
|
51
|
-
# add method to invalidate it if previous options are different from current
|
52
|
-
|
53
|
-
def clear_cache
|
28
|
+
def clear_cache # :nodoc:
|
54
29
|
@connection = nil
|
55
30
|
end
|
56
31
|
|
57
|
-
def caching?
|
32
|
+
def caching? # :nodoc:
|
58
33
|
!@connection.nil?
|
59
34
|
end
|
60
35
|
|
61
|
-
def connection(options = {})
|
62
|
-
|
36
|
+
def connection(options = {}) # :nodoc:
|
37
|
+
|
38
|
+
# parse(options['resource'], options['mime_type'] || mime_type) if options['mime_type']
|
39
|
+
debugger
|
40
|
+
|
41
|
+
merged_options = if connection_options.empty?
|
42
|
+
header_options
|
43
|
+
else
|
44
|
+
connection_options.merge(header_options)
|
45
|
+
end
|
63
46
|
|
64
47
|
clear_cache unless options.empty?
|
65
48
|
|
@@ -89,4 +72,3 @@ module Github
|
|
89
72
|
|
90
73
|
end # Connection
|
91
74
|
end # Github
|
92
|
-
|
@@ -4,8 +4,12 @@ module Github
|
|
4
4
|
class Gists
|
5
5
|
module Comments
|
6
6
|
|
7
|
-
REQUIRED_GIST_COMMENT_INPUTS = %w[
|
8
|
-
|
7
|
+
REQUIRED_GIST_COMMENT_INPUTS = %w[
|
8
|
+
body
|
9
|
+
mime_type
|
10
|
+
resource
|
11
|
+
].freeze
|
12
|
+
|
9
13
|
# List comments on a gist
|
10
14
|
#
|
11
15
|
# = Examples
|
@@ -14,6 +18,8 @@ module Github
|
|
14
18
|
#
|
15
19
|
def gist_comments(gist_id, params={})
|
16
20
|
_normalize_params_keys(params)
|
21
|
+
_merge_mime_type(:gist_comment, params)
|
22
|
+
|
17
23
|
get("/gists/#{gist_id}/comments", params)
|
18
24
|
end
|
19
25
|
|
@@ -25,6 +31,8 @@ module Github
|
|
25
31
|
#
|
26
32
|
def gist_comment(comment_id, params={})
|
27
33
|
_normalize_params_keys(params)
|
34
|
+
_merge_mime_type(:gist_comment, params)
|
35
|
+
|
28
36
|
get("/gists/comments/#{comment_id}", params)
|
29
37
|
end
|
30
38
|
|
@@ -36,8 +44,9 @@ module Github
|
|
36
44
|
#
|
37
45
|
def create_gist_comment(gist_id, params={})
|
38
46
|
_normalize_params_keys(params)
|
47
|
+
_merge_mime_type(:gist_comment, params)
|
39
48
|
_filter_params_keys(REQUIRED_GIST_COMMENT_INPUTS, params)
|
40
|
-
|
49
|
+
|
41
50
|
raise ArgumentError, "Required inputs are: :body" unless _validate_inputs(REQUIRED_GIST_COMMENT_INPUTS, params)
|
42
51
|
|
43
52
|
post("/gists/#{gist_id}/comments", params)
|
@@ -51,8 +60,9 @@ module Github
|
|
51
60
|
#
|
52
61
|
def edit_gist_comment(comment_id, params={})
|
53
62
|
_normalize_params_keys(params)
|
63
|
+
_merge_mime_type(:gist_comment, params)
|
54
64
|
_filter_params_keys(REQUIRED_GIST_COMMENT_INPUTS, params)
|
55
|
-
|
65
|
+
|
56
66
|
raise ArgumentError, "Required inputs are: :body" unless _validate_inputs(REQUIRED_GIST_COMMENT_INPUTS, params)
|
57
67
|
|
58
68
|
patch("/gists/comments/#{comment_id}", params)
|
@@ -66,9 +76,11 @@ module Github
|
|
66
76
|
#
|
67
77
|
def delete_gist_comment(comment_id, params={})
|
68
78
|
_normalize_params_keys(params)
|
79
|
+
_merge_mime_type(:gist_comment, params)
|
80
|
+
|
69
81
|
delete("/gists/comments/#{comment_id}", params)
|
70
82
|
end
|
71
|
-
|
83
|
+
|
72
84
|
end # Comments
|
73
85
|
end # Gists
|
74
86
|
end # Github
|
data/lib/github_api/issues.rb
CHANGED
@@ -27,6 +27,8 @@ module Github
|
|
27
27
|
mentioned
|
28
28
|
title
|
29
29
|
body
|
30
|
+
resource
|
31
|
+
mime_type
|
30
32
|
]
|
31
33
|
|
32
34
|
VALID_ISSUE_PARAM_VALUES = {
|
@@ -58,7 +60,7 @@ module Github
|
|
58
60
|
#
|
59
61
|
# = Examples
|
60
62
|
# @github = Github.new :oauth_token => '...'
|
61
|
-
# @github.issues.issues :since => '2011-04-12312:12:121',
|
63
|
+
# @github.issues.issues :since => '2011-04-12312:12:121',
|
62
64
|
# :filter => 'created',
|
63
65
|
# :state => 'open',
|
64
66
|
# :labels => "bug,ui,bla",
|
@@ -68,6 +70,7 @@ module Github
|
|
68
70
|
def issues(params={})
|
69
71
|
_normalize_params_keys(params)
|
70
72
|
_filter_params_keys(VALID_ISSUE_PARAM_NAMES, params)
|
73
|
+
_merge_mime_type(:issue, params)
|
71
74
|
_validate_params_values(VALID_ISSUE_PARAM_VALUES, params)
|
72
75
|
|
73
76
|
response = get("/issues", params)
|
@@ -111,6 +114,7 @@ module Github
|
|
111
114
|
|
112
115
|
_normalize_params_keys(params)
|
113
116
|
_filter_params_keys(VALID_ISSUE_PARAM_NAMES, params)
|
117
|
+
_merge_mime_type(:issue, params)
|
114
118
|
_validate_params_values(VALID_ISSUE_PARAM_VALUES, params)
|
115
119
|
|
116
120
|
response = get("/repos/#{user}/#{repo}/issues", params)
|
@@ -127,7 +131,9 @@ module Github
|
|
127
131
|
def get_issue(user_name, repo_name, issue_id, params={})
|
128
132
|
_update_user_repo_params(user_name, repo_name)
|
129
133
|
_validate_user_repo_params(user, repo) unless user? && repo?
|
134
|
+
|
130
135
|
_normalize_params_keys(params)
|
136
|
+
_merge_mime_type(:issue, params)
|
131
137
|
|
132
138
|
get("/repos/#{user}/#{repo}/issues/#{issue_id}")
|
133
139
|
end
|
@@ -157,6 +163,7 @@ module Github
|
|
157
163
|
_validate_user_repo_params(user, repo) unless user? && repo?
|
158
164
|
|
159
165
|
_normalize_params_keys(params)
|
166
|
+
_merge_mime_type(:issue, params)
|
160
167
|
_filter_params_keys(VALID_MILESTONE_INPUTS, params)
|
161
168
|
|
162
169
|
raise ArgumentError, "Required params are: :title" unless _validate_inputs(%w[ title ], params)
|
@@ -192,6 +199,7 @@ module Github
|
|
192
199
|
_validate_presence_of issue_id
|
193
200
|
|
194
201
|
_normalize_params_keys(params)
|
202
|
+
_merge_mime_type(:issue, params)
|
195
203
|
_filter_params_keys(VALID_MILESTONE_INPUTS, params)
|
196
204
|
|
197
205
|
patch("/repos/#{user}/#{repo}/issues/#{issue_id}", params)
|