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/base.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support/core_ext/string'
|
2
4
|
require 'active_support/inflector'
|
3
5
|
require 'set'
|
@@ -81,8 +83,8 @@ module JIRA
|
|
81
83
|
if options[relation]
|
82
84
|
instance_variable_set("@#{relation}", options[relation])
|
83
85
|
instance_variable_set("@#{relation}_id", options[relation].key_value)
|
84
|
-
elsif options["#{relation}_id"
|
85
|
-
instance_variable_set("@#{relation}_id", options["#{relation}_id"
|
86
|
+
elsif options[:"#{relation}_id"]
|
87
|
+
instance_variable_set("@#{relation}_id", options[:"#{relation}_id"])
|
86
88
|
else
|
87
89
|
raise ArgumentError, "Required option #{relation.inspect} missing" unless options[relation]
|
88
90
|
end
|
@@ -96,7 +98,7 @@ module JIRA
|
|
96
98
|
json = parse_json(response.body)
|
97
99
|
json = json[endpoint_name.pluralize] if collection_attributes_are_nested
|
98
100
|
json.map do |attrs|
|
99
|
-
new(client, { attrs:
|
101
|
+
new(client, { attrs: }.merge(options))
|
100
102
|
end
|
101
103
|
end
|
102
104
|
|
@@ -111,7 +113,7 @@ module JIRA
|
|
111
113
|
# Builds a new instance of the resource with the given attributes.
|
112
114
|
# These attributes will be posted to the JIRA Api if save is called.
|
113
115
|
def self.build(client, attrs)
|
114
|
-
new(client, attrs:
|
116
|
+
new(client, attrs:)
|
115
117
|
end
|
116
118
|
|
117
119
|
# Returns the name of this resource for use in URL components.
|
@@ -141,7 +143,7 @@ module JIRA
|
|
141
143
|
# JIRA::Resource::Comment.singular_path('456','/issue/123/')
|
142
144
|
# # => /jira/rest/api/2/issue/123/comment/456
|
143
145
|
def self.singular_path(client, key, prefix = '/')
|
144
|
-
collection_path(client, prefix)
|
146
|
+
"#{collection_path(client, prefix)}/#{key}"
|
145
147
|
end
|
146
148
|
|
147
149
|
# Returns the attribute name of the attribute used for find.
|
@@ -193,10 +195,11 @@ module JIRA
|
|
193
195
|
# # => Looks for {"foo":{"bar":{"baz":{"child":{}}}}}
|
194
196
|
def self.has_one(resource, options = {})
|
195
197
|
attribute_key = options[:attribute_key] || resource.to_s
|
196
|
-
child_class = options[:class] ||
|
198
|
+
child_class = options[:class] || "JIRA::Resource::#{resource.to_s.classify}".constantize
|
197
199
|
define_method(resource) do
|
198
200
|
attribute = maybe_nested_attribute(attribute_key, options[:nested_under])
|
199
201
|
return nil unless attribute
|
202
|
+
|
200
203
|
child_class.new(client, attrs: attribute)
|
201
204
|
end
|
202
205
|
end
|
@@ -244,7 +247,7 @@ module JIRA
|
|
244
247
|
# # => Looks for {"foo":{"bar":{"baz":{"children":{}}}}}
|
245
248
|
def self.has_many(collection, options = {})
|
246
249
|
attribute_key = options[:attribute_key] || collection.to_s
|
247
|
-
child_class = options[:class] ||
|
250
|
+
child_class = options[:class] || "JIRA::Resource::#{collection.to_s.classify}".constantize
|
248
251
|
self_class_basename = name.split('::').last.downcase.to_sym
|
249
252
|
define_method(collection) do
|
250
253
|
child_class_options = { self_class_basename => self }
|
@@ -288,11 +291,7 @@ module JIRA
|
|
288
291
|
# and returns true when found, otherwise proxies the
|
289
292
|
# call to the superclass.
|
290
293
|
def respond_to?(method_name, _include_all = false)
|
291
|
-
|
292
|
-
true
|
293
|
-
else
|
294
|
-
super(method_name)
|
295
|
-
end
|
294
|
+
attrs.key?(method_name.to_s) || super(method_name)
|
296
295
|
end
|
297
296
|
|
298
297
|
# Overrides method_missing to check the attribute hash
|
@@ -322,7 +321,7 @@ module JIRA
|
|
322
321
|
# issue it returns '/issue'
|
323
322
|
def path_component
|
324
323
|
path_component = "/#{self.class.endpoint_name}"
|
325
|
-
path_component +=
|
324
|
+
path_component += "/#{key_value}" if key_value
|
326
325
|
path_component
|
327
326
|
end
|
328
327
|
|
@@ -331,6 +330,7 @@ module JIRA
|
|
331
330
|
# is not set
|
332
331
|
def fetch(reload = false, query_params = {})
|
333
332
|
return if expanded? && !reload
|
333
|
+
|
334
334
|
response = client.get(url_with_query_params(url, query_params))
|
335
335
|
set_attrs_from_response(response)
|
336
336
|
@expanded = true
|
@@ -359,14 +359,14 @@ module JIRA
|
|
359
359
|
def save(attrs, path = url)
|
360
360
|
begin
|
361
361
|
save_status = save!(attrs, path)
|
362
|
-
rescue JIRA::HTTPError =>
|
362
|
+
rescue JIRA::HTTPError => e
|
363
363
|
begin
|
364
|
-
set_attrs_from_response(
|
365
|
-
rescue JSON::ParserError
|
364
|
+
set_attrs_from_response(e.response) # Merge error status generated by JIRA REST API
|
365
|
+
rescue JSON::ParserError
|
366
366
|
set_attrs('exception' => {
|
367
|
-
'class' =>
|
368
|
-
'code' =>
|
369
|
-
'message' =>
|
367
|
+
'class' => e.response.class.name,
|
368
|
+
'code' => e.response.code,
|
369
|
+
'message' => e.response.message
|
370
370
|
})
|
371
371
|
end
|
372
372
|
# raise exception
|
@@ -378,10 +378,10 @@ module JIRA
|
|
378
378
|
# Sets the attributes hash from a HTTPResponse object from JIRA if it is
|
379
379
|
# not nil or is not a json response.
|
380
380
|
def set_attrs_from_response(response)
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
381
|
+
return if response.body.nil? || (response.body.length < 2)
|
382
|
+
|
383
|
+
json = self.class.parse_json(response.body)
|
384
|
+
set_attrs(json)
|
385
385
|
end
|
386
386
|
|
387
387
|
# Set the current attributes from a hash. If clobber is true, any existing
|
@@ -419,7 +419,7 @@ module JIRA
|
|
419
419
|
prefix = '/'
|
420
420
|
unless self.class.belongs_to_relationships.empty?
|
421
421
|
prefix = self.class.belongs_to_relationships.inject(prefix) do |prefix_so_far, relationship|
|
422
|
-
prefix_so_far
|
422
|
+
"#{prefix_so_far}#{relationship}/#{send("#{relationship}_id")}/"
|
423
423
|
end
|
424
424
|
end
|
425
425
|
if @attrs['self']
|
@@ -434,7 +434,8 @@ module JIRA
|
|
434
434
|
end
|
435
435
|
|
436
436
|
# This method fixes issue that there is no / prefix in url. It is happened when we call for instance
|
437
|
-
# Looks like this issue is actual only in case if you use atlassian sdk your app
|
437
|
+
# Looks like this issue is actual only in case if you use atlassian sdk your app pathis not root
|
438
|
+
# (like /jira in example below)
|
438
439
|
# issue.save() for existing resource.
|
439
440
|
# As a result we got error 400 from JIRA API:
|
440
441
|
# [07/Jun/2015:15:32:19 +0400] "PUT jira/rest/api/2/issue/10111 HTTP/1.1" 400 -
|
@@ -443,6 +444,7 @@ module JIRA
|
|
443
444
|
def patched_url
|
444
445
|
result = url
|
445
446
|
return result if result.start_with?('/', 'http')
|
447
|
+
|
446
448
|
"/#{result}"
|
447
449
|
end
|
448
450
|
|
@@ -476,15 +478,18 @@ module JIRA
|
|
476
478
|
|
477
479
|
def self.maybe_nested_attribute(attributes, attribute_name, nested_under = nil)
|
478
480
|
return attributes[attribute_name] if nested_under.nil?
|
481
|
+
|
479
482
|
if nested_under.instance_of? Array
|
480
483
|
final = nested_under.inject(attributes) do |parent, key|
|
481
484
|
break if parent.nil?
|
485
|
+
|
482
486
|
parent[key]
|
483
487
|
end
|
484
488
|
return nil if final.nil?
|
489
|
+
|
485
490
|
final[attribute_name]
|
486
491
|
else
|
487
|
-
|
492
|
+
attributes[nested_under][attribute_name]
|
488
493
|
end
|
489
494
|
end
|
490
495
|
|
@@ -493,10 +498,10 @@ module JIRA
|
|
493
498
|
end
|
494
499
|
|
495
500
|
def self.url_with_query_params(url, query_params)
|
496
|
-
if
|
497
|
-
"#{url}?#{hash_to_query_string query_params}"
|
498
|
-
else
|
501
|
+
if query_params.empty?
|
499
502
|
url
|
503
|
+
else
|
504
|
+
"#{url}?#{hash_to_query_string query_params}"
|
500
505
|
end
|
501
506
|
end
|
502
507
|
|
@@ -506,20 +511,16 @@ module JIRA
|
|
506
511
|
|
507
512
|
def self.hash_to_query_string(query_params)
|
508
513
|
query_params.map do |k, v|
|
509
|
-
CGI.escape(k.to_s)
|
514
|
+
"#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
|
510
515
|
end.join('&')
|
511
516
|
end
|
512
517
|
|
513
518
|
def self.query_params_for_single_fetch(options)
|
514
|
-
|
515
|
-
QUERY_PARAMS_FOR_SINGLE_FETCH.include? k
|
516
|
-
end]
|
519
|
+
options.slice(*QUERY_PARAMS_FOR_SINGLE_FETCH)
|
517
520
|
end
|
518
521
|
|
519
522
|
def self.query_params_for_search(options)
|
520
|
-
|
521
|
-
QUERY_PARAMS_FOR_SEARCH.include? k
|
522
|
-
end]
|
523
|
+
options.slice(*QUERY_PARAMS_FOR_SEARCH)
|
523
524
|
end
|
524
525
|
end
|
525
526
|
end
|
data/lib/jira/base_factory.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JIRA
|
2
4
|
# This is the base class for all the JIRA resource factory instances.
|
3
5
|
class BaseFactory
|
@@ -36,7 +38,8 @@ module JIRA
|
|
36
38
|
# The principle purpose of this class is to delegate methods to the corresponding
|
37
39
|
# non-factory class and automatically prepend the client argument to the argument
|
38
40
|
# list.
|
39
|
-
delegate_to_target_class :all, :find, :collection_path, :singular_path, :jql, :get_backlog_issues,
|
41
|
+
delegate_to_target_class :all, :find, :collection_path, :singular_path, :jql, :get_backlog_issues,
|
42
|
+
:get_board_issues, :get_sprints, :get_sprint_issues, :get_projects, :get_projects_full
|
40
43
|
|
41
44
|
# This method needs special handling as it has a default argument value
|
42
45
|
def build(attrs = {})
|
data/lib/jira/client.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
require 'forwardable'
|
3
|
-
require 'ostruct'
|
4
5
|
|
5
6
|
module JIRA
|
6
7
|
# This class is the main access point for all JIRA::Resource instances.
|
@@ -34,6 +35,7 @@ module JIRA
|
|
34
35
|
# :default_headers => {},
|
35
36
|
# :use_client_cert => false,
|
36
37
|
# :read_timeout => nil,
|
38
|
+
# :max_retries => nil,
|
37
39
|
# :http_debug => false,
|
38
40
|
# :shared_secret => nil,
|
39
41
|
# :cert_path => nil,
|
@@ -52,48 +54,50 @@ module JIRA
|
|
52
54
|
#
|
53
55
|
# The authenticated client instance returned by the respective client type
|
54
56
|
# (Oauth, Basic)
|
55
|
-
attr_accessor :consumer, :request_client, :http_debug, :
|
57
|
+
attr_accessor :consumer, :request_client, :http_debug, :field_map_cache
|
56
58
|
|
57
59
|
# The configuration options for this client instance
|
58
60
|
attr_reader :options
|
59
61
|
|
60
|
-
def_delegators :@request_client, :init_access_token, :set_access_token, :set_request_token, :request_token,
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
62
|
+
def_delegators :@request_client, :init_access_token, :set_access_token, :set_request_token, :request_token,
|
63
|
+
:access_token, :authenticated?
|
64
|
+
|
65
|
+
DEFINED_OPTIONS = %i[
|
66
|
+
site
|
67
|
+
context_path
|
68
|
+
signature_method
|
69
|
+
request_token_path
|
70
|
+
authorize_path
|
71
|
+
access_token_path
|
72
|
+
private_key
|
73
|
+
private_key_file
|
74
|
+
rest_base_path
|
75
|
+
consumer_key
|
76
|
+
consumer_secret
|
77
|
+
ssl_verify_mode
|
78
|
+
ssl_version
|
79
|
+
use_ssl
|
80
|
+
username
|
81
|
+
password
|
82
|
+
auth_type
|
83
|
+
proxy_address
|
84
|
+
proxy_port
|
85
|
+
proxy_username
|
86
|
+
proxy_password
|
87
|
+
use_cookies
|
88
|
+
additional_cookies
|
89
|
+
default_headers
|
90
|
+
use_client_cert
|
91
|
+
read_timeout
|
92
|
+
max_retries
|
93
|
+
http_debug
|
94
|
+
issuer
|
95
|
+
base_url
|
96
|
+
shared_secret
|
97
|
+
cert_path
|
98
|
+
key_path
|
99
|
+
ssl_client_cert
|
100
|
+
ssl_client_key
|
97
101
|
].freeze
|
98
102
|
|
99
103
|
DEFAULT_OPTIONS = {
|
@@ -108,6 +112,23 @@ module JIRA
|
|
108
112
|
default_headers: {}
|
109
113
|
}.freeze
|
110
114
|
|
115
|
+
# Creates a new JIRA::Client instance
|
116
|
+
# @param [Hash] options The configuration options for the client
|
117
|
+
# @option options [Symbol] :auth_type The authentication type to use, :basic, :oauth, :oauth_2legged, or :cookie.
|
118
|
+
# @option options [String] :site The base URL for the JIRA instance
|
119
|
+
# @option options [Boolean] :use_ssl Whether to use HTTPS for requests
|
120
|
+
# @option options [Integer] :ssl_verify_mode The SSL verification mode OpenSSL::SSL::VERIFY_PEER or OpenSSL::SSL::VERIFY_NONE
|
121
|
+
# @option options [Hash] :default_headers Additional headers to send with each request
|
122
|
+
# @option options [String] :cert_path The path to the SSL certificate file to verify the server with
|
123
|
+
# @option options [String] :use_client_cert Whether to use a client certificate for authentication
|
124
|
+
# @option options [String] :ssl_client_cert The client certificate to use
|
125
|
+
# @option options [String] :ssl_client_key The client certificate key to use
|
126
|
+
# @option options [String] :proxy_address The address of the proxy server to use
|
127
|
+
# @option options [Integer] :proxy_port The port of the proxy server to use
|
128
|
+
# @option options [String] :proxy_username The username for the proxy server
|
129
|
+
# @option options [String] :proxy_password The password for the proxy server
|
130
|
+
# @return [JIRA::Client] The client instance
|
131
|
+
# @raise [ArgumentError] If an unknown option is given
|
111
132
|
def initialize(options = {})
|
112
133
|
options = DEFAULT_OPTIONS.merge(options)
|
113
134
|
@options = options
|
@@ -117,11 +138,20 @@ module JIRA
|
|
117
138
|
raise ArgumentError, "Unknown option(s) given: #{unknown_options}" unless unknown_options.empty?
|
118
139
|
|
119
140
|
if options[:use_client_cert]
|
120
|
-
|
141
|
+
if @options[:cert_path]
|
142
|
+
@options[:ssl_client_cert] =
|
143
|
+
OpenSSL::X509::Certificate.new(File.read(@options[:cert_path]))
|
144
|
+
end
|
121
145
|
@options[:ssl_client_key] = OpenSSL::PKey::RSA.new(File.read(@options[:key_path])) if @options[:key_path]
|
122
146
|
|
123
|
-
|
124
|
-
|
147
|
+
unless @options[:ssl_client_cert]
|
148
|
+
raise ArgumentError,
|
149
|
+
'Options: :cert_path or :ssl_client_cert must be set when :use_client_cert is true'
|
150
|
+
end
|
151
|
+
unless @options[:ssl_client_key]
|
152
|
+
raise ArgumentError,
|
153
|
+
'Options: :key_path or :ssl_client_key must be set when :use_client_cert is true'
|
154
|
+
end
|
125
155
|
end
|
126
156
|
|
127
157
|
case options[:auth_type]
|
@@ -133,7 +163,11 @@ module JIRA
|
|
133
163
|
when :basic
|
134
164
|
@request_client = HttpClient.new(@options)
|
135
165
|
when :cookie
|
136
|
-
|
166
|
+
if @options.key?(:use_cookies) && !@options[:use_cookies]
|
167
|
+
raise ArgumentError,
|
168
|
+
'Options: :use_cookies must be true for :cookie authorization type'
|
169
|
+
end
|
170
|
+
|
137
171
|
@options[:use_cookies] = true
|
138
172
|
@request_client = HttpClient.new(@options)
|
139
173
|
@request_client.make_cookie_auth_request
|
@@ -146,8 +180,6 @@ module JIRA
|
|
146
180
|
@http_debug = @options[:http_debug]
|
147
181
|
|
148
182
|
@options.freeze
|
149
|
-
|
150
|
-
@cache = OpenStruct.new
|
151
183
|
end
|
152
184
|
|
153
185
|
def Project # :nodoc:
|
@@ -182,6 +214,10 @@ module JIRA
|
|
182
214
|
JIRA::Resource::StatusFactory.new(self)
|
183
215
|
end
|
184
216
|
|
217
|
+
def StatusCategory # :nodoc:
|
218
|
+
JIRA::Resource::StatusCategoryFactory.new(self)
|
219
|
+
end
|
220
|
+
|
185
221
|
def Resolution # :nodoc:
|
186
222
|
JIRA::Resource::ResolutionFactory.new(self)
|
187
223
|
end
|
@@ -226,10 +262,6 @@ module JIRA
|
|
226
262
|
JIRA::Resource::SprintFactory.new(self)
|
227
263
|
end
|
228
264
|
|
229
|
-
def SprintReport
|
230
|
-
JIRA::Resource::SprintReportFactory.new(self)
|
231
|
-
end
|
232
|
-
|
233
265
|
def ServerInfo
|
234
266
|
JIRA::Resource::ServerInfoFactory.new(self)
|
235
267
|
end
|
@@ -271,29 +303,63 @@ module JIRA
|
|
271
303
|
end
|
272
304
|
|
273
305
|
# HTTP methods without a body
|
306
|
+
|
307
|
+
# Make an HTTP DELETE request
|
308
|
+
# @param [String] path The path to request
|
309
|
+
# @param [Hash] headers The headers to send with the request
|
310
|
+
# @return [Net::HTTPResponse] The response object
|
311
|
+
# @raise [JIRA::HTTPError] If the response is not an HTTP success code
|
274
312
|
def delete(path, headers = {})
|
275
313
|
request(:delete, path, nil, merge_default_headers(headers))
|
276
314
|
end
|
277
315
|
|
316
|
+
# Make an HTTP GET request
|
317
|
+
# @param [String] path The path to request
|
318
|
+
# @param [Hash] headers The headers to send with the request
|
319
|
+
# @return [Net::HTTPResponse] The response object
|
320
|
+
# @raise [JIRA::HTTPError] If the response is not an HTTP success code
|
278
321
|
def get(path, headers = {})
|
279
322
|
request(:get, path, nil, merge_default_headers(headers))
|
280
323
|
end
|
281
324
|
|
325
|
+
# Make an HTTP HEAD request
|
326
|
+
# @param [String] path The path to request
|
327
|
+
# @param [Hash] headers The headers to send with the request
|
328
|
+
# @return [Net::HTTPResponse] The response object
|
329
|
+
# @raise [JIRA::HTTPError] If the response is not an HTTP success code
|
282
330
|
def head(path, headers = {})
|
283
331
|
request(:head, path, nil, merge_default_headers(headers))
|
284
332
|
end
|
285
333
|
|
286
334
|
# HTTP methods with a body
|
335
|
+
|
336
|
+
# Make an HTTP POST request
|
337
|
+
# @param [String] path The path to request
|
338
|
+
# @param [String] body The body of the request
|
339
|
+
# @param [Hash] headers The headers to send with the request
|
340
|
+
# @return [Net::HTTPResponse] The response object
|
287
341
|
def post(path, body = '', headers = {})
|
288
342
|
headers = { 'Content-Type' => 'application/json' }.merge(headers)
|
289
343
|
request(:post, path, body, merge_default_headers(headers))
|
290
344
|
end
|
291
345
|
|
346
|
+
# Make an HTTP POST request with a file upload
|
347
|
+
# @param [String] path The path to request
|
348
|
+
# @param [String] file The file to upload
|
349
|
+
# @param [Hash] headers The headers to send with the request
|
350
|
+
# @return [Net::HTTPResponse] The response object
|
351
|
+
# @raise [JIRA::HTTPError] If the response is not an HTTP success code
|
292
352
|
def post_multipart(path, file, headers = {})
|
293
353
|
puts "post multipart: #{path} - [#{file}]" if @http_debug
|
294
|
-
@request_client.request_multipart(path, file, headers)
|
354
|
+
@request_client.request_multipart(path, file, merge_default_headers(headers))
|
295
355
|
end
|
296
356
|
|
357
|
+
# Make an HTTP PUT request
|
358
|
+
# @param [String] path The path to request
|
359
|
+
# @param [String] body The body of the request
|
360
|
+
# @param [Hash] headers The headers to send with the request
|
361
|
+
# @return [Net::HTTPResponse] The response object
|
362
|
+
# @raise [JIRA::HTTPError] If the response is not an HTTP success code
|
297
363
|
def put(path, body = '', headers = {})
|
298
364
|
headers = { 'Content-Type' => 'application/json' }.merge(headers)
|
299
365
|
request(:put, path, body, merge_default_headers(headers))
|
@@ -301,11 +367,18 @@ module JIRA
|
|
301
367
|
|
302
368
|
# Sends the specified HTTP request to the REST API through the
|
303
369
|
# appropriate method (oauth, basic).
|
370
|
+
# @param [Symbol] http_method The HTTP method to use
|
371
|
+
# @param [String] path The path to request
|
372
|
+
# @param [String] body The body of the request
|
373
|
+
# @param [Hash] headers The headers to send with the request
|
374
|
+
# @return [Net::HTTPResponse] The response object
|
375
|
+
# @raise [JIRA::HTTPError] If the response is not an HTTP success code
|
304
376
|
def request(http_method, path, body = '', headers = {})
|
305
377
|
puts "#{http_method}: #{path} - [#{body}]" if @http_debug
|
306
378
|
@request_client.request(http_method, path, body, headers)
|
307
379
|
end
|
308
380
|
|
381
|
+
# @private
|
309
382
|
# Stops sensitive client information from being displayed in logs
|
310
383
|
def inspect
|
311
384
|
"#<JIRA::Client:#{object_id}>"
|
data/lib/jira/has_many_proxy.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
#
|
2
4
|
# Whenever a collection from a has_many relationship is accessed, an instance
|
3
5
|
# of this class is returned. This instance wraps the Array of instances in
|
@@ -6,37 +8,39 @@
|
|
6
8
|
#
|
7
9
|
# In practice, instances of this class behave exactly like an Array.
|
8
10
|
#
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
module JIRA
|
12
|
+
class HasManyProxy
|
13
|
+
attr_reader :target_class, :parent
|
14
|
+
attr_accessor :collection
|
12
15
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
def initialize(parent, target_class, collection = [])
|
17
|
+
@parent = parent
|
18
|
+
@target_class = target_class
|
19
|
+
@collection = collection
|
20
|
+
end
|
18
21
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
22
|
+
# Builds an instance of this class with the correct parent.
|
23
|
+
# For example, issue.comments.build(attrs) will initialize a
|
24
|
+
# comment as follows:
|
25
|
+
#
|
26
|
+
# JIRA::Resource::Comment.new(issue.client,
|
27
|
+
# :attrs => attrs,
|
28
|
+
# :issue => issue)
|
29
|
+
def build(attrs = {})
|
30
|
+
resource = target_class.new(parent.client, :attrs => attrs, parent.to_sym => parent)
|
31
|
+
collection << resource
|
32
|
+
resource
|
33
|
+
end
|
31
34
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
# Forces an HTTP request to fetch all instances of the target class that
|
36
|
+
# are associated with the parent
|
37
|
+
def all
|
38
|
+
target_class.all(parent.client, parent.to_sym => parent)
|
39
|
+
end
|
37
40
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
+
# Delegate any missing methods to the collection that this proxy wraps
|
42
|
+
def method_missing(method_name, ...)
|
43
|
+
collection.send(method_name, ...)
|
44
|
+
end
|
41
45
|
end
|
42
46
|
end
|