jira-ruby 1.8.0 → 2.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 960c900089bbe802d788f2c8daa7fcfa4b004a4674598693057117a1a1bca1c1
4
- data.tar.gz: '086f550ca45271d9390498c7a55e8ba3ea281aa74641cae693c06d014ebd144c'
3
+ metadata.gz: 3167a32cb87f89e17ad016fa13bac784a689c9c39ac800e70137a9944b00b550
4
+ data.tar.gz: 28c6dd444429802a94c58d13a3786647de6bfe37164251fc043761a70ef9d20f
5
5
  SHA512:
6
- metadata.gz: 5e8b4e34177a1a7f20b2376b949c5bc2f86ec6e14c64a1eb6ab1f332a243164a3fad933a54a079d930f732a8f986504f9c6e2386a7e6f1f87e3692d84cf5c6a9
7
- data.tar.gz: e6c535fcec553bf6d74447c8e44fe5d38dcaf6248ccd76f5f554a3e52cdf4270a0fdb8d0e051a9af09fd15810cbd5759e33f6f616e1560e907135fa6b71f3b11
6
+ metadata.gz: f35ac632b07ffd50c4bc58c810bc10e8ed54ffdd212b9d172e3ce2080ee3e947754e5b9afd521bbc655e69064fd658bb29dda880833afc7327d089c8eea3d31c
7
+ data.tar.gz: 361f3be9096ca1eed2383c4dcd4c388806b6f56e1b44305e802c7bb206a79b1216a4e6c8104ee26472a4f81c59b9b1c533c4d18d140b7e5928e6d3d581e571bc
data/.gitignore CHANGED
@@ -9,3 +9,5 @@ pkg/*
9
9
  .DS_STORE
10
10
  doc
11
11
  .ruby-version
12
+
13
+ .rakeTasks
@@ -3,7 +3,7 @@ rvm:
3
3
  - 2.4
4
4
  - 2.5
5
5
  - 2.6
6
- - ruby-head
6
+ - 2.7
7
7
  before_script:
8
8
  - rake jira:generate_public_cert
9
9
  script: bundle exec rake spec
data/README.md CHANGED
@@ -163,7 +163,7 @@ api_token = "myApiToken"
163
163
  options = {
164
164
  :username => username,
165
165
  :password => api_token,
166
- :site => 'http://localhost:8080/', # or 'https://<your_subdomain>.atlassian.net'
166
+ :site => 'http://localhost:8080/', # or 'https://<your_subdomain>.atlassian.net/'
167
167
  :context_path => '/myjira', # often blank
168
168
  :auth_type => :basic,
169
169
  :read_timeout => 120
@@ -307,7 +307,7 @@ class App < Sinatra::Base
307
307
  # site uri, and the request token, access token, and authorize paths
308
308
  before do
309
309
  options = {
310
- :site => 'http://localhost:2990',
310
+ :site => 'http://localhost:2990/',
311
311
  :context_path => '/jira',
312
312
  :signature_method => 'RSA-SHA1',
313
313
  :request_token_path => "/plugins/servlet/oauth/request-token",
@@ -405,7 +405,7 @@ require 'pp'
405
405
  require 'jira-ruby'
406
406
 
407
407
  options = {
408
- :site => 'http://localhost:2990',
408
+ :site => 'http://localhost:2990/',
409
409
  :context_path => '/jira',
410
410
  :signature_method => 'RSA-SHA1',
411
411
  :private_key_file => "rsakey.pem",
@@ -424,7 +424,7 @@ module JIRA
424
424
  end
425
425
  if @attrs['self']
426
426
  the_url = @attrs['self']
427
- the_url = the_url.sub(@client.options[:site], '') if @client.options[:site]
427
+ the_url = the_url.sub(@client.options[:site].chomp('/'), '') if @client.options[:site]
428
428
  the_url
429
429
  elsif key_value
430
430
  self.class.singular_path(client, key_value.to_s, prefix)
@@ -14,6 +14,7 @@ module JIRA
14
14
  # :request_token_path => "/plugins/servlet/oauth/request-token",
15
15
  # :authorize_path => "/plugins/servlet/oauth/authorize",
16
16
  # :access_token_path => "/plugins/servlet/oauth/access-token",
17
+ # :private_key => nil,
17
18
  # :private_key_file => "rsakey.pem",
18
19
  # :rest_base_path => "/rest/api/2",
19
20
  # :consumer_key => nil,
@@ -29,7 +30,15 @@ module JIRA
29
30
  # :proxy_username => nil,
30
31
  # :proxy_password => nil,
31
32
  # :additional_cookies => nil,
32
- # :default_headers => {}
33
+ # :default_headers => {},
34
+ # :use_client_cert => false,
35
+ # :read_timeout => nil,
36
+ # :http_debug => false,
37
+ # :shared_secret => nil,
38
+ # :cert_path => nil,
39
+ # :key_path => nil,
40
+ # :ssl_client_cert => nil,
41
+ # :ssl_client_key => nil
33
42
  #
34
43
  # See the JIRA::Base class methods for all of the available methods on these accessor
35
44
  # objects.
@@ -48,6 +57,42 @@ module JIRA
48
57
 
49
58
  def_delegators :@request_client, :init_access_token, :set_access_token, :set_request_token, :request_token, :access_token, :authenticated?
50
59
 
60
+ DEFINED_OPTIONS = [
61
+ :site,
62
+ :context_path,
63
+ :signature_method,
64
+ :request_token_path,
65
+ :authorize_path,
66
+ :access_token_path,
67
+ :private_key,
68
+ :private_key_file,
69
+ :rest_base_path,
70
+ :consumer_key,
71
+ :consumer_secret,
72
+ :ssl_verify_mode,
73
+ :ssl_version,
74
+ :use_ssl,
75
+ :username,
76
+ :password,
77
+ :auth_type,
78
+ :proxy_address,
79
+ :proxy_port,
80
+ :proxy_username,
81
+ :proxy_password,
82
+ :additional_cookies,
83
+ :default_headers,
84
+ :use_client_cert,
85
+ :read_timeout,
86
+ :http_debug,
87
+ :issuer,
88
+ :base_url,
89
+ :shared_secret,
90
+ :cert_path,
91
+ :key_path,
92
+ :ssl_client_cert,
93
+ :ssl_client_key
94
+ ].freeze
95
+
51
96
  DEFAULT_OPTIONS = {
52
97
  site: 'http://localhost:2990',
53
98
  context_path: '/jira',
@@ -65,11 +110,15 @@ module JIRA
65
110
  @options = options
66
111
  @options[:rest_base_path] = @options[:context_path] + @options[:rest_base_path]
67
112
 
113
+ unknown_options = options.keys.reject { |o| DEFINED_OPTIONS.include?(o) }
114
+ raise ArgumentError, "Unknown option(s) given: #{unknown_options}" unless unknown_options.empty?
115
+
68
116
  if options[:use_client_cert]
69
- raise ArgumentError, 'Options: :cert_path must be set when :use_client_cert is true' unless @options[:cert_path]
70
- raise ArgumentError, 'Options: :key_path must be set when :use_client_cert is true' unless @options[:key_path]
71
- @options[:cert] = OpenSSL::X509::Certificate.new(File.read(@options[:cert_path]))
72
- @options[:key] = OpenSSL::PKey::RSA.new(File.read(@options[:key_path]))
117
+ @options[:ssl_client_cert] = OpenSSL::X509::Certificate.new(File.read(@options[:cert_path])) if @options[:cert_path]
118
+ @options[:ssl_client_key] = OpenSSL::PKey::RSA.new(File.read(@options[:key_path])) if @options[:key_path]
119
+
120
+ raise ArgumentError, 'Options: :cert_path or :ssl_client_cert must be set when :use_client_cert is true' unless @options[:ssl_client_cert]
121
+ raise ArgumentError, 'Options: :key_path or :ssl_client_key must be set when :use_client_cert is true' unless @options[:ssl_client_key]
73
122
  end
74
123
 
75
124
  case options[:auth_type]
@@ -233,6 +282,11 @@ module JIRA
233
282
  request(:post, path, body, merge_default_headers(headers))
234
283
  end
235
284
 
285
+ def post_multipart(path, file, headers = {})
286
+ puts "post multipart: #{path} - [#{file}]" if @http_debug
287
+ @request_client.request_multipart(path, file, headers)
288
+ end
289
+
236
290
  def put(path, body = '', headers = {})
237
291
  headers = { 'Content-Type' => 'application/json' }.merge(headers)
238
292
  request(:put, path, body, merge_default_headers(headers))
@@ -29,12 +29,15 @@ module JIRA
29
29
  path = request_path(url)
30
30
  request = Net::HTTP.const_get(http_method.to_s.capitalize).new(path, headers)
31
31
  request.body = body unless body.nil?
32
- add_cookies(request) if options[:use_cookies]
33
- request.basic_auth(@options[:username], @options[:password]) if @options[:username] && @options[:password]
34
- response = basic_auth_http_conn.request(request)
35
- @authenticated = response.is_a? Net::HTTPOK
36
- store_cookies(response) if options[:use_cookies]
37
- response
32
+
33
+ execute_request(request)
34
+ end
35
+
36
+ def make_multipart_request(url, body, headers = {})
37
+ path = request_path(url)
38
+ request = Net::HTTP::Post::Multipart.new(path, body, headers)
39
+
40
+ execute_request(request)
38
41
  end
39
42
 
40
43
  def basic_auth_http_conn
@@ -50,8 +53,8 @@ module JIRA
50
53
  http_conn = http_class.new(uri.host, uri.port)
51
54
  http_conn.use_ssl = @options[:use_ssl]
52
55
  if @options[:use_client_cert]
53
- http_conn.cert = @options[:cert]
54
- http_conn.key = @options[:key]
56
+ http_conn.cert = @options[:ssl_client_cert]
57
+ http_conn.key = @options[:ssl_client_key]
55
58
  end
56
59
  http_conn.verify_mode = @options[:ssl_verify_mode]
57
60
  http_conn.ssl_version = @options[:ssl_version] if @options[:ssl_version]
@@ -60,7 +63,7 @@ module JIRA
60
63
  end
61
64
 
62
65
  def uri
63
- uri = URI.parse(@options[:site])
66
+ URI.parse(@options[:site])
64
67
  end
65
68
 
66
69
  def authenticated?
@@ -69,6 +72,17 @@ module JIRA
69
72
 
70
73
  private
71
74
 
75
+ def execute_request(request)
76
+ add_cookies(request) if options[:use_cookies]
77
+ request.basic_auth(@options[:username], @options[:password]) if @options[:username] && @options[:password]
78
+
79
+ response = basic_auth_http_conn.request(request)
80
+ @authenticated = response.is_a? Net::HTTPOK
81
+ store_cookies(response) if options[:use_cookies]
82
+
83
+ response
84
+ end
85
+
72
86
  def request_path(url)
73
87
  parsed_uri = URI(url)
74
88
 
@@ -8,7 +8,7 @@ module JIRA
8
8
 
9
9
  def initialize(response)
10
10
  @response = response
11
- @message = response.try(:message) || response.try(:body)
11
+ @message = response.try(:message).presence || response.try(:body)
12
12
  end
13
13
  end
14
14
  end
@@ -3,16 +3,15 @@ require 'atlassian/jwt'
3
3
  module JIRA
4
4
  class JwtClient < HttpClient
5
5
  def make_request(http_method, url, body = '', headers = {})
6
- # When a proxy is enabled, Net::HTTP expects that the request path omits the domain name
7
- path = request_path(http_method, url)
6
+ @http_method = http_method
8
7
 
9
- request = Net::HTTP.const_get(http_method.to_s.capitalize).new(path, headers)
10
- request.body = body unless body.nil?
8
+ super(http_method, url, body, headers)
9
+ end
10
+
11
+ def make_multipart_request(url, data, headers = {})
12
+ @http_method = :post
11
13
 
12
- response = basic_auth_http_conn.request(request)
13
- @authenticated = response.is_a? Net::HTTPOK
14
- store_cookies(response) if options[:use_cookies]
15
- response
14
+ super(url, data, headers)
16
15
  end
17
16
 
18
17
  class JwtUriBuilder
@@ -53,7 +52,9 @@ module JIRA
53
52
 
54
53
  private
55
54
 
56
- def request_path(http_method, url)
55
+ attr_reader :http_method
56
+
57
+ def request_path(url)
57
58
  JwtUriBuilder.new(
58
59
  url,
59
60
  http_method.to_s,
@@ -38,6 +38,8 @@ module JIRA
38
38
  @options[:request_token_path] = @options[:context_path] + @options[:request_token_path]
39
39
  @options[:authorize_path] = @options[:context_path] + @options[:authorize_path]
40
40
  @options[:access_token_path] = @options[:context_path] + @options[:access_token_path]
41
+ # proxy_address does not exist in oauth's gem context but proxy does
42
+ @options[:proxy] = @options[:proxy_address] if @options[:proxy_address]
41
43
  OAuth::Consumer.new(@options[:consumer_key], @options[:consumer_secret], @options)
42
44
  end
43
45
 
@@ -72,29 +74,39 @@ module JIRA
72
74
  @access_token
73
75
  end
74
76
 
75
- def make_request(http_method, path, body = '', headers = {})
77
+ def make_request(http_method, url, body = '', headers = {})
76
78
  # When using oauth_2legged we need to add an empty oauth_token parameter to every request.
77
79
  if @options[:auth_type] == :oauth_2legged
78
80
  oauth_params_str = 'oauth_token='
79
- uri = URI.parse(path)
81
+ uri = URI.parse(url)
80
82
  uri.query = if uri.query.to_s == ''
81
83
  oauth_params_str
82
84
  else
83
85
  uri.query + '&' + oauth_params_str
84
86
  end
85
- path = uri.to_s
87
+ url = uri.to_s
86
88
  end
87
89
 
88
90
  case http_method
89
91
  when :delete, :get, :head
90
- response = access_token.send http_method, path, headers
92
+ response = access_token.send http_method, url, headers
91
93
  when :post, :put
92
- response = access_token.send http_method, path, body, headers
94
+ response = access_token.send http_method, url, body, headers
93
95
  end
94
96
  @authenticated = true
95
97
  response
96
98
  end
97
99
 
100
+ def make_multipart_request(url, data, headers = {})
101
+ request = Net::HTTP::Post::Multipart.new url, data, headers
102
+
103
+ access_token.sign! request
104
+
105
+ response = consumer.http.request(request)
106
+ @authenticated = true
107
+ response
108
+ end
109
+
98
110
  def authenticated?
99
111
  @authenticated
100
112
  end
@@ -1,7 +1,6 @@
1
1
  require 'oauth'
2
2
  require 'json'
3
3
  require 'net/https'
4
- # require 'pry'
5
4
 
6
5
  module JIRA
7
6
  class RequestClient
@@ -11,9 +10,22 @@ module JIRA
11
10
 
12
11
  def request(*args)
13
12
  response = make_request(*args)
14
- # binding.pry unless response.kind_of?(Net::HTTPSuccess)
15
13
  raise HTTPError, response unless response.is_a?(Net::HTTPSuccess)
16
14
  response
17
15
  end
16
+
17
+ def request_multipart(*args)
18
+ response = make_multipart_request(*args)
19
+ raise HTTPError, response unless response.is_a?(Net::HTTPSuccess)
20
+ response
21
+ end
22
+
23
+ def make_request(*args)
24
+ raise NotImplementedError
25
+ end
26
+
27
+ def make_multipart_request(*args)
28
+ raise NotImplementedError
29
+ end
18
30
  end
19
- end
31
+ end
@@ -19,27 +19,32 @@ module JIRA
19
19
  parse_json(response.body)
20
20
  end
21
21
 
22
- def save!(attrs)
23
- headers = { 'X-Atlassian-Token' => 'nocheck' }
24
- data = { 'file' => UploadIO.new(attrs['file'], 'application/binary', attrs['file']) }
25
-
26
- request = Net::HTTP::Post::Multipart.new url, data, headers
27
- request.basic_auth(client.request_client.options[:username],
28
- client.request_client.options[:password])
22
+ def save!(attrs, path = url)
23
+ file = attrs['file'] || attrs[:file] # Keep supporting 'file' parameter as a string for backward compatibility
24
+ mime_type = attrs[:mimeType] || 'application/binary'
29
25
 
30
- response = client.request_client.basic_auth_http_conn.request(request)
26
+ headers = { 'X-Atlassian-Token' => 'nocheck' }
27
+ data = { 'file' => UploadIO.new(file, mime_type, file) }
31
28
 
32
- set_attrs(attrs, false)
33
- unless response.body.nil? || response.body.length < 2
34
- json = self.class.parse_json(response.body)
35
- attachment = json[0]
29
+ response = client.post_multipart(path, data , headers)
36
30
 
37
- set_attrs(attachment)
38
- end
31
+ set_attributes(attrs, response)
39
32
 
40
33
  @expanded = false
41
34
  true
42
35
  end
36
+
37
+ private
38
+
39
+ def set_attributes(attributes, response)
40
+ set_attrs(attributes, false)
41
+ return if response.body.nil? || response.body.length < 2
42
+
43
+ json = self.class.parse_json(response.body)
44
+ attachment = json[0]
45
+
46
+ set_attrs(attachment)
47
+ end
43
48
  end
44
49
  end
45
50
  end
@@ -5,7 +5,7 @@ module JIRA
5
5
 
6
6
  class Sprint < JIRA::Base
7
7
  def self.find(client, key)
8
- response = client.get("#{client.options[:site]}/rest/agile/1.0/sprint/#{key}")
8
+ response = client.get(agile_path(client, key))
9
9
  json = parse_json(response.body)
10
10
  client.Sprint.build(json)
11
11
  end
@@ -19,7 +19,7 @@ module JIRA
19
19
 
20
20
  def add_issue(issue)
21
21
  request_body = { issues: [issue.id] }.to_json
22
- response = client.post(client.options[:site] + "/rest/agile/1.0/sprint/#{id}/issue", request_body)
22
+ response = client.post("#{agile_path}/issue", request_body)
23
23
  true
24
24
  end
25
25
 
@@ -47,8 +47,8 @@ module JIRA
47
47
  end
48
48
 
49
49
  def get_sprint_details
50
- search_url = client.options[:site] + '/rest/greenhopper/1.0/rapid/charts/sprintreport?rapidViewId=' +
51
- rapidview_id.to_s + '&sprintId=' + id.to_s
50
+ search_url =
51
+ "#{client.options[:site]}#{client.options[:client_path]}/rest/greenhopper/1.0/rapid/charts/sprintreport?rapidViewId=#{rapidview_id}&sprintId=#{id}"
52
52
  begin
53
53
  response = client.get(search_url)
54
54
  rescue StandardError
@@ -76,12 +76,12 @@ module JIRA
76
76
 
77
77
  def save(attrs = {}, _path = nil)
78
78
  attrs = @attrs if attrs.empty?
79
- super(attrs, agile_url)
79
+ super(attrs, agile_path)
80
80
  end
81
81
 
82
82
  def save!(attrs = {}, _path = nil)
83
83
  attrs = @attrs if attrs.empty?
84
- super(attrs, agile_url)
84
+ super(attrs, agile_path)
85
85
  end
86
86
 
87
87
  # WORK IN PROGRESS
@@ -93,8 +93,12 @@ module JIRA
93
93
 
94
94
  private
95
95
 
96
- def agile_url
97
- "#{client.options[:site]}/rest/agile/1.0/sprint/#{id}"
96
+ def agile_path
97
+ self.class.agile_path(client, id)
98
+ end
99
+
100
+ def self.agile_path(client, key)
101
+ "#{client.options[:context_path]}/rest/agile/1.0/sprint/#{key}"
98
102
  end
99
103
  end
100
104
  end
@@ -23,6 +23,13 @@ module JIRA
23
23
  issue.watchers.build(watcher)
24
24
  end
25
25
  end
26
+
27
+ def save!(user_id, path = nil)
28
+ path ||= new_record? ? url : patched_url
29
+ response = client.post(path, user_id.to_json)
30
+ true
31
+ end
32
+
26
33
  end
27
34
  end
28
35
  end
@@ -1,3 +1,3 @@
1
1
  module JIRA
2
- VERSION = '1.8.0'.freeze
2
+ VERSION = '2.1.3'.freeze
3
3
  end
@@ -33,21 +33,30 @@ describe JIRA::Resource::Watcher do
33
33
  end
34
34
 
35
35
  describe 'watchers' do
36
- it 'should returns all the watchers' do
37
- stub_request(:get,
38
- site_url + '/jira/rest/api/2/issue/10002')
36
+ before(:each) do
37
+ stub_request(:get, site_url + '/jira/rest/api/2/issue/10002')
39
38
  .to_return(status: 200, body: get_mock_response('issue/10002.json'))
40
39
 
41
- stub_request(:get,
42
- site_url + '/jira/rest/api/2/issue/10002/watchers')
40
+ stub_request(:get, site_url + '/jira/rest/api/2/issue/10002/watchers')
43
41
  .to_return(status: 200, body: get_mock_response('issue/10002/watchers.json'))
44
42
 
43
+ stub_request(:post, site_url + '/jira/rest/api/2/issue/10002/watchers')
44
+ .to_return(status: 204, body: nil)
45
+ end
46
+
47
+ it 'should returns all the watchers' do
45
48
  issue = client.Issue.find('10002')
46
49
  watchers = client.Watcher.all(options = { issue: issue })
47
50
  expect(watchers.length).to eq(1)
48
51
  end
52
+
53
+ it 'should add a watcher' do
54
+ issue = client.Issue.find('10002')
55
+ watcher = JIRA::Resource::Watcher.new(client, issue: issue)
56
+ user_id = "tester"
57
+ watcher.save!(user_id)
58
+ end
49
59
  end
50
60
 
51
- it_should_behave_like 'a resource'
52
61
  end
53
62
  end
@@ -369,6 +369,18 @@ describe JIRA::Base do
369
369
  expect(subject.url).to eq('http://foo/bar')
370
370
  end
371
371
 
372
+ it 'returns path as the URL if set and site options is specified' do
373
+ allow(client).to receive(:options) { { site: 'http://foo' } }
374
+ attrs['self'] = 'http://foo/bar'
375
+ expect(subject.url).to eq('/bar')
376
+ end
377
+
378
+ it 'returns path as the URL if set and site options is specified and ends with a slash' do
379
+ allow(client).to receive(:options) { { site: 'http://foo/' } }
380
+ attrs['self'] = 'http://foo/bar'
381
+ expect(subject.url).to eq('/bar')
382
+ end
383
+
372
384
  it 'generates the URL from id if self not set' do
373
385
  attrs['self'] = nil
374
386
  attrs['id'] = '98765'
@@ -59,6 +59,19 @@ RSpec.shared_examples 'Client Common Tests' do
59
59
  expect(subject.Project.find('123')).to eq(find_result)
60
60
  end
61
61
  end
62
+
63
+ describe 'SSL client options' do
64
+ context 'without certificate and key' do
65
+ let(:options) { { use_client_cert: true } }
66
+ subject { JIRA::Client.new(options) }
67
+
68
+ it 'raises an ArgumentError' do
69
+ expect { subject }.to raise_exception(ArgumentError, 'Options: :cert_path or :ssl_client_cert must be set when :use_client_cert is true')
70
+ options[:ssl_client_cert] = '<cert></cert>'
71
+ expect { subject }.to raise_exception(ArgumentError, 'Options: :key_path or :ssl_client_key must be set when :use_client_cert is true')
72
+ end
73
+ end
74
+ end
62
75
  end
63
76
 
64
77
  RSpec.shared_examples 'HttpClient tests' do
@@ -266,4 +279,13 @@ describe JIRA::Client do
266
279
 
267
280
  include_examples 'OAuth Common Tests'
268
281
  end
282
+
283
+ context 'with unknown options' do
284
+ let(:options) { { 'username' => 'foo', 'password' => 'bar', auth_type: :basic } }
285
+ subject { JIRA::Client.new(options) }
286
+
287
+ it 'raises an ArgumentError' do
288
+ expect { subject }.to raise_exception(ArgumentError, 'Unknown option(s) given: ["username", "password"]')
289
+ end
290
+ end
269
291
  end
@@ -280,8 +280,8 @@ describe JIRA::HttpClient do
280
280
  expect(http_conn).to receive(:use_ssl=).with(basic_client.options[:use_ssl])
281
281
  expect(http_conn).to receive(:verify_mode=).with(basic_client.options[:ssl_verify_mode])
282
282
  expect(http_conn).to receive(:read_timeout=).with(basic_client.options[:read_timeout])
283
- expect(http_conn).to receive(:cert=).with(basic_client_cert_client.options[:cert])
284
- expect(http_conn).to receive(:key=).with(basic_client_cert_client.options[:key])
283
+ expect(http_conn).to receive(:cert=).with(basic_client_cert_client.options[:ssl_client_cert])
284
+ expect(http_conn).to receive(:key=).with(basic_client_cert_client.options[:ssl_client_key])
285
285
  expect(basic_client_cert_client.http_conn(uri)).to eq(http_conn)
286
286
  end
287
287
 
@@ -292,4 +292,37 @@ describe JIRA::HttpClient do
292
292
  expect(basic_client).to receive(:http_conn).and_return(http_conn)
293
293
  expect(basic_client.basic_auth_http_conn).to eq(http_conn)
294
294
  end
295
+
296
+ describe '#make_multipart_request' do
297
+ subject do
298
+ basic_client.make_multipart_request(path, data, headers)
299
+ end
300
+
301
+ let(:path) { '/foo' }
302
+ let(:data) { {} }
303
+ let(:headers) { { 'X-Atlassian-Token' => 'no-check' } }
304
+ let(:basic_auth_http_conn) { double }
305
+ let(:request) { double('Http Request', path: path) }
306
+ let(:response) { double('response') }
307
+
308
+ before do
309
+ allow(request).to receive(:basic_auth)
310
+ allow(Net::HTTP::Post::Multipart).to receive(:new).with(path, data, headers).and_return(request)
311
+ allow(basic_client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn)
312
+ allow(basic_auth_http_conn).to receive(:request).with(request).and_return(response)
313
+ end
314
+
315
+ it 'performs a basic http client request' do
316
+ expect(request).to receive(:basic_auth).with(basic_client.options[:username], basic_client.options[:password]).and_return(request)
317
+
318
+ subject
319
+ end
320
+
321
+ it 'makes a correct HTTP request' do
322
+ expect(basic_auth_http_conn).to receive(:request).with(request).and_return(response)
323
+ expect(response).to receive(:is_a?).with(Net::HTTPOK)
324
+
325
+ subject
326
+ end
327
+ end
295
328
  end
@@ -82,28 +82,45 @@ describe JIRA::OauthClient do
82
82
  end
83
83
 
84
84
  describe 'http' do
85
+ let(:headers) { double }
86
+ let(:access_token) { double }
87
+ let(:body) { nil }
88
+
89
+ before do
90
+ allow(oauth_client).to receive(:access_token).and_return(access_token)
91
+ end
92
+
85
93
  it 'responds to the http methods' do
86
- headers = double
87
- mock_access_token = double
88
- allow(oauth_client).to receive(:access_token).and_return(mock_access_token)
89
94
  %i[delete get head].each do |method|
90
- expect(mock_access_token).to receive(method).with('/path', headers).and_return(response)
95
+ expect(access_token).to receive(method).with('/path', headers).and_return(response)
91
96
  oauth_client.make_request(method, '/path', '', headers)
92
97
  end
93
98
  %i[post put].each do |method|
94
- expect(mock_access_token).to receive(method).with('/path', '', headers).and_return(response)
99
+ expect(access_token).to receive(method).with('/path', '', headers).and_return(response)
95
100
  oauth_client.make_request(method, '/path', '', headers)
96
101
  end
97
102
  end
98
103
 
99
104
  it 'performs a request' do
100
- body = nil
101
- headers = double
102
- access_token = double
103
105
  expect(access_token).to receive(:send).with(:get, '/foo', headers).and_return(response)
104
- allow(oauth_client).to receive(:access_token).and_return(access_token)
106
+
107
+
105
108
  oauth_client.request(:get, '/foo', body, headers)
106
109
  end
110
+
111
+ context 'for a multipart request' do
112
+ subject { oauth_client.make_multipart_request('/path', data, headers) }
113
+
114
+ let(:data) { {} }
115
+ let(:headers) { {} }
116
+
117
+ it 'signs the access_token and performs the request' do
118
+ expect(access_token).to receive(:sign!).with(an_instance_of(Net::HTTP::Post::Multipart))
119
+ expect(oauth_client.consumer).to receive_message_chain(:http, :request).with(an_instance_of(Net::HTTP::Post::Multipart))
120
+
121
+ subject
122
+ end
123
+ end
107
124
  end
108
125
 
109
126
  describe 'auth type is oauth_2legged' do
@@ -142,4 +159,4 @@ describe JIRA::OauthClient do
142
159
  end
143
160
  end
144
161
  end
145
- end
162
+ end
@@ -1,14 +1,41 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe JIRA::RequestClient do
4
- it 'raises an exception for non success responses' do
5
- response = double
6
- allow(response).to receive(:kind_of?).with(Net::HTTPSuccess).and_return(false)
7
- rc = JIRA::RequestClient.new
8
- expect(rc).to receive(:make_request).with(:get, '/foo', '', {}).and_return(response)
9
-
10
- expect do
11
- rc.request(:get, '/foo', '', {})
12
- end.to raise_exception(JIRA::HTTPError)
4
+ let(:request_client) { JIRA::RequestClient.new }
5
+
6
+ describe '#request' do
7
+ subject(:request) { request_client.request(:get, '/foo', '', {}) }
8
+
9
+ context 'when doing a request fails' do
10
+ let(:response) { double }
11
+
12
+ before do
13
+ allow(response).to receive(:kind_of?).with(Net::HTTPSuccess).and_return(false)
14
+ allow(request_client).to receive(:make_request).with(:get, '/foo', '', {}).and_return(response)
15
+ end
16
+
17
+ it 'raises an exception' do
18
+ expect{ subject }.to raise_exception(JIRA::HTTPError)
19
+ end
20
+ end
21
+ end
22
+
23
+ describe '#request_multipart' do
24
+ subject(:request) { request_client.request_multipart('/foo', data, {}) }
25
+
26
+ let(:data) { double }
27
+
28
+ context 'when doing a request fails' do
29
+ let(:response) { double }
30
+
31
+ before do
32
+ allow(response).to receive(:kind_of?).with(Net::HTTPSuccess).and_return(false)
33
+ allow(request_client).to receive(:make_multipart_request).with('/foo', data, {}).and_return(response)
34
+ end
35
+
36
+ it 'raises an exception' do
37
+ expect{ subject }.to raise_exception(JIRA::HTTPError)
38
+ end
39
+ end
13
40
  end
14
- end
41
+ end
@@ -1,6 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe JIRA::Resource::Attachment do
4
+ subject(:attachment) do
5
+ JIRA::Resource::Attachment.new(
6
+ client,
7
+ issue: JIRA::Resource::Issue.new(client),
8
+ attrs: { 'author' => { 'foo' => 'bar' } }
9
+ )
10
+ end
11
+
4
12
  let(:client) do
5
13
  double(
6
14
  'client',
@@ -17,42 +25,78 @@ describe JIRA::Resource::Attachment do
17
25
  end
18
26
 
19
27
  describe 'relationships' do
20
- subject do
21
- JIRA::Resource::Attachment.new(client,
22
- issue: JIRA::Resource::Issue.new(client),
23
- attrs: { 'author' => { 'foo' => 'bar' } })
28
+ it 'has an author' do
29
+ expect(subject).to have_one(:author, JIRA::Resource::User)
24
30
  end
25
31
 
26
- it 'has the correct relationships' do
27
- expect(subject).to have_one(:author, JIRA::Resource::User)
32
+ it 'has the correct author name' do
28
33
  expect(subject.author.foo).to eq('bar')
29
34
  end
30
35
  end
31
36
 
32
- describe '#meta' do
37
+ describe '.meta' do
38
+ subject { JIRA::Resource::Attachment.meta(client) }
39
+
33
40
  let(:response) do
34
41
  double(
35
- 'response',
36
- body: '{"enabled":true,"uploadLimit":10485760}'
42
+ 'response',
43
+ body: '{"enabled":true,"uploadLimit":10485760}'
37
44
  )
38
45
  end
39
46
 
40
47
  it 'returns meta information about attachment upload' do
41
48
  expect(client).to receive(:get).with('/jira/rest/api/2/attachment/meta').and_return(response)
42
- JIRA::Resource::Attachment.meta(client)
49
+
50
+ subject
43
51
  end
44
52
 
45
- subject { JIRA::Resource::AttachmentFactory.new(client) }
53
+ context 'the factory delegates correctly' do
54
+ subject { JIRA::Resource::AttachmentFactory.new(client) }
46
55
 
47
- it 'delegates #meta to to target class' do
48
- expect(subject).to respond_to(:meta)
56
+ it 'delegates #meta to to target class' do
57
+ expect(subject).to respond_to(:meta)
58
+ end
49
59
  end
50
60
  end
51
61
 
52
- describe '#save!' do
62
+ describe '#save' do
63
+ subject { attachment.save('file' => path_to_file) }
64
+ let(:path_to_file) { './spec/mock_responses/issue.json' }
65
+ let(:response) do
66
+ double(
67
+ body: [
68
+ {
69
+ "id": 10_001,
70
+ "self": 'http://www.example.com/jira/rest/api/2.0/attachments/10000',
71
+ "filename": 'picture.jpg',
72
+ "created": '2017-07-19T12:23:06.572+0000',
73
+ "size": 23_123,
74
+ "mimeType": 'image/jpeg'
75
+ }
76
+ ].to_json
77
+ )
78
+ end
79
+ let(:issue) { JIRA::Resource::Issue.new(client) }
80
+
81
+ before do
82
+ allow(client).to receive(:post_multipart).and_return(response)
83
+ end
84
+
53
85
  it 'successfully update the attachment' do
54
- basic_auth_http_conn = double
55
- response = double(
86
+ subject
87
+
88
+ expect(attachment.filename).to eq 'picture.jpg'
89
+ expect(attachment.mimeType).to eq 'image/jpeg'
90
+ expect(attachment.size).to eq 23_123
91
+ end
92
+ end
93
+
94
+ describe '#save!' do
95
+ subject { attachment.save!('file' => path_to_file) }
96
+
97
+ let(:path_to_file) { './spec/mock_responses/issue.json' }
98
+ let(:response) do
99
+ double(
56
100
  body: [
57
101
  {
58
102
  "id": 10_001,
@@ -64,18 +108,31 @@ describe JIRA::Resource::Attachment do
64
108
  }
65
109
  ].to_json
66
110
  )
111
+ end
112
+ let(:issue) { JIRA::Resource::Issue.new(client) }
67
113
 
68
- allow(client.request_client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn)
69
- allow(basic_auth_http_conn).to receive(:request).and_return(response)
114
+ before do
115
+ allow(client).to receive(:post_multipart).and_return(response)
116
+ end
70
117
 
71
- issue = JIRA::Resource::Issue.new(client)
72
- path_to_file = './spec/mock_responses/issue.json'
73
- attachment = JIRA::Resource::Attachment.new(client, issue: issue)
74
- attachment.save!('file' => path_to_file)
118
+ it 'successfully update the attachment' do
119
+ subject
75
120
 
76
121
  expect(attachment.filename).to eq 'picture.jpg'
77
122
  expect(attachment.mimeType).to eq 'image/jpeg'
78
123
  expect(attachment.size).to eq 23_123
79
124
  end
125
+
126
+ context 'when passing in a symbol as file key' do
127
+ subject { attachment.save!(file: path_to_file) }
128
+
129
+ it 'successfully update the attachment' do
130
+ subject
131
+
132
+ expect(attachment.filename).to eq 'picture.jpg'
133
+ expect(attachment.mimeType).to eq 'image/jpeg'
134
+ expect(attachment.size).to eq 23_123
135
+ end
136
+ end
80
137
  end
81
138
  end
@@ -1,12 +1,25 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe JIRA::Resource::Sprint do
4
- describe 'peristence' do
5
- let(:sprint) { described_class.new(client) }
6
- let(:client) { double('Client', options: { site: 'https://foo.bar.com' }) }
4
+ let(:client) do
5
+ client = double(options: { site: 'https://foo.bar.com', context_path: '/jira' })
6
+ allow(client).to receive(:Sprint).and_return(JIRA::Resource::SprintFactory.new(client))
7
+ client
8
+ end
9
+ let(:sprint) { described_class.new(client) }
10
+ let(:agile_sprint_path) { "#{sprint.client.options[:context_path]}/rest/agile/1.0/sprint/#{sprint.id}" }
7
11
 
12
+ describe '::find' do
13
+ let(:response) { double('Response', body: '{"some_detail":"some detail"}') }
14
+
15
+ it 'fetches the sprint from JIRA' do
16
+ expect(client).to receive(:get).with('/jira/rest/agile/1.0/sprint/111').and_return(response)
17
+ expect(JIRA::Resource::Sprint.find(client, '111')).to be_a(JIRA::Resource::Sprint)
18
+ end
19
+ end
20
+
21
+ describe 'peristence' do
8
22
  describe '#save' do
9
- let(:agile_sprint_url) { "#{sprint.client.options[:site]}/rest/agile/1.0/sprint/#{sprint.id}" }
10
23
  let(:instance_attrs) { { start_date: '2016-06-01' } }
11
24
 
12
25
  before do
@@ -17,7 +30,7 @@ describe JIRA::Resource::Sprint do
17
30
  let(:given_attrs) { { start_date: '2016-06-10' } }
18
31
 
19
32
  it 'calls save on the super class with the given attributes & agile url' do
20
- expect_any_instance_of(JIRA::Base).to receive(:save).with(given_attrs, agile_sprint_url)
33
+ expect_any_instance_of(JIRA::Base).to receive(:save).with(given_attrs, agile_sprint_path)
21
34
 
22
35
  sprint.save(given_attrs)
23
36
  end
@@ -25,7 +38,7 @@ describe JIRA::Resource::Sprint do
25
38
 
26
39
  context 'when attributes are not specified' do
27
40
  it 'calls save on the super class with the instance attributes & agile url' do
28
- expect_any_instance_of(JIRA::Base).to receive(:save).with(instance_attrs, agile_sprint_url)
41
+ expect_any_instance_of(JIRA::Base).to receive(:save).with(instance_attrs, agile_sprint_path)
29
42
 
30
43
  sprint.save
31
44
  end
@@ -33,7 +46,7 @@ describe JIRA::Resource::Sprint do
33
46
 
34
47
  context 'when providing the path argument' do
35
48
  it 'ignores it' do
36
- expect_any_instance_of(JIRA::Base).to receive(:save).with(instance_attrs, agile_sprint_url)
49
+ expect_any_instance_of(JIRA::Base).to receive(:save).with(instance_attrs, agile_sprint_path)
37
50
 
38
51
  sprint.save({}, 'mavenlink.com')
39
52
  end
@@ -41,7 +54,6 @@ describe JIRA::Resource::Sprint do
41
54
  end
42
55
 
43
56
  describe '#save!' do
44
- let(:agile_sprint_url) { "#{sprint.client.options[:site]}/rest/agile/1.0/sprint/#{sprint.id}" }
45
57
  let(:instance_attrs) { { start_date: '2016-06-01' } }
46
58
 
47
59
  before do
@@ -52,7 +64,7 @@ describe JIRA::Resource::Sprint do
52
64
  let(:given_attrs) { { start_date: '2016-06-10' } }
53
65
 
54
66
  it 'calls save! on the super class with the given attributes & agile url' do
55
- expect_any_instance_of(JIRA::Base).to receive(:save!).with(given_attrs, agile_sprint_url)
67
+ expect_any_instance_of(JIRA::Base).to receive(:save!).with(given_attrs, agile_sprint_path)
56
68
 
57
69
  sprint.save!(given_attrs)
58
70
  end
@@ -60,7 +72,7 @@ describe JIRA::Resource::Sprint do
60
72
 
61
73
  context 'when attributes are not specified' do
62
74
  it 'calls save! on the super class with the instance attributes & agile url' do
63
- expect_any_instance_of(JIRA::Base).to receive(:save!).with(instance_attrs, agile_sprint_url)
75
+ expect_any_instance_of(JIRA::Base).to receive(:save!).with(instance_attrs, agile_sprint_path)
64
76
 
65
77
  sprint.save!
66
78
  end
@@ -68,7 +80,7 @@ describe JIRA::Resource::Sprint do
68
80
 
69
81
  context 'when providing the path argument' do
70
82
  it 'ignores it' do
71
- expect_any_instance_of(JIRA::Base).to receive(:save!).with(instance_attrs, agile_sprint_url)
83
+ expect_any_instance_of(JIRA::Base).to receive(:save!).with(instance_attrs, agile_sprint_path)
72
84
 
73
85
  sprint.save!({}, 'mavenlink.com')
74
86
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jira-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 2.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - SUMO Heavy Industries
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-03-14 00:00:00.000000000 Z
12
+ date: 2020-07-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport