jira-ruby 2.3.0 → 3.0.0.beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/CI.yml +29 -0
- data/.github/workflows/codeql.yml +96 -0
- data/.github/workflows/rubocop.yml +18 -0
- data/.gitignore +3 -1
- data/.rubocop.yml +120 -0
- data/.yardopts +4 -0
- data/Gemfile +11 -3
- data/Guardfile +2 -0
- data/README.md +94 -18
- data/Rakefile +3 -4
- data/jira-ruby.gemspec +11 -17
- data/lib/jira/base.rb +37 -36
- data/lib/jira/base_factory.rb +4 -1
- data/lib/jira/client.rb +123 -50
- data/lib/jira/has_many_proxy.rb +32 -28
- data/lib/jira/http_client.rb +80 -13
- data/lib/jira/http_error.rb +4 -0
- data/lib/jira/jwt_client.rb +18 -42
- data/lib/jira/oauth_client.rb +68 -3
- data/lib/jira/railtie.rb +2 -0
- data/lib/jira/request_client.rb +31 -2
- data/lib/jira/resource/agile.rb +7 -9
- data/lib/jira/resource/applinks.rb +5 -3
- data/lib/jira/resource/attachment.rb +128 -3
- data/lib/jira/resource/board.rb +5 -3
- data/lib/jira/resource/board_configuration.rb +2 -0
- data/lib/jira/resource/comment.rb +2 -0
- data/lib/jira/resource/component.rb +2 -0
- data/lib/jira/resource/createmeta.rb +3 -1
- data/lib/jira/resource/field.rb +13 -12
- data/lib/jira/resource/filter.rb +2 -0
- data/lib/jira/resource/issue.rb +95 -44
- data/lib/jira/resource/issue_picker_suggestions.rb +4 -1
- data/lib/jira/resource/issue_picker_suggestions_issue.rb +2 -0
- data/lib/jira/resource/issuelink.rb +6 -3
- data/lib/jira/resource/issuelinktype.rb +2 -0
- data/lib/jira/resource/issuetype.rb +2 -0
- data/lib/jira/resource/priority.rb +2 -0
- data/lib/jira/resource/project.rb +4 -2
- data/lib/jira/resource/rapidview.rb +5 -3
- data/lib/jira/resource/remotelink.rb +2 -0
- data/lib/jira/resource/resolution.rb +2 -0
- data/lib/jira/resource/serverinfo.rb +2 -0
- data/lib/jira/resource/sprint.rb +14 -23
- data/lib/jira/resource/status.rb +7 -1
- data/lib/jira/resource/status_category.rb +10 -0
- data/lib/jira/resource/suggested_issue.rb +2 -0
- data/lib/jira/resource/transition.rb +2 -0
- data/lib/jira/resource/user.rb +3 -1
- data/lib/jira/resource/version.rb +2 -0
- data/lib/jira/resource/watcher.rb +3 -2
- data/lib/jira/resource/webhook.rb +9 -3
- data/lib/jira/resource/worklog.rb +3 -2
- data/lib/jira/version.rb +3 -1
- data/lib/jira-ruby.rb +5 -3
- data/lib/tasks/generate.rake +3 -1
- data/spec/data/files/short.txt +1 -0
- data/spec/integration/attachment_spec.rb +3 -3
- data/spec/integration/comment_spec.rb +8 -8
- data/spec/integration/component_spec.rb +7 -7
- data/spec/integration/field_spec.rb +3 -3
- data/spec/integration/issue_spec.rb +20 -16
- data/spec/integration/issuelinktype_spec.rb +3 -3
- data/spec/integration/issuetype_spec.rb +3 -3
- data/spec/integration/priority_spec.rb +3 -3
- data/spec/integration/project_spec.rb +8 -8
- data/spec/integration/rapidview_spec.rb +10 -10
- data/spec/integration/resolution_spec.rb +3 -3
- data/spec/integration/status_category_spec.rb +20 -0
- data/spec/integration/status_spec.rb +4 -8
- data/spec/integration/transition_spec.rb +2 -2
- data/spec/integration/user_spec.rb +34 -11
- data/spec/integration/version_spec.rb +7 -7
- data/spec/integration/watcher_spec.rb +21 -18
- data/spec/integration/webhook_spec.rb +33 -0
- data/spec/integration/worklog_spec.rb +8 -8
- data/spec/jira/base_factory_spec.rb +13 -3
- data/spec/jira/base_spec.rb +135 -98
- data/spec/jira/client_spec.rb +63 -47
- data/spec/jira/has_many_proxy_spec.rb +3 -3
- data/spec/jira/http_client_spec.rb +94 -27
- data/spec/jira/http_error_spec.rb +2 -2
- data/spec/jira/oauth_client_spec.rb +14 -8
- data/spec/jira/request_client_spec.rb +4 -4
- data/spec/jira/resource/agile_spec.rb +30 -30
- data/spec/jira/resource/attachment_spec.rb +170 -57
- data/spec/jira/resource/board_spec.rb +24 -23
- data/spec/jira/resource/createmeta_spec.rb +48 -48
- data/spec/jira/resource/field_spec.rb +44 -27
- data/spec/jira/resource/filter_spec.rb +4 -4
- data/spec/jira/resource/issue_picker_suggestions_spec.rb +17 -17
- data/spec/jira/resource/issue_spec.rb +49 -43
- data/spec/jira/resource/jira_picker_suggestions_issue_spec.rb +3 -3
- data/spec/jira/resource/project_factory_spec.rb +3 -2
- data/spec/jira/resource/project_spec.rb +14 -14
- data/spec/jira/resource/sprint_spec.rb +88 -9
- data/spec/jira/resource/status_spec.rb +21 -0
- data/spec/jira/resource/user_factory_spec.rb +5 -5
- data/spec/jira/resource/worklog_spec.rb +4 -4
- data/spec/mock_responses/sprint/1.json +13 -0
- data/spec/mock_responses/status/1.json +8 -1
- data/spec/mock_responses/status.json +40 -5
- data/spec/mock_responses/statuscategory/1.json +7 -0
- data/spec/mock_responses/statuscategory.json +30 -0
- data/spec/mock_responses/{user_username=admin.json → user_accountId=1234567890abcdef01234567.json} +2 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/support/clients_helper.rb +3 -5
- data/spec/support/mock_client.rb +9 -0
- data/spec/support/mock_response.rb +8 -0
- data/spec/support/shared_examples/integration.rb +25 -28
- metadata +27 -260
- data/.travis.yml +0 -9
- data/example.rb +0 -232
- data/http-basic-example.rb +0 -113
- data/lib/jira/resource/sprint_report.rb +0 -8
- data/lib/jira/tasks.rb +0 -0
- data/spec/integration/webhook.rb +0 -25
- data/spec/jira/jwt_uri_builder_spec.rb +0 -59
data/lib/jira/http_client.rb
CHANGED
@@ -1,17 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
require 'net/https'
|
3
5
|
require 'cgi/cookie'
|
4
6
|
require 'uri'
|
5
7
|
|
6
8
|
module JIRA
|
9
|
+
# Client using HTTP Basic Authentication
|
10
|
+
# @example Basic authentication
|
11
|
+
# options = {
|
12
|
+
# auth_type: :basic,
|
13
|
+
# site: "https://jira.example.com",
|
14
|
+
# use_ssl: true,
|
15
|
+
# ssl_verify_mode: OpenSSL::SSL::VERIFY_PEER,
|
16
|
+
# cert_path: '/usr/local/etc/trusted-certificates.pem',
|
17
|
+
# username: 'jamie',
|
18
|
+
# password: 'password'
|
19
|
+
# }
|
20
|
+
# client = JIRA::Client.new(options)
|
21
|
+
# @example Bearer token authentication
|
22
|
+
# options = {
|
23
|
+
# auth_type: :basic,
|
24
|
+
# site: "https://jira.example.com",
|
25
|
+
# default_headers: { 'authorization' => "Bearer #{bearer_token_str}" },
|
26
|
+
# use_ssl: true,
|
27
|
+
# ssl_verify_mode: OpenSSL::SSL::VERIFY_PEER
|
28
|
+
# cert_path: '/usr/local/etc/trusted-certificates.pem',
|
29
|
+
# }
|
30
|
+
# client = JIRA::Client.new(options)
|
7
31
|
class HttpClient < RequestClient
|
32
|
+
# @private
|
8
33
|
DEFAULT_OPTIONS = {
|
9
34
|
username: nil,
|
10
35
|
password: nil
|
11
36
|
}.freeze
|
12
37
|
|
38
|
+
# @!attribute [r] options
|
39
|
+
# @return [Hash] The client options
|
13
40
|
attr_reader :options
|
14
41
|
|
42
|
+
# Generally not used directly, but through JIRA::Client.
|
43
|
+
# See JIRA::Client for documentation.
|
44
|
+
# @param [Hash] options Options as passed from JIRA::Client constructor.
|
45
|
+
# @option options [String] :username The username to authenticate with
|
46
|
+
# @option options [String] :password The password to authenticate with
|
47
|
+
# @option options [Hash] :default_headers Additional headers for requests
|
48
|
+
# @option options [String] :proxy_uri Proxy URI
|
49
|
+
# @option options [String] :proxy_user Proxy user
|
50
|
+
# @option options [String] :proxy_password Proxy Password
|
15
51
|
def initialize(options)
|
16
52
|
@options = DEFAULT_OPTIONS.merge(options)
|
17
53
|
@cookies = {}
|
@@ -21,9 +57,21 @@ module JIRA
|
|
21
57
|
body = { username: @options[:username].to_s, password: @options[:password].to_s }.to_json
|
22
58
|
@options.delete(:username)
|
23
59
|
@options.delete(:password)
|
24
|
-
make_request(:post, @options[:context_path]
|
60
|
+
make_request(:post, "#{@options[:context_path]}/rest/auth/1/session", body, 'Content-Type' => 'application/json')
|
25
61
|
end
|
26
62
|
|
63
|
+
# Makes a request to the JIRA server.
|
64
|
+
#
|
65
|
+
# Generally you should not call this method directly, but use the helper methods in JIRA::Client.
|
66
|
+
#
|
67
|
+
# File uploads are not supported with this method. Use make_multipart_request instead.
|
68
|
+
#
|
69
|
+
# @param [Symbol] http_method The HTTP method to use
|
70
|
+
# @param [String] url The JIRA REST URL to call
|
71
|
+
# @param [String] body The request body
|
72
|
+
# @param [Hash] headers Additional headers to send with the request
|
73
|
+
# @return [Net::HTTPResponse] The response from the server
|
74
|
+
# @raise [JIRA::HTTPError] If the response is not an HTTP success code
|
27
75
|
def make_request(http_method, url, body = '', headers = {})
|
28
76
|
# When a proxy is enabled, Net::HTTP expects that the request path omits the domain name
|
29
77
|
path = request_path(url)
|
@@ -33,6 +81,17 @@ module JIRA
|
|
33
81
|
execute_request(request)
|
34
82
|
end
|
35
83
|
|
84
|
+
# Makes a multipart request to the JIRA server.
|
85
|
+
#
|
86
|
+
# This is used for file uploads.
|
87
|
+
#
|
88
|
+
# Generally you should not call this method directly, but use the helper methods in JIRA::Client.
|
89
|
+
#
|
90
|
+
# @param [String] url The JIRA REST URL to call
|
91
|
+
# @param [Hash] body The Net::HTTP::Post::Multipart data to send with the request
|
92
|
+
# @param [Hash] headers The headers to send with the request
|
93
|
+
# @return [Net::HTTPResponse] The response object
|
94
|
+
# @raise [JIRA::HTTPError] If the response is not an HTTP success code
|
36
95
|
def make_multipart_request(url, body, headers = {})
|
37
96
|
path = request_path(url)
|
38
97
|
request = Net::HTTP::Post::Multipart.new(path, body, headers)
|
@@ -40,17 +99,20 @@ module JIRA
|
|
40
99
|
execute_request(request)
|
41
100
|
end
|
42
101
|
|
102
|
+
# @private
|
43
103
|
def basic_auth_http_conn
|
44
104
|
http_conn(uri)
|
45
105
|
end
|
46
106
|
|
107
|
+
# @private
|
47
108
|
def http_conn(uri)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
109
|
+
http_conn =
|
110
|
+
if @options[:proxy_address]
|
111
|
+
Net::HTTP.new(uri.host, uri.port, @options[:proxy_address], @options[:proxy_port] || 80,
|
112
|
+
@options[:proxy_username], @options[:proxy_password])
|
113
|
+
else
|
114
|
+
Net::HTTP.new(uri.host, uri.port)
|
115
|
+
end
|
54
116
|
http_conn.use_ssl = @options[:use_ssl]
|
55
117
|
if @options[:use_client_cert]
|
56
118
|
http_conn.cert = @options[:ssl_client_cert]
|
@@ -59,14 +121,19 @@ module JIRA
|
|
59
121
|
http_conn.verify_mode = @options[:ssl_verify_mode]
|
60
122
|
http_conn.ssl_version = @options[:ssl_version] if @options[:ssl_version]
|
61
123
|
http_conn.read_timeout = @options[:read_timeout]
|
124
|
+
http_conn.max_retries = @options[:max_retries] if @options[:max_retries]
|
62
125
|
http_conn.ca_file = @options[:ca_file] if @options[:ca_file]
|
63
126
|
http_conn
|
64
127
|
end
|
65
128
|
|
129
|
+
# The URI of the JIRA REST API call
|
130
|
+
# @return [URI] The URI of the JIRA REST API call
|
66
131
|
def uri
|
67
132
|
URI.parse(@options[:site])
|
68
133
|
end
|
69
134
|
|
135
|
+
# Returns true if the client is authenticated.
|
136
|
+
# @return [Boolean] True if the client is authenticated
|
70
137
|
def authenticated?
|
71
138
|
@authenticated
|
72
139
|
end
|
@@ -94,12 +161,12 @@ module JIRA
|
|
94
161
|
|
95
162
|
def store_cookies(response)
|
96
163
|
cookies = response.get_fields('set-cookie')
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
164
|
+
return unless cookies
|
165
|
+
|
166
|
+
cookies.each do |cookie|
|
167
|
+
data = CGI::Cookie.parse(cookie)
|
168
|
+
data.delete('Path')
|
169
|
+
@cookies.merge!(data)
|
103
170
|
end
|
104
171
|
end
|
105
172
|
|
data/lib/jira/http_error.rb
CHANGED
data/lib/jira/jwt_client.rb
CHANGED
@@ -1,67 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'atlassian/jwt'
|
2
4
|
|
3
5
|
module JIRA
|
4
6
|
class JwtClient < HttpClient
|
5
7
|
def make_request(http_method, url, body = '', headers = {})
|
6
8
|
@http_method = http_method
|
9
|
+
jwt_header = build_jwt_header(url)
|
7
10
|
|
8
|
-
super(http_method, url, body, headers)
|
11
|
+
super(http_method, url, body, headers.merge(jwt_header))
|
9
12
|
end
|
10
13
|
|
11
14
|
def make_multipart_request(url, data, headers = {})
|
12
15
|
@http_method = :post
|
16
|
+
jwt_header = build_jwt_header(url)
|
13
17
|
|
14
|
-
super(url, data, headers)
|
18
|
+
super(url, data, headers.merge(jwt_header))
|
15
19
|
end
|
16
20
|
|
17
|
-
|
18
|
-
attr_reader :request_url, :http_method, :shared_secret, :site, :issuer
|
19
|
-
|
20
|
-
def initialize(request_url, http_method, shared_secret, site, issuer)
|
21
|
-
@request_url = request_url
|
22
|
-
@http_method = http_method
|
23
|
-
@shared_secret = shared_secret
|
24
|
-
@site = site
|
25
|
-
@issuer = issuer
|
26
|
-
end
|
27
|
-
|
28
|
-
def build
|
29
|
-
uri = URI.parse(request_url)
|
30
|
-
new_query = URI.decode_www_form(String(uri.query)) << ['jwt', jwt_header]
|
31
|
-
uri.query = URI.encode_www_form(new_query)
|
32
|
-
|
33
|
-
return uri.to_s unless uri.is_a?(URI::HTTP)
|
34
|
-
|
35
|
-
uri.request_uri
|
36
|
-
end
|
21
|
+
private
|
37
22
|
|
38
|
-
|
23
|
+
attr_reader :http_method
|
39
24
|
|
40
|
-
|
41
|
-
|
42
|
-
issuer,
|
43
|
-
request_url,
|
44
|
-
http_method.to_s,
|
45
|
-
site,
|
46
|
-
(Time.now - 60).to_i,
|
47
|
-
(Time.now + 86_400).to_i
|
25
|
+
def build_jwt_header(url)
|
26
|
+
jwt = build_jwt(url)
|
48
27
|
|
49
|
-
|
50
|
-
end
|
28
|
+
{ 'Authorization' => "JWT #{jwt}" }
|
51
29
|
end
|
52
30
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
def request_path(url)
|
58
|
-
JwtUriBuilder.new(
|
31
|
+
def build_jwt(url)
|
32
|
+
claim = Atlassian::Jwt.build_claims \
|
33
|
+
@options[:issuer],
|
59
34
|
url,
|
60
35
|
http_method.to_s,
|
61
|
-
@options[:shared_secret],
|
62
36
|
@options[:site],
|
63
|
-
|
64
|
-
|
37
|
+
(Time.now - 60).to_i,
|
38
|
+
(Time.now + 86_400).to_i
|
39
|
+
|
40
|
+
JWT.encode claim, @options[:shared_secret]
|
65
41
|
end
|
66
42
|
end
|
67
43
|
end
|
data/lib/jira/oauth_client.rb
CHANGED
@@ -1,9 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'oauth'
|
2
4
|
require 'json'
|
3
5
|
require 'forwardable'
|
4
6
|
|
5
7
|
module JIRA
|
8
|
+
# Client using OAuth 1.0
|
9
|
+
#
|
10
|
+
# @!attribute [rw] consumer
|
11
|
+
# @return [OAuth::Consumer] The oauth consumer object
|
12
|
+
# @!attribute [r] options
|
13
|
+
# @return [Hash] The oauth connection options
|
14
|
+
# @!attribute [r] access_token
|
15
|
+
# @return [OAuth::AccessToken] The oauth access token
|
6
16
|
class OauthClient < RequestClient
|
17
|
+
# @private
|
7
18
|
DEFAULT_OPTIONS = {
|
8
19
|
signature_method: 'RSA-SHA1',
|
9
20
|
request_token_path: '/plugins/servlet/oauth/request-token',
|
@@ -29,11 +40,29 @@ module JIRA
|
|
29
40
|
|
30
41
|
def_instance_delegators :@consumer, :key, :secret, :get_request_token
|
31
42
|
|
43
|
+
# Generally not used directly, but through JIRA::Client.
|
44
|
+
# @param [Hash] options Options as passed from JIRA::Client constructor.
|
45
|
+
# @option options [String] :signature_method The signature method to use (defaults to 'RSA-SHA1')
|
46
|
+
# @option options [String] :request_token_path The path to request a token (defaults to '/plugins/servlet/oauth/request-token')
|
47
|
+
# @option options [String] :authorize_path The path to authorize a token (defaults to '/plugins/servlet/oauth/authorize')
|
48
|
+
# @option options [String] :access_token_path The path to access a token (defaults to '/plugins/servlet/oauth/access-token')
|
49
|
+
# @option options [String] :private_key_file The path to the private key file
|
50
|
+
# @option options [String] :consumer_key The OAuth 1.0 consumer key
|
51
|
+
# @option options [String] :consumer_secret The OAuth 1.0 consumer secret
|
52
|
+
# @option options [Hash] :default_headers Additional headers for requests
|
53
|
+
# @option options [String] :proxy_uri Proxy URI
|
54
|
+
# @option options [String] :proxy_user Proxy user
|
55
|
+
# @option options [String] :proxy_password Proxy Password
|
32
56
|
def initialize(options)
|
33
57
|
@options = DEFAULT_OPTIONS.merge(options)
|
34
58
|
@consumer = init_oauth_consumer(@options)
|
35
59
|
end
|
36
60
|
|
61
|
+
# @private
|
62
|
+
# Initialises the OAuth consumer object.
|
63
|
+
# Generally you should not call this method directly, it is called by the constructor.
|
64
|
+
# @param [Hash] _options The options hash
|
65
|
+
# @return [OAuth::Consumer] The OAuth consumer object
|
37
66
|
def init_oauth_consumer(_options)
|
38
67
|
@options[:request_token_path] = @options[:context_path] + @options[:request_token_path]
|
39
68
|
@options[:authorize_path] = @options[:context_path] + @options[:authorize_path]
|
@@ -45,22 +74,31 @@ module JIRA
|
|
45
74
|
|
46
75
|
# Returns the current request token if it is set, else it creates
|
47
76
|
# and sets a new token.
|
48
|
-
|
49
|
-
|
77
|
+
# @param [Hash] options
|
78
|
+
def request_token(options = {}, ...)
|
79
|
+
@request_token ||= get_request_token(options, ...)
|
50
80
|
end
|
51
81
|
|
52
82
|
# Sets the request token from a given token and secret.
|
83
|
+
# @param [String] token The request token
|
84
|
+
# @param [String] secret The request token secret
|
85
|
+
# @return [OAuth::RequestToken] The request token object
|
53
86
|
def set_request_token(token, secret)
|
54
87
|
@request_token = OAuth::RequestToken.new(@consumer, token, secret)
|
55
88
|
end
|
56
89
|
|
57
90
|
# Initialises and returns a new access token from the params hash
|
58
91
|
# returned by the OAuth transaction.
|
92
|
+
# @param [Hash] params The params hash returned by the OAuth transaction
|
93
|
+
# @return [OAuth::AccessToken] The access token object
|
59
94
|
def init_access_token(params)
|
60
95
|
@access_token = request_token.get_access_token(params)
|
61
96
|
end
|
62
97
|
|
63
98
|
# Sets the access token from a preexisting token and secret.
|
99
|
+
# @param [String] token The access token
|
100
|
+
# @param [String] secret The access token secret
|
101
|
+
# @return [OAuth::AccessToken] The access token object
|
64
102
|
def set_access_token(token, secret)
|
65
103
|
@access_token = OAuth::AccessToken.new(@consumer, token, secret)
|
66
104
|
@authenticated = true
|
@@ -69,11 +107,25 @@ module JIRA
|
|
69
107
|
|
70
108
|
# Returns the current access token. Raises an
|
71
109
|
# JIRA::Client::UninitializedAccessTokenError exception if it is not set.
|
110
|
+
# @return [OAuth::AccessToken] The access token object
|
72
111
|
def access_token
|
73
112
|
raise UninitializedAccessTokenError unless @access_token
|
113
|
+
|
74
114
|
@access_token
|
75
115
|
end
|
76
116
|
|
117
|
+
# Makes a request to the JIRA server using the oauth gem.
|
118
|
+
#
|
119
|
+
# Generally you should not call this method directly, but use the helper methods in JIRA::Client.
|
120
|
+
#
|
121
|
+
# File uploads are not supported with this method. Use make_multipart_request instead.
|
122
|
+
#
|
123
|
+
# @param [Symbol] http_method The HTTP method to use
|
124
|
+
# @param [String] url The JIRA REST URL to call
|
125
|
+
# @param [String] body The body of the request
|
126
|
+
# @param [Hash] headers The headers to send with the request
|
127
|
+
# @return [Net::HTTPResponse] The response object
|
128
|
+
# @raise [JIRA::HTTPError] If the response is not an HTTP success code
|
77
129
|
def make_request(http_method, url, body = '', headers = {})
|
78
130
|
# When using oauth_2legged we need to add an empty oauth_token parameter to every request.
|
79
131
|
if @options[:auth_type] == :oauth_2legged
|
@@ -82,7 +134,7 @@ module JIRA
|
|
82
134
|
uri.query = if uri.query.to_s == ''
|
83
135
|
oauth_params_str
|
84
136
|
else
|
85
|
-
uri.query
|
137
|
+
"#{uri.query}&#{oauth_params_str}"
|
86
138
|
end
|
87
139
|
url = uri.to_s
|
88
140
|
end
|
@@ -97,6 +149,17 @@ module JIRA
|
|
97
149
|
response
|
98
150
|
end
|
99
151
|
|
152
|
+
# Makes a multipart request to the JIRA server using the oauth gem.
|
153
|
+
#
|
154
|
+
# This is used for file uploads.
|
155
|
+
#
|
156
|
+
# Generally you should not call this method directly, but use the helper methods in JIRA::Client.
|
157
|
+
#
|
158
|
+
# @param [String] url The JIRA REST URL to call
|
159
|
+
# @param [Hash] data The Net::HTTP::Post::Multipart data to send with the request
|
160
|
+
# @param [Hash] headers The headers to send with the request
|
161
|
+
# @return [Net::HTTPResponse] The response object
|
162
|
+
# @raise [JIRA::HTTPError] If the response is not an HTTP success code
|
100
163
|
def make_multipart_request(url, data, headers = {})
|
101
164
|
request = Net::HTTP::Post::Multipart.new url, data, headers
|
102
165
|
|
@@ -107,6 +170,8 @@ module JIRA
|
|
107
170
|
response
|
108
171
|
end
|
109
172
|
|
173
|
+
# Returns true if the client is authenticated.
|
174
|
+
# @return [Boolean] True if the client is authenticated
|
110
175
|
def authenticated?
|
111
176
|
@authenticated
|
112
177
|
end
|
data/lib/jira/railtie.rb
CHANGED
data/lib/jira/request_client.rb
CHANGED
@@ -1,31 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'oauth'
|
2
4
|
require 'json'
|
3
5
|
require 'net/https'
|
4
6
|
|
5
7
|
module JIRA
|
8
|
+
# Base class for request clients specific to a particular authentication method.
|
6
9
|
class RequestClient
|
10
|
+
# Makes the JIRA REST API call.
|
11
|
+
#
|
7
12
|
# Returns the response if the request was successful (HTTP::2xx) and
|
8
13
|
# raises a JIRA::HTTPError if it was not successful, with the response
|
9
14
|
# attached.
|
10
|
-
|
15
|
+
#
|
16
|
+
# Generally you should not call this method directly, but use derived classes.
|
17
|
+
#
|
18
|
+
# File uploads are not supported with this method. Use request_multipart instead.
|
19
|
+
#
|
20
|
+
# @param [Array] args Arguments to pass to the request method
|
21
|
+
# @return [Net::HTTPResponse] The response from the server
|
22
|
+
# @raise [JIRA::HTTPError] if it was not successful
|
11
23
|
def request(*args)
|
12
24
|
response = make_request(*args)
|
13
25
|
raise HTTPError, response unless response.is_a?(Net::HTTPSuccess)
|
26
|
+
|
14
27
|
response
|
15
28
|
end
|
16
29
|
|
30
|
+
# Makes a multipart request to the JIRA server.
|
31
|
+
#
|
32
|
+
# This is used for file uploads.
|
33
|
+
#
|
34
|
+
# Generally you should not call this method directly, but use derived classes.
|
35
|
+
#
|
36
|
+
# @param [Array] args Arguments to pass to the request method
|
37
|
+
# @return [Net::HTTPResponse] The response from the server
|
38
|
+
# @raise [JIRA::HTTPError] if it was not successful
|
17
39
|
def request_multipart(*args)
|
18
40
|
response = make_multipart_request(*args)
|
19
41
|
raise HTTPError, response unless response.is_a?(Net::HTTPSuccess)
|
42
|
+
|
20
43
|
response
|
21
44
|
end
|
22
45
|
|
46
|
+
# Abstract method to make a request to the JIRA server.
|
47
|
+
# @abstract
|
48
|
+
# @param [Array] args Arguments to pass to the request method
|
23
49
|
def make_request(*args)
|
24
50
|
raise NotImplementedError
|
25
51
|
end
|
26
52
|
|
53
|
+
# Abstract method to make a request to the JIRA server with a file upload.
|
54
|
+
# @abstract
|
55
|
+
# @param [Array] args Arguments to pass to the request method
|
27
56
|
def make_multipart_request(*args)
|
28
57
|
raise NotImplementedError
|
29
58
|
end
|
30
59
|
end
|
31
|
-
end
|
60
|
+
end
|
data/lib/jira/resource/agile.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cgi'
|
2
4
|
|
3
5
|
module JIRA
|
@@ -25,7 +27,8 @@ module JIRA
|
|
25
27
|
response = client.get(path_base(client) + "/board/#{board_id}/issue?#{hash_to_query_string(options)}")
|
26
28
|
json = parse_json(response.body)
|
27
29
|
# To get Issue objects with the same structure as for Issue.all
|
28
|
-
return {} if json['issues'].
|
30
|
+
return {} if json['issues'].empty?
|
31
|
+
|
29
32
|
issue_ids = json['issues'].map do |issue|
|
30
33
|
issue['id']
|
31
34
|
end
|
@@ -58,22 +61,17 @@ module JIRA
|
|
58
61
|
parse_json(response.body)
|
59
62
|
end
|
60
63
|
|
61
|
-
# def self.find(client, key, options = {})
|
62
|
-
# options[:maxResults] ||= 100
|
63
|
-
# fields = options[:fields].join(',') unless options[:fields].nil?
|
64
|
-
# response = client.get("/rest/api/latest/search?jql=sprint=#{key}&fields=#{fields}&maxResults=#{options[:maxResults]}")
|
65
|
-
# parse_json(response.body)
|
66
|
-
# end
|
67
|
-
|
68
64
|
private
|
69
65
|
|
70
66
|
def self.path_base(client)
|
71
|
-
client.options[:context_path]
|
67
|
+
"#{client.options[:context_path]}/rest/agile/1.0"
|
72
68
|
end
|
73
69
|
|
74
70
|
def path_base(client)
|
75
71
|
self.class.path_base(client)
|
76
72
|
end
|
73
|
+
|
74
|
+
private_class_method :path_base
|
77
75
|
end
|
78
76
|
end
|
79
77
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JIRA
|
2
4
|
module Resource
|
3
5
|
class ApplicationLinkFactory < JIRA::BaseFactory # :nodoc:
|
@@ -5,7 +7,7 @@ module JIRA
|
|
5
7
|
end
|
6
8
|
|
7
9
|
class ApplicationLink < JIRA::Base
|
8
|
-
REST_BASE_PATH = '/rest/applinks/1.0'
|
10
|
+
REST_BASE_PATH = '/rest/applinks/1.0'
|
9
11
|
|
10
12
|
def self.endpoint_name
|
11
13
|
'listApplicationlinks'
|
@@ -24,12 +26,12 @@ module JIRA
|
|
24
26
|
json = parse_json(response.body)
|
25
27
|
json = json['list']
|
26
28
|
json.map do |attrs|
|
27
|
-
new(client, { attrs:
|
29
|
+
new(client, { attrs: }.merge(options))
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
31
33
|
def self.manifest(client)
|
32
|
-
url = full_url(client)
|
34
|
+
url = "#{full_url(client)}/manifest"
|
33
35
|
response = client.get(url)
|
34
36
|
json = parse_json(response.body)
|
35
37
|
JIRA::Base.new(client, attrs: json)
|