jira-ruby 1.2.0 → 2.3.0
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 +5 -5
- data/.gitignore +3 -0
- data/.travis.yml +5 -3
- data/Gemfile +7 -1
- data/Guardfile +1 -1
- data/README.md +452 -0
- data/Rakefile +6 -7
- data/example.rb +23 -1
- data/http-basic-example.rb +13 -12
- data/jira-ruby.gemspec +13 -13
- data/lib/jira/base.rb +53 -52
- data/lib/jira/base_factory.rb +3 -6
- data/lib/jira/client.rb +127 -30
- data/lib/jira/has_many_proxy.rb +0 -1
- data/lib/jira/http_client.rb +54 -16
- data/lib/jira/http_error.rb +3 -5
- data/lib/jira/jwt_client.rb +67 -0
- data/lib/jira/oauth_client.rb +47 -17
- data/lib/jira/request_client.rb +16 -5
- data/lib/jira/resource/agile.rb +34 -9
- data/lib/jira/resource/applinks.rb +5 -8
- data/lib/jira/resource/attachment.rb +41 -3
- data/lib/jira/resource/board.rb +91 -0
- data/lib/jira/resource/board_configuration.rb +9 -0
- data/lib/jira/resource/comment.rb +0 -2
- data/lib/jira/resource/component.rb +1 -3
- data/lib/jira/resource/createmeta.rb +12 -14
- data/lib/jira/resource/field.rb +22 -22
- data/lib/jira/resource/filter.rb +2 -2
- data/lib/jira/resource/issue.rb +69 -38
- data/lib/jira/resource/issue_picker_suggestions.rb +24 -0
- data/lib/jira/resource/issue_picker_suggestions_issue.rb +10 -0
- data/lib/jira/resource/issuelink.rb +3 -5
- data/lib/jira/resource/issuelinktype.rb +0 -1
- data/lib/jira/resource/issuetype.rb +1 -3
- data/lib/jira/resource/priority.rb +1 -3
- data/lib/jira/resource/project.rb +5 -7
- data/lib/jira/resource/rapidview.rb +28 -7
- data/lib/jira/resource/remotelink.rb +1 -4
- data/lib/jira/resource/resolution.rb +2 -4
- data/lib/jira/resource/serverinfo.rb +1 -2
- data/lib/jira/resource/sprint.rb +86 -17
- data/lib/jira/resource/sprint_report.rb +8 -0
- data/lib/jira/resource/status.rb +1 -3
- data/lib/jira/resource/suggested_issue.rb +9 -0
- data/lib/jira/resource/transition.rb +2 -6
- data/lib/jira/resource/user.rb +12 -2
- data/lib/jira/resource/version.rb +1 -3
- data/lib/jira/resource/watcher.rb +35 -0
- data/lib/jira/resource/webhook.rb +3 -6
- data/lib/jira/resource/worklog.rb +3 -5
- data/lib/jira/version.rb +1 -1
- data/lib/jira-ruby.rb +12 -2
- data/lib/tasks/generate.rake +4 -4
- data/spec/integration/attachment_spec.rb +17 -8
- data/spec/integration/comment_spec.rb +31 -34
- data/spec/integration/component_spec.rb +21 -24
- data/spec/integration/field_spec.rb +15 -18
- data/spec/integration/issue_spec.rb +45 -46
- data/spec/integration/issuelinktype_spec.rb +8 -11
- data/spec/integration/issuetype_spec.rb +5 -7
- data/spec/integration/priority_spec.rb +5 -8
- data/spec/integration/project_spec.rb +13 -20
- data/spec/integration/rapidview_spec.rb +17 -10
- data/spec/integration/resolution_spec.rb +7 -10
- data/spec/integration/status_spec.rb +5 -8
- data/spec/integration/transition_spec.rb +17 -20
- data/spec/integration/user_spec.rb +24 -8
- data/spec/integration/version_spec.rb +21 -25
- data/spec/integration/watcher_spec.rb +62 -0
- data/spec/integration/webhook.rb +8 -17
- data/spec/integration/worklog_spec.rb +30 -34
- data/spec/jira/base_factory_spec.rb +11 -12
- data/spec/jira/base_spec.rb +216 -229
- data/spec/jira/client_spec.rb +227 -159
- data/spec/jira/has_many_proxy_spec.rb +11 -12
- data/spec/jira/http_client_spec.rb +254 -31
- data/spec/jira/http_error_spec.rb +7 -9
- data/spec/jira/jwt_uri_builder_spec.rb +59 -0
- data/spec/jira/oauth_client_spec.rb +110 -39
- data/spec/jira/request_client_spec.rb +36 -9
- data/spec/jira/resource/agile_spec.rb +135 -0
- data/spec/jira/resource/attachment_spec.rb +127 -9
- data/spec/jira/resource/board_spec.rb +224 -0
- data/spec/jira/resource/createmeta_spec.rb +29 -32
- data/spec/jira/resource/field_spec.rb +42 -48
- data/spec/jira/resource/filter_spec.rb +40 -40
- data/spec/jira/resource/issue_picker_suggestions_spec.rb +79 -0
- data/spec/jira/resource/issue_spec.rb +88 -85
- data/spec/jira/resource/issuelink_spec.rb +1 -1
- data/spec/jira/resource/jira_picker_suggestions_issue_spec.rb +18 -0
- data/spec/jira/resource/project_factory_spec.rb +2 -4
- data/spec/jira/resource/project_spec.rb +33 -33
- data/spec/jira/resource/sprint_spec.rb +90 -0
- data/spec/jira/resource/user_factory_spec.rb +6 -8
- data/spec/jira/resource/worklog_spec.rb +9 -11
- data/spec/mock_responses/board/1.json +33 -0
- data/spec/mock_responses/board/1_issues.json +62 -0
- data/spec/mock_responses/empty_issues.json +8 -0
- data/spec/mock_responses/issue/10002/watchers.json +13 -0
- data/spec/mock_responses/issue.json +1 -1
- data/spec/mock_responses/sprint/1_issues.json +125 -0
- data/spec/spec_helper.rb +8 -9
- data/spec/support/clients_helper.rb +4 -4
- data/spec/support/shared_examples/integration.rb +60 -77
- metadata +115 -55
- data/.ruby-version +0 -1
- data/README.rdoc +0 -333
- /data/spec/mock_responses/{attachment → issue/10002/attachments}/10000.json +0 -0
data/lib/jira/base.rb
CHANGED
@@ -3,7 +3,6 @@ require 'active_support/inflector'
|
|
3
3
|
require 'set'
|
4
4
|
|
5
5
|
module JIRA
|
6
|
-
|
7
6
|
# This class provides the basic object <-> REST mapping for all JIRA::Resource subclasses,
|
8
7
|
# i.e. the Create, Retrieve, Update, Delete lifecycle methods.
|
9
8
|
#
|
@@ -51,8 +50,8 @@ module JIRA
|
|
51
50
|
# new_comment = issue.comments.build
|
52
51
|
#
|
53
52
|
class Base
|
54
|
-
QUERY_PARAMS_FOR_SINGLE_FETCH = Set.new [
|
55
|
-
QUERY_PARAMS_FOR_SEARCH = Set.new [
|
53
|
+
QUERY_PARAMS_FOR_SINGLE_FETCH = Set.new %i[expand fields]
|
54
|
+
QUERY_PARAMS_FOR_SEARCH = Set.new %i[expand fields startAt maxResults]
|
56
55
|
|
57
56
|
# A reference to the JIRA::Client used to initialize this resource.
|
58
57
|
attr_reader :client
|
@@ -67,8 +66,8 @@ module JIRA
|
|
67
66
|
# representation of the JSON returned from the JIRA API
|
68
67
|
attr_accessor :attrs
|
69
68
|
|
70
|
-
alias
|
71
|
-
alias
|
69
|
+
alias expanded? expanded
|
70
|
+
alias deleted? deleted
|
72
71
|
|
73
72
|
def initialize(client, options = {})
|
74
73
|
@client = client
|
@@ -80,12 +79,12 @@ module JIRA
|
|
80
79
|
# each of them must be passed in to the initializer.
|
81
80
|
self.class.belongs_to_relationships.each do |relation|
|
82
81
|
if options[relation]
|
83
|
-
instance_variable_set("@#{relation
|
84
|
-
instance_variable_set("@#{relation
|
82
|
+
instance_variable_set("@#{relation}", options[relation])
|
83
|
+
instance_variable_set("@#{relation}_id", options[relation].key_value)
|
85
84
|
elsif options["#{relation}_id".to_sym]
|
86
|
-
instance_variable_set("@#{relation
|
85
|
+
instance_variable_set("@#{relation}_id", options["#{relation}_id".to_sym])
|
87
86
|
else
|
88
|
-
raise ArgumentError
|
87
|
+
raise ArgumentError, "Required option #{relation.inspect} missing" unless options[relation]
|
89
88
|
end
|
90
89
|
end
|
91
90
|
end
|
@@ -95,17 +94,15 @@ module JIRA
|
|
95
94
|
def self.all(client, options = {})
|
96
95
|
response = client.get(collection_path(client))
|
97
96
|
json = parse_json(response.body)
|
98
|
-
if collection_attributes_are_nested
|
99
|
-
json = json[endpoint_name.pluralize]
|
100
|
-
end
|
97
|
+
json = json[endpoint_name.pluralize] if collection_attributes_are_nested
|
101
98
|
json.map do |attrs|
|
102
|
-
|
99
|
+
new(client, { attrs: attrs }.merge(options))
|
103
100
|
end
|
104
101
|
end
|
105
102
|
|
106
103
|
# Finds and retrieves a resource with the given ID.
|
107
104
|
def self.find(client, key, options = {})
|
108
|
-
instance =
|
105
|
+
instance = new(client, options)
|
109
106
|
instance.attrs[key_attribute.to_s] = key
|
110
107
|
instance.fetch(false, query_params_for_single_fetch(options))
|
111
108
|
instance
|
@@ -114,7 +111,7 @@ module JIRA
|
|
114
111
|
# Builds a new instance of the resource with the given attributes.
|
115
112
|
# These attributes will be posted to the JIRA Api if save is called.
|
116
113
|
def self.build(client, attrs)
|
117
|
-
|
114
|
+
new(client, attrs: attrs)
|
118
115
|
end
|
119
116
|
|
120
117
|
# Returns the name of this resource for use in URL components.
|
@@ -122,7 +119,7 @@ module JIRA
|
|
122
119
|
# JIRA::Resource::Issue.endpoint_name
|
123
120
|
# # => issue
|
124
121
|
def self.endpoint_name
|
125
|
-
|
122
|
+
name.split('::').last.downcase
|
126
123
|
end
|
127
124
|
|
128
125
|
# Returns the full path for a collection of this resource.
|
@@ -130,7 +127,7 @@ module JIRA
|
|
130
127
|
# JIRA::Resource::Issue.collection_path
|
131
128
|
# # => /jira/rest/api/2/issue
|
132
129
|
def self.collection_path(client, prefix = '/')
|
133
|
-
client.options[:rest_base_path] + prefix +
|
130
|
+
client.options[:rest_base_path] + prefix + endpoint_name
|
134
131
|
end
|
135
132
|
|
136
133
|
# Returns the singular path for the resource with the given key.
|
@@ -200,7 +197,7 @@ module JIRA
|
|
200
197
|
define_method(resource) do
|
201
198
|
attribute = maybe_nested_attribute(attribute_key, options[:nested_under])
|
202
199
|
return nil unless attribute
|
203
|
-
child_class.new(client, :
|
200
|
+
child_class.new(client, attrs: attribute)
|
204
201
|
end
|
205
202
|
end
|
206
203
|
|
@@ -248,12 +245,12 @@ module JIRA
|
|
248
245
|
def self.has_many(collection, options = {})
|
249
246
|
attribute_key = options[:attribute_key] || collection.to_s
|
250
247
|
child_class = options[:class] || ('JIRA::Resource::' + collection.to_s.classify).constantize
|
251
|
-
self_class_basename =
|
248
|
+
self_class_basename = name.split('::').last.downcase.to_sym
|
252
249
|
define_method(collection) do
|
253
|
-
child_class_options = {self_class_basename => self}
|
250
|
+
child_class_options = { self_class_basename => self }
|
254
251
|
attribute = maybe_nested_attribute(attribute_key, options[:nested_under]) || []
|
255
252
|
collection = attribute.map do |child_attributes|
|
256
|
-
child_class.new(client, child_class_options.merge(:
|
253
|
+
child_class.new(client, child_class_options.merge(attrs: child_attributes))
|
257
254
|
end
|
258
255
|
HasManyProxy.new(self, child_class, collection)
|
259
256
|
end
|
@@ -290,8 +287,8 @@ module JIRA
|
|
290
287
|
# Checks if method_name is set in the attributes hash
|
291
288
|
# and returns true when found, otherwise proxies the
|
292
289
|
# call to the superclass.
|
293
|
-
def respond_to?(method_name,
|
294
|
-
if attrs.
|
290
|
+
def respond_to?(method_name, _include_all = false)
|
291
|
+
if attrs.key?(method_name.to_s)
|
295
292
|
true
|
296
293
|
else
|
297
294
|
super(method_name)
|
@@ -301,8 +298,8 @@ module JIRA
|
|
301
298
|
# Overrides method_missing to check the attribute hash
|
302
299
|
# for resources matching method_name and proxies the call
|
303
300
|
# to the superclass if no match is found.
|
304
|
-
def method_missing(method_name, *
|
305
|
-
if attrs.
|
301
|
+
def method_missing(method_name, *_args)
|
302
|
+
if attrs.key?(method_name.to_s)
|
306
303
|
attrs[method_name.to_s]
|
307
304
|
else
|
308
305
|
super(method_name)
|
@@ -315,7 +312,7 @@ module JIRA
|
|
315
312
|
@attrs[self.class.key_attribute.to_s]
|
316
313
|
end
|
317
314
|
|
318
|
-
def collection_path(prefix =
|
315
|
+
def collection_path(prefix = '/')
|
319
316
|
# Just proxy this to the class method
|
320
317
|
self.class.collection_path(client, prefix)
|
321
318
|
end
|
@@ -325,9 +322,7 @@ module JIRA
|
|
325
322
|
# issue it returns '/issue'
|
326
323
|
def path_component
|
327
324
|
path_component = "/#{self.class.endpoint_name}"
|
328
|
-
if key_value
|
329
|
-
path_component += '/' + key_value
|
330
|
-
end
|
325
|
+
path_component += '/' + key_value if key_value
|
331
326
|
path_component
|
332
327
|
end
|
333
328
|
|
@@ -346,9 +341,10 @@ module JIRA
|
|
346
341
|
#
|
347
342
|
# Accepts an attributes hash of the values to be saved. Will throw a
|
348
343
|
# JIRA::HTTPError if the request fails (response is not HTTP 2xx).
|
349
|
-
def save!(attrs)
|
344
|
+
def save!(attrs, path = nil)
|
345
|
+
path ||= new_record? ? url : patched_url
|
350
346
|
http_method = new_record? ? :post : :put
|
351
|
-
response = client.send(http_method,
|
347
|
+
response = client.send(http_method, path, attrs.to_json)
|
352
348
|
set_attrs(attrs, false)
|
353
349
|
set_attrs_from_response(response)
|
354
350
|
@expanded = false
|
@@ -360,21 +356,20 @@ module JIRA
|
|
360
356
|
#
|
361
357
|
# Accepts an attributes hash of the values to be saved. Will return false
|
362
358
|
# if the request fails.
|
363
|
-
def save(attrs)
|
359
|
+
def save(attrs, path = url)
|
364
360
|
begin
|
365
|
-
save_status = save!(attrs)
|
361
|
+
save_status = save!(attrs, path)
|
366
362
|
rescue JIRA::HTTPError => exception
|
367
|
-
puts ">>>>>>>>> Exception response: #{exception.response.body}"
|
368
363
|
begin
|
369
364
|
set_attrs_from_response(exception.response) # Merge error status generated by JIRA REST API
|
370
365
|
rescue JSON::ParserError => parse_exception
|
371
|
-
set_attrs(
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
}
|
376
|
-
)
|
366
|
+
set_attrs('exception' => {
|
367
|
+
'class' => exception.response.class.name,
|
368
|
+
'code' => exception.response.code,
|
369
|
+
'message' => exception.response.message
|
370
|
+
})
|
377
371
|
end
|
372
|
+
# raise exception
|
378
373
|
save_status = false
|
379
374
|
end
|
380
375
|
save_status
|
@@ -383,7 +378,7 @@ module JIRA
|
|
383
378
|
# Sets the attributes hash from a HTTPResponse object from JIRA if it is
|
384
379
|
# not nil or is not a json response.
|
385
380
|
def set_attrs_from_response(response)
|
386
|
-
unless response.body.nil?
|
381
|
+
unless response.body.nil? || (response.body.length < 2)
|
387
382
|
json = self.class.parse_json(response.body)
|
388
383
|
set_attrs(json)
|
389
384
|
end
|
@@ -393,7 +388,7 @@ module JIRA
|
|
393
388
|
# hash values will be clobbered by the new hash, otherwise the hash will
|
394
389
|
# be deeply merged into attrs. The target paramater is for internal use only
|
395
390
|
# and should not be used.
|
396
|
-
def set_attrs(hash, clobber=true, target = nil)
|
391
|
+
def set_attrs(hash, clobber = true, target = nil)
|
397
392
|
target ||= @attrs
|
398
393
|
if clobber
|
399
394
|
target.merge!(hash)
|
@@ -424,12 +419,12 @@ module JIRA
|
|
424
419
|
prefix = '/'
|
425
420
|
unless self.class.belongs_to_relationships.empty?
|
426
421
|
prefix = self.class.belongs_to_relationships.inject(prefix) do |prefix_so_far, relationship|
|
427
|
-
prefix_so_far.to_s + relationship.to_s +
|
422
|
+
prefix_so_far.to_s + relationship.to_s + '/' + send("#{relationship}_id").to_s + '/'
|
428
423
|
end
|
429
424
|
end
|
430
425
|
if @attrs['self']
|
431
|
-
the_url = @attrs['self']
|
432
|
-
the_url =
|
426
|
+
the_url = @attrs['self']
|
427
|
+
the_url = the_url.sub(@client.options[:site].chomp('/'), '') if @client.options[:site]
|
433
428
|
the_url
|
434
429
|
elsif key_value
|
435
430
|
self.class.singular_path(client, key_value.to_s, prefix)
|
@@ -447,7 +442,7 @@ module JIRA
|
|
447
442
|
# [07/Jun/2015:15:17:18 +0400] "PUT /jira/rest/api/2/issue/10111 HTTP/1.1" 204 -
|
448
443
|
def patched_url
|
449
444
|
result = url
|
450
|
-
return result if result.start_with?('/')
|
445
|
+
return result if result.start_with?('/', 'http')
|
451
446
|
"/#{result}"
|
452
447
|
end
|
453
448
|
|
@@ -494,9 +489,15 @@ module JIRA
|
|
494
489
|
end
|
495
490
|
|
496
491
|
def url_with_query_params(url, query_params)
|
497
|
-
|
498
|
-
|
499
|
-
|
492
|
+
self.class.url_with_query_params(url, query_params)
|
493
|
+
end
|
494
|
+
|
495
|
+
def self.url_with_query_params(url, query_params)
|
496
|
+
if !query_params.empty?
|
497
|
+
"#{url}?#{hash_to_query_string query_params}"
|
498
|
+
else
|
499
|
+
url
|
500
|
+
end
|
500
501
|
end
|
501
502
|
|
502
503
|
def hash_to_query_string(query_params)
|
@@ -504,19 +505,19 @@ module JIRA
|
|
504
505
|
end
|
505
506
|
|
506
507
|
def self.hash_to_query_string(query_params)
|
507
|
-
query_params.map do |k,v|
|
508
|
+
query_params.map do |k, v|
|
508
509
|
CGI.escape(k.to_s) + '=' + CGI.escape(v.to_s)
|
509
510
|
end.join('&')
|
510
511
|
end
|
511
512
|
|
512
513
|
def self.query_params_for_single_fetch(options)
|
513
|
-
Hash[options.select do |k,
|
514
|
+
Hash[options.select do |k, _v|
|
514
515
|
QUERY_PARAMS_FOR_SINGLE_FETCH.include? k
|
515
516
|
end]
|
516
517
|
end
|
517
518
|
|
518
519
|
def self.query_params_for_search(options)
|
519
|
-
Hash[options.select do |k,
|
520
|
+
Hash[options.select do |k, _v|
|
520
521
|
QUERY_PARAMS_FOR_SEARCH.include? k
|
521
522
|
end]
|
522
523
|
end
|
data/lib/jira/base_factory.rb
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
module JIRA
|
2
|
-
|
3
2
|
# This is the base class for all the JIRA resource factory instances.
|
4
3
|
class BaseFactory
|
5
|
-
|
6
4
|
attr_reader :client
|
7
5
|
|
8
6
|
def initialize(client)
|
9
7
|
@client = client
|
10
8
|
end
|
11
9
|
|
12
|
-
# Return the name of the class which this factory generates, i.e.
|
10
|
+
# Return the name of the class which this factory generates, i.e.
|
13
11
|
# JIRA::Resource::FooFactory creates JIRA::Resource::Foo instances.
|
14
12
|
def target_class
|
15
13
|
# Need to do a little bit of work here as Module.const_get doesn't work
|
@@ -38,12 +36,11 @@ module JIRA
|
|
38
36
|
# The principle purpose of this class is to delegate methods to the corresponding
|
39
37
|
# non-factory class and automatically prepend the client argument to the argument
|
40
38
|
# list.
|
41
|
-
delegate_to_target_class :all, :find, :collection_path, :singular_path, :jql, :get_backlog_issues, :get_sprints, :get_sprint_issues
|
39
|
+
delegate_to_target_class :all, :find, :collection_path, :singular_path, :jql, :get_backlog_issues, :get_board_issues, :get_sprints, :get_sprint_issues, :get_projects, :get_projects_full
|
42
40
|
|
43
41
|
# This method needs special handling as it has a default argument value
|
44
|
-
def build(attrs={})
|
42
|
+
def build(attrs = {})
|
45
43
|
target_class.build(@client, attrs)
|
46
44
|
end
|
47
|
-
|
48
45
|
end
|
49
46
|
end
|
data/lib/jira/client.rb
CHANGED
@@ -3,11 +3,10 @@ require 'forwardable'
|
|
3
3
|
require 'ostruct'
|
4
4
|
|
5
5
|
module JIRA
|
6
|
-
|
7
6
|
# This class is the main access point for all JIRA::Resource instances.
|
8
7
|
#
|
9
8
|
# The client must be initialized with an options hash containing
|
10
|
-
# configuration options.
|
9
|
+
# configuration options. The available options are:
|
11
10
|
#
|
12
11
|
# :site => 'http://localhost:2990',
|
13
12
|
# :context_path => '/jira',
|
@@ -15,23 +14,38 @@ module JIRA
|
|
15
14
|
# :request_token_path => "/plugins/servlet/oauth/request-token",
|
16
15
|
# :authorize_path => "/plugins/servlet/oauth/authorize",
|
17
16
|
# :access_token_path => "/plugins/servlet/oauth/access-token",
|
17
|
+
# :private_key => nil,
|
18
18
|
# :private_key_file => "rsakey.pem",
|
19
19
|
# :rest_base_path => "/rest/api/2",
|
20
20
|
# :consumer_key => nil,
|
21
21
|
# :consumer_secret => nil,
|
22
22
|
# :ssl_verify_mode => OpenSSL::SSL::VERIFY_PEER,
|
23
|
+
# :ssl_version => nil,
|
23
24
|
# :use_ssl => true,
|
24
25
|
# :username => nil,
|
25
26
|
# :password => nil,
|
26
|
-
# :auth_type => :oauth
|
27
|
-
# :proxy_address => nil
|
28
|
-
# :proxy_port => nil
|
27
|
+
# :auth_type => :oauth,
|
28
|
+
# :proxy_address => nil,
|
29
|
+
# :proxy_port => nil,
|
30
|
+
# :proxy_username => nil,
|
31
|
+
# :proxy_password => nil,
|
32
|
+
# :use_cookies => nil,
|
33
|
+
# :additional_cookies => nil,
|
34
|
+
# :default_headers => {},
|
35
|
+
# :use_client_cert => false,
|
36
|
+
# :read_timeout => nil,
|
37
|
+
# :http_debug => false,
|
38
|
+
# :shared_secret => nil,
|
39
|
+
# :cert_path => nil,
|
40
|
+
# :key_path => nil,
|
41
|
+
# :ssl_client_cert => nil,
|
42
|
+
# :ssl_client_key => nil
|
43
|
+
# :ca_file => nil
|
29
44
|
#
|
30
45
|
# See the JIRA::Base class methods for all of the available methods on these accessor
|
31
46
|
# objects.
|
32
47
|
|
33
48
|
class Client
|
34
|
-
|
35
49
|
extend Forwardable
|
36
50
|
|
37
51
|
# The OAuth::Consumer instance returned by the OauthClient
|
@@ -43,27 +57,79 @@ module JIRA
|
|
43
57
|
# The configuration options for this client instance
|
44
58
|
attr_reader :options
|
45
59
|
|
46
|
-
def_delegators :@request_client, :init_access_token, :set_access_token, :set_request_token, :request_token, :access_token
|
60
|
+
def_delegators :@request_client, :init_access_token, :set_access_token, :set_request_token, :request_token, :access_token, :authenticated?
|
61
|
+
|
62
|
+
DEFINED_OPTIONS = [
|
63
|
+
:site,
|
64
|
+
:context_path,
|
65
|
+
:signature_method,
|
66
|
+
:request_token_path,
|
67
|
+
:authorize_path,
|
68
|
+
:access_token_path,
|
69
|
+
:private_key,
|
70
|
+
:private_key_file,
|
71
|
+
:rest_base_path,
|
72
|
+
:consumer_key,
|
73
|
+
:consumer_secret,
|
74
|
+
:ssl_verify_mode,
|
75
|
+
:ssl_version,
|
76
|
+
:use_ssl,
|
77
|
+
:username,
|
78
|
+
:password,
|
79
|
+
:auth_type,
|
80
|
+
:proxy_address,
|
81
|
+
:proxy_port,
|
82
|
+
:proxy_username,
|
83
|
+
:proxy_password,
|
84
|
+
:use_cookies,
|
85
|
+
:additional_cookies,
|
86
|
+
:default_headers,
|
87
|
+
:use_client_cert,
|
88
|
+
:read_timeout,
|
89
|
+
:http_debug,
|
90
|
+
:issuer,
|
91
|
+
:base_url,
|
92
|
+
:shared_secret,
|
93
|
+
:cert_path,
|
94
|
+
:key_path,
|
95
|
+
:ssl_client_cert,
|
96
|
+
:ssl_client_key
|
97
|
+
].freeze
|
47
98
|
|
48
99
|
DEFAULT_OPTIONS = {
|
49
|
-
:
|
50
|
-
:
|
51
|
-
:
|
52
|
-
:
|
53
|
-
:
|
54
|
-
:
|
55
|
-
:
|
56
|
-
|
57
|
-
|
58
|
-
|
100
|
+
site: 'http://localhost:2990',
|
101
|
+
context_path: '/jira',
|
102
|
+
rest_base_path: '/rest/api/2',
|
103
|
+
ssl_verify_mode: OpenSSL::SSL::VERIFY_PEER,
|
104
|
+
use_ssl: true,
|
105
|
+
use_client_cert: false,
|
106
|
+
auth_type: :oauth,
|
107
|
+
http_debug: false,
|
108
|
+
default_headers: {}
|
109
|
+
}.freeze
|
110
|
+
|
111
|
+
def initialize(options = {})
|
59
112
|
options = DEFAULT_OPTIONS.merge(options)
|
60
113
|
@options = options
|
61
114
|
@options[:rest_base_path] = @options[:context_path] + @options[:rest_base_path]
|
62
115
|
|
116
|
+
unknown_options = options.keys.reject { |o| DEFINED_OPTIONS.include?(o) }
|
117
|
+
raise ArgumentError, "Unknown option(s) given: #{unknown_options}" unless unknown_options.empty?
|
118
|
+
|
119
|
+
if options[:use_client_cert]
|
120
|
+
@options[:ssl_client_cert] = OpenSSL::X509::Certificate.new(File.read(@options[:cert_path])) if @options[:cert_path]
|
121
|
+
@options[:ssl_client_key] = OpenSSL::PKey::RSA.new(File.read(@options[:key_path])) if @options[:key_path]
|
122
|
+
|
123
|
+
raise ArgumentError, 'Options: :cert_path or :ssl_client_cert must be set when :use_client_cert is true' unless @options[:ssl_client_cert]
|
124
|
+
raise ArgumentError, 'Options: :key_path or :ssl_client_key must be set when :use_client_cert is true' unless @options[:ssl_client_key]
|
125
|
+
end
|
126
|
+
|
63
127
|
case options[:auth_type]
|
64
|
-
when :oauth
|
128
|
+
when :oauth, :oauth_2legged
|
65
129
|
@request_client = OauthClient.new(@options)
|
66
130
|
@consumer = @request_client.consumer
|
131
|
+
when :jwt
|
132
|
+
@request_client = JwtClient.new(@options)
|
67
133
|
when :basic
|
68
134
|
@request_client = HttpClient.new(@options)
|
69
135
|
when :cookie
|
@@ -71,8 +137,10 @@ module JIRA
|
|
71
137
|
@options[:use_cookies] = true
|
72
138
|
@request_client = HttpClient.new(@options)
|
73
139
|
@request_client.make_cookie_auth_request
|
140
|
+
@options.delete(:username)
|
141
|
+
@options.delete(:password)
|
74
142
|
else
|
75
|
-
raise ArgumentError, 'Options: ":auth_type" must be ":oauth", ":cookie" or ":basic"'
|
143
|
+
raise ArgumentError, 'Options: ":auth_type" must be ":oauth",":oauth_2legged", ":cookie" or ":basic"'
|
76
144
|
end
|
77
145
|
|
78
146
|
@http_debug = @options[:http_debug]
|
@@ -142,10 +210,26 @@ module JIRA
|
|
142
210
|
JIRA::Resource::FieldFactory.new(self)
|
143
211
|
end
|
144
212
|
|
213
|
+
def Board
|
214
|
+
JIRA::Resource::BoardFactory.new(self)
|
215
|
+
end
|
216
|
+
|
217
|
+
def BoardConfiguration
|
218
|
+
JIRA::Resource::BoardConfigurationFactory.new(self)
|
219
|
+
end
|
220
|
+
|
145
221
|
def RapidView
|
146
222
|
JIRA::Resource::RapidViewFactory.new(self)
|
147
223
|
end
|
148
224
|
|
225
|
+
def Sprint
|
226
|
+
JIRA::Resource::SprintFactory.new(self)
|
227
|
+
end
|
228
|
+
|
229
|
+
def SprintReport
|
230
|
+
JIRA::Resource::SprintReportFactory.new(self)
|
231
|
+
end
|
232
|
+
|
149
233
|
def ServerInfo
|
150
234
|
JIRA::Resource::ServerInfoFactory.new(self)
|
151
235
|
end
|
@@ -158,6 +242,10 @@ module JIRA
|
|
158
242
|
JIRA::Resource::ApplicationLinkFactory.new(self)
|
159
243
|
end
|
160
244
|
|
245
|
+
def Watcher
|
246
|
+
JIRA::Resource::WatcherFactory.new(self)
|
247
|
+
end
|
248
|
+
|
161
249
|
def Webhook
|
162
250
|
JIRA::Resource::WebhookFactory.new(self)
|
163
251
|
end
|
@@ -170,12 +258,12 @@ module JIRA
|
|
170
258
|
JIRA::Resource::IssuelinktypeFactory.new(self)
|
171
259
|
end
|
172
260
|
|
173
|
-
def
|
174
|
-
JIRA::Resource::
|
261
|
+
def IssuePickerSuggestions
|
262
|
+
JIRA::Resource::IssuePickerSuggestionsFactory.new(self)
|
175
263
|
end
|
176
264
|
|
177
|
-
def
|
178
|
-
JIRA::Resource::
|
265
|
+
def Remotelink
|
266
|
+
JIRA::Resource::RemotelinkFactory.new(self)
|
179
267
|
end
|
180
268
|
|
181
269
|
def Agile
|
@@ -197,27 +285,36 @@ module JIRA
|
|
197
285
|
|
198
286
|
# HTTP methods with a body
|
199
287
|
def post(path, body = '', headers = {})
|
200
|
-
headers = {'Content-Type' => 'application/json'}.merge(headers)
|
288
|
+
headers = { 'Content-Type' => 'application/json' }.merge(headers)
|
201
289
|
request(:post, path, body, merge_default_headers(headers))
|
202
290
|
end
|
203
291
|
|
292
|
+
def post_multipart(path, file, headers = {})
|
293
|
+
puts "post multipart: #{path} - [#{file}]" if @http_debug
|
294
|
+
@request_client.request_multipart(path, file, headers)
|
295
|
+
end
|
296
|
+
|
204
297
|
def put(path, body = '', headers = {})
|
205
|
-
headers = {'Content-Type' => 'application/json'}.merge(headers)
|
298
|
+
headers = { 'Content-Type' => 'application/json' }.merge(headers)
|
206
299
|
request(:put, path, body, merge_default_headers(headers))
|
207
300
|
end
|
208
301
|
|
209
302
|
# Sends the specified HTTP request to the REST API through the
|
210
303
|
# appropriate method (oauth, basic).
|
211
|
-
def request(http_method, path, body = '', headers={})
|
304
|
+
def request(http_method, path, body = '', headers = {})
|
212
305
|
puts "#{http_method}: #{path} - [#{body}]" if @http_debug
|
213
306
|
@request_client.request(http_method, path, body, headers)
|
214
307
|
end
|
215
308
|
|
216
|
-
|
309
|
+
# Stops sensitive client information from being displayed in logs
|
310
|
+
def inspect
|
311
|
+
"#<JIRA::Client:#{object_id}>"
|
312
|
+
end
|
217
313
|
|
218
|
-
|
219
|
-
{'Accept' => 'application/json'}.merge(headers)
|
220
|
-
end
|
314
|
+
protected
|
221
315
|
|
316
|
+
def merge_default_headers(headers)
|
317
|
+
{ 'Accept' => 'application/json' }.merge(@options[:default_headers]).merge(headers)
|
318
|
+
end
|
222
319
|
end
|
223
320
|
end
|