jira-ruby 1.7.0 → 2.1.1

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: 0e2f1a7c44350f6423550154d1dd1929e38f5c2af002ebc463eef3bfa035b404
4
- data.tar.gz: 4c2eb811cb02e66ff324a062fa27edaed2cf215b87cc89856a42dde1618fb3c5
3
+ metadata.gz: 4134942b3228eb9c8b459a5c237b269fd4a0e1acf68c853aa1ecaae68a7f5c09
4
+ data.tar.gz: 1d8e205e64c61c9b27ff2a60c7d7cb5ef07de9c33c15da33d17875fc671676e4
5
5
  SHA512:
6
- metadata.gz: 24f0604ca0ad23f7a4204b920f4ec90ec816033c607db5686cde519a0a00668ddf13828f03769f07f0a6cd36bee51186b02164e91ed144cf0892b5cd124d5df8
7
- data.tar.gz: 2c7866e454e455465103803030f1fb40708d1ff9e04c09975594423884c5f84ceb43afb7ba853209ac26e8c9e12a91d3268b80452f8fb3641eee4a1556a787a8
6
+ metadata.gz: 30e17a5592edf781b456616b61405cc1999a24214171f835577631b9ff20526cb4d2d145fdc10c6d7e95d6d73449c4b8dbb78a7c249355166b8a06a405aea4f8
7
+ data.tar.gz: f159cdc2aacd86ef037cb54419ed6c57c09b61f864377affd1b6daba15a75ab6a6dd6e3092a1d22672087717c163ac6862ffb80d2eb0a1e95f58305d3c9d6e40
data/.gitignore CHANGED
@@ -9,3 +9,5 @@ pkg/*
9
9
  .DS_STORE
10
10
  doc
11
11
  .ruby-version
12
+
13
+ .rakeTasks
@@ -1,8 +1,9 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.3
4
3
  - 2.4
5
- - ruby-head
4
+ - 2.5
5
+ - 2.6
6
+ - 2.7
6
7
  before_script:
7
8
  - rake jira:generate_public_cert
8
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",
@@ -13,8 +13,6 @@ Gem::Specification.new do |s|
13
13
 
14
14
  s.required_ruby_version = '>= 1.9.3'
15
15
 
16
- s.rubyforge_project = 'jira-ruby'
17
-
18
16
  s.files = `git ls-files`.split("\n")
19
17
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
18
  s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
@@ -38,6 +38,7 @@ require 'jira/resource/createmeta'
38
38
  require 'jira/resource/webhook'
39
39
  require 'jira/resource/agile'
40
40
  require 'jira/resource/board'
41
+ require 'jira/resource/board_configuration'
41
42
 
42
43
  require 'jira/request_client'
43
44
  require 'jira/oauth_client'
@@ -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)
@@ -19,14 +19,21 @@ module JIRA
19
19
  # :consumer_key => nil,
20
20
  # :consumer_secret => nil,
21
21
  # :ssl_verify_mode => OpenSSL::SSL::VERIFY_PEER,
22
+ # :ssl_version => nil,
22
23
  # :use_ssl => true,
23
24
  # :username => nil,
24
25
  # :password => nil,
25
26
  # :auth_type => :oauth,
26
27
  # :proxy_address => nil,
27
28
  # :proxy_port => nil,
29
+ # :proxy_username => nil,
30
+ # :proxy_password => nil,
28
31
  # :additional_cookies => nil,
29
- # :default_headers => {}
32
+ # :default_headers => {},
33
+ # :use_client_cert => false,
34
+ # :read_timeout => nil,
35
+ # :http_debug => false,
36
+ # :shared_secret => nil
30
37
  #
31
38
  # See the JIRA::Base class methods for all of the available methods on these accessor
32
39
  # objects.
@@ -45,6 +52,37 @@ module JIRA
45
52
 
46
53
  def_delegators :@request_client, :init_access_token, :set_access_token, :set_request_token, :request_token, :access_token, :authenticated?
47
54
 
55
+ DEFINED_OPTIONS = [
56
+ :site,
57
+ :context_path,
58
+ :signature_method,
59
+ :request_token_path,
60
+ :authorize_path,
61
+ :access_token_path,
62
+ :private_key_file,
63
+ :rest_base_path,
64
+ :consumer_key,
65
+ :consumer_secret,
66
+ :ssl_verify_mode,
67
+ :ssl_version,
68
+ :use_ssl,
69
+ :username,
70
+ :password,
71
+ :auth_type,
72
+ :proxy_address,
73
+ :proxy_port,
74
+ :proxy_username,
75
+ :proxy_password,
76
+ :additional_cookies,
77
+ :default_headers,
78
+ :use_client_cert,
79
+ :read_timeout,
80
+ :http_debug,
81
+ :issuer,
82
+ :base_url,
83
+ :shared_secret
84
+ ].freeze
85
+
48
86
  DEFAULT_OPTIONS = {
49
87
  site: 'http://localhost:2990',
50
88
  context_path: '/jira',
@@ -62,6 +100,9 @@ module JIRA
62
100
  @options = options
63
101
  @options[:rest_base_path] = @options[:context_path] + @options[:rest_base_path]
64
102
 
103
+ unknown_options = options.keys.reject { |o| DEFINED_OPTIONS.include?(o) }
104
+ raise ArgumentError, "Unknown option(s) given: #{unknown_options}" unless unknown_options.empty?
105
+
65
106
  if options[:use_client_cert]
66
107
  raise ArgumentError, 'Options: :cert_path must be set when :use_client_cert is true' unless @options[:cert_path]
67
108
  raise ArgumentError, 'Options: :key_path must be set when :use_client_cert is true' unless @options[:key_path]
@@ -159,6 +200,10 @@ module JIRA
159
200
  JIRA::Resource::BoardFactory.new(self)
160
201
  end
161
202
 
203
+ def BoardConfiguration
204
+ JIRA::Resource::BoardConfigurationFactory.new(self)
205
+ end
206
+
162
207
  def RapidView
163
208
  JIRA::Resource::RapidViewFactory.new(self)
164
209
  end
@@ -203,10 +248,6 @@ module JIRA
203
248
  JIRA::Resource::RemotelinkFactory.new(self)
204
249
  end
205
250
 
206
- def Sprint
207
- JIRA::Resource::SprintFactory.new(self)
208
- end
209
-
210
251
  def Agile
211
252
  JIRA::Resource::AgileFactory.new(self)
212
253
  end
@@ -230,6 +271,11 @@ module JIRA
230
271
  request(:post, path, body, merge_default_headers(headers))
231
272
  end
232
273
 
274
+ def post_multipart(path, file, headers = {})
275
+ puts "post multipart: #{path} - [#{file}]" if @http_debug
276
+ @request_client.request_multipart(path, file, headers)
277
+ end
278
+
233
279
  def put(path, body = '', headers = {})
234
280
  headers = { 'Content-Type' => 'application/json' }.merge(headers)
235
281
  request(:put, path, body, merge_default_headers(headers))
@@ -6,8 +6,8 @@ require 'uri'
6
6
  module JIRA
7
7
  class HttpClient < RequestClient
8
8
  DEFAULT_OPTIONS = {
9
- username: '',
10
- password: ''
9
+ username: nil,
10
+ password: nil
11
11
  }.freeze
12
12
 
13
13
  attr_reader :options
@@ -18,7 +18,7 @@ module JIRA
18
18
  end
19
19
 
20
20
  def make_cookie_auth_request
21
- body = { username: @options[:username], password: @options[:password] }.to_json
21
+ body = { username: @options[:username].to_s, password: @options[:password].to_s }.to_json
22
22
  @options.delete(:username)
23
23
  @options.delete(:password)
24
24
  make_request(:post, @options[:context_path] + '/rest/auth/1/session', body, 'Content-Type' => 'application/json')
@@ -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
@@ -43,7 +46,7 @@ module JIRA
43
46
 
44
47
  def http_conn(uri)
45
48
  if @options[:proxy_address]
46
- http_class = Net::HTTP::Proxy(@options[:proxy_address], @options[:proxy_port] || 80)
49
+ http_class = Net::HTTP::Proxy(@options[:proxy_address], @options[:proxy_port] || 80, @options[:proxy_username], @options[:proxy_password])
47
50
  else
48
51
  http_class = Net::HTTP
49
52
  end
@@ -54,12 +57,13 @@ module JIRA
54
57
  http_conn.key = @options[:key]
55
58
  end
56
59
  http_conn.verify_mode = @options[:ssl_verify_mode]
60
+ http_conn.ssl_version = @options[:ssl_version] if @options[:ssl_version]
57
61
  http_conn.read_timeout = @options[:read_timeout]
58
62
  http_conn
59
63
  end
60
64
 
61
65
  def uri
62
- uri = URI.parse(@options[:site])
66
+ URI.parse(@options[:site])
63
67
  end
64
68
 
65
69
  def authenticated?
@@ -68,6 +72,17 @@ module JIRA
68
72
 
69
73
  private
70
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
+
71
86
  def request_path(url)
72
87
  parsed_uri = URI(url)
73
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,30 +3,65 @@ 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(url) + "?jwt=#{jwt_header(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)
15
+ end
16
+
17
+ class JwtUriBuilder
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
37
+
38
+ private
39
+
40
+ def jwt_header
41
+ claim = Atlassian::Jwt.build_claims \
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
48
+
49
+ JWT.encode claim, shared_secret
50
+ end
16
51
  end
17
52
 
18
53
  private
19
54
 
20
- def jwt_header(http_method, url)
21
- claim = Atlassian::Jwt.build_claims \
22
- @options[:issuer],
55
+ attr_reader :http_method
56
+
57
+ def request_path(url)
58
+ JwtUriBuilder.new(
23
59
  url,
24
60
  http_method.to_s,
61
+ @options[:shared_secret],
25
62
  @options[:site],
26
- (Time.now - 60).to_i,
27
- (Time.now + (86400)).to_i
28
-
29
- JWT.encode claim, @options[:shared_secret]
63
+ @options[:issuer]
64
+ ).build
30
65
  end
31
66
  end
32
67
  end
@@ -72,29 +72,39 @@ module JIRA
72
72
  @access_token
73
73
  end
74
74
 
75
- def make_request(http_method, path, body = '', headers = {})
75
+ def make_request(http_method, url, body = '', headers = {})
76
76
  # When using oauth_2legged we need to add an empty oauth_token parameter to every request.
77
77
  if @options[:auth_type] == :oauth_2legged
78
78
  oauth_params_str = 'oauth_token='
79
- uri = URI.parse(path)
79
+ uri = URI.parse(url)
80
80
  uri.query = if uri.query.to_s == ''
81
81
  oauth_params_str
82
82
  else
83
83
  uri.query + '&' + oauth_params_str
84
84
  end
85
- path = uri.to_s
85
+ url = uri.to_s
86
86
  end
87
87
 
88
88
  case http_method
89
89
  when :delete, :get, :head
90
- response = access_token.send http_method, path, headers
90
+ response = access_token.send http_method, url, headers
91
91
  when :post, :put
92
- response = access_token.send http_method, path, body, headers
92
+ response = access_token.send http_method, url, body, headers
93
93
  end
94
94
  @authenticated = true
95
95
  response
96
96
  end
97
97
 
98
+ def make_multipart_request(url, data, headers = {})
99
+ request = Net::HTTP::Post::Multipart.new url, data, headers
100
+
101
+ access_token.sign! request
102
+
103
+ response = consumer.http.request(request)
104
+ @authenticated = true
105
+ response
106
+ end
107
+
98
108
  def authenticated?
99
109
  @authenticated
100
110
  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