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/http_client.rb
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'json'
         
     | 
| 
       2 
2 
     | 
    
         
             
            require 'net/https'
         
     | 
| 
       3 
3 
     | 
    
         
             
            require 'cgi/cookie'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'uri'
         
     | 
| 
       4 
5 
     | 
    
         | 
| 
       5 
6 
     | 
    
         
             
            module JIRA
         
     | 
| 
       6 
7 
     | 
    
         
             
              class HttpClient < RequestClient
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
8 
     | 
    
         
             
                DEFAULT_OPTIONS = {
         
     | 
| 
       9 
     | 
    
         
            -
                  : 
     | 
| 
       10 
     | 
    
         
            -
                  : 
     | 
| 
       11 
     | 
    
         
            -
                }
         
     | 
| 
      
 9 
     | 
    
         
            +
                  username: nil,
         
     | 
| 
      
 10 
     | 
    
         
            +
                  password: nil
         
     | 
| 
      
 11 
     | 
    
         
            +
                }.freeze
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
13 
     | 
    
         
             
                attr_reader :options
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
         @@ -18,18 +18,26 @@ module JIRA 
     | 
|
| 
       18 
18 
     | 
    
         
             
                end
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
       20 
20 
     | 
    
         
             
                def make_cookie_auth_request
         
     | 
| 
       21 
     | 
    
         
            -
                  body = { : 
     | 
| 
       22 
     | 
    
         
            -
                   
     | 
| 
      
 21 
     | 
    
         
            +
                  body = { username: @options[:username].to_s, password: @options[:password].to_s }.to_json
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @options.delete(:username)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @options.delete(:password)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  make_request(:post, @options[:context_path] + '/rest/auth/1/session', body, 'Content-Type' => 'application/json')
         
     | 
| 
       23 
25 
     | 
    
         
             
                end
         
     | 
| 
       24 
26 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
                def make_request(http_method,  
     | 
| 
      
 27 
     | 
    
         
            +
                def make_request(http_method, url, body = '', headers = {})
         
     | 
| 
      
 28 
     | 
    
         
            +
                  # When a proxy is enabled, Net::HTTP expects that the request path omits the domain name
         
     | 
| 
      
 29 
     | 
    
         
            +
                  path = request_path(url)
         
     | 
| 
       26 
30 
     | 
    
         
             
                  request = Net::HTTP.const_get(http_method.to_s.capitalize).new(path, headers)
         
     | 
| 
       27 
31 
     | 
    
         
             
                  request.body = body unless body.nil?
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                  request 
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
      
 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)
         
     | 
| 
       33 
41 
     | 
    
         
             
                end
         
     | 
| 
       34 
42 
     | 
    
         | 
| 
       35 
43 
     | 
    
         
             
                def basic_auth_http_conn
         
     | 
| 
         @@ -38,23 +46,52 @@ module JIRA 
     | 
|
| 
       38 
46 
     | 
    
         | 
| 
       39 
47 
     | 
    
         
             
                def http_conn(uri)
         
     | 
| 
       40 
48 
     | 
    
         
             
                  if @options[:proxy_address]
         
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
      
 49 
     | 
    
         
            +
                    http_class = Net::HTTP::Proxy(@options[:proxy_address], @options[:proxy_port] || 80, @options[:proxy_username], @options[:proxy_password])
         
     | 
| 
       42 
50 
     | 
    
         
             
                  else
         
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
      
 51 
     | 
    
         
            +
                    http_class = Net::HTTP
         
     | 
| 
       44 
52 
     | 
    
         
             
                  end
         
     | 
| 
       45 
53 
     | 
    
         
             
                  http_conn = http_class.new(uri.host, uri.port)
         
     | 
| 
       46 
54 
     | 
    
         
             
                  http_conn.use_ssl = @options[:use_ssl]
         
     | 
| 
      
 55 
     | 
    
         
            +
                  if @options[:use_client_cert]
         
     | 
| 
      
 56 
     | 
    
         
            +
                    http_conn.cert = @options[:ssl_client_cert]
         
     | 
| 
      
 57 
     | 
    
         
            +
                    http_conn.key = @options[:ssl_client_key]
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
       47 
59 
     | 
    
         
             
                  http_conn.verify_mode = @options[:ssl_verify_mode]
         
     | 
| 
      
 60 
     | 
    
         
            +
                  http_conn.ssl_version = @options[:ssl_version] if @options[:ssl_version]
         
     | 
| 
       48 
61 
     | 
    
         
             
                  http_conn.read_timeout = @options[:read_timeout]
         
     | 
| 
      
 62 
     | 
    
         
            +
                  http_conn.ca_file = @options[:ca_file] if @options[:ca_file]
         
     | 
| 
       49 
63 
     | 
    
         
             
                  http_conn
         
     | 
| 
       50 
64 
     | 
    
         
             
                end
         
     | 
| 
       51 
65 
     | 
    
         | 
| 
       52 
66 
     | 
    
         
             
                def uri
         
     | 
| 
       53 
     | 
    
         
            -
                   
     | 
| 
      
 67 
     | 
    
         
            +
                  URI.parse(@options[:site])
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                def authenticated?
         
     | 
| 
      
 71 
     | 
    
         
            +
                  @authenticated
         
     | 
| 
       54 
72 
     | 
    
         
             
                end
         
     | 
| 
       55 
73 
     | 
    
         | 
| 
       56 
74 
     | 
    
         
             
                private
         
     | 
| 
       57 
75 
     | 
    
         | 
| 
      
 76 
     | 
    
         
            +
                def execute_request(request)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  add_cookies(request) if options[:use_cookies]
         
     | 
| 
      
 78 
     | 
    
         
            +
                  request.basic_auth(@options[:username], @options[:password]) if @options[:username] && @options[:password]
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  response = basic_auth_http_conn.request(request)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  @authenticated = response.is_a? Net::HTTPOK
         
     | 
| 
      
 82 
     | 
    
         
            +
                  store_cookies(response) if options[:use_cookies]
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                  response
         
     | 
| 
      
 85 
     | 
    
         
            +
                end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                def request_path(url)
         
     | 
| 
      
 88 
     | 
    
         
            +
                  parsed_uri = URI(url)
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                  return url unless parsed_uri.is_a?(URI::HTTP)
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                  parsed_uri.request_uri
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
       58 
95 
     | 
    
         
             
                def store_cookies(response)
         
     | 
| 
       59 
96 
     | 
    
         
             
                  cookies = response.get_fields('set-cookie')
         
     | 
| 
       60 
97 
     | 
    
         
             
                  if cookies
         
     | 
| 
         @@ -67,7 +104,8 @@ module JIRA 
     | 
|
| 
       67 
104 
     | 
    
         
             
                end
         
     | 
| 
       68 
105 
     | 
    
         | 
| 
       69 
106 
     | 
    
         
             
                def add_cookies(request)
         
     | 
| 
       70 
     | 
    
         
            -
                  cookie_array = @cookies.values.map { |cookie| cookie. 
     | 
| 
      
 107 
     | 
    
         
            +
                  cookie_array = @cookies.values.map { |cookie| "#{cookie.name}=#{cookie.value[0]}" }
         
     | 
| 
      
 108 
     | 
    
         
            +
                  cookie_array += Array(@options[:additional_cookies]) if @options.key?(:additional_cookies)
         
     | 
| 
       71 
109 
     | 
    
         
             
                  request.add_field('Cookie', cookie_array.join('; ')) if cookie_array.any?
         
     | 
| 
       72 
110 
     | 
    
         
             
                  request
         
     | 
| 
       73 
111 
     | 
    
         
             
                end
         
     | 
    
        data/lib/jira/http_error.rb
    CHANGED
    
    | 
         @@ -1,16 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'forwardable'
         
     | 
| 
       2 
2 
     | 
    
         
             
            module JIRA
         
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
3 
     | 
    
         
             
              class HTTPError < StandardError
         
     | 
| 
       5 
4 
     | 
    
         
             
                extend Forwardable
         
     | 
| 
       6 
5 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
                def_instance_delegators :@response, : 
     | 
| 
       8 
     | 
    
         
            -
                attr_reader :response
         
     | 
| 
      
 6 
     | 
    
         
            +
                def_instance_delegators :@response, :code
         
     | 
| 
      
 7 
     | 
    
         
            +
                attr_reader :response, :message
         
     | 
| 
       9 
8 
     | 
    
         | 
| 
       10 
9 
     | 
    
         
             
                def initialize(response)
         
     | 
| 
       11 
10 
     | 
    
         
             
                  @response = response
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @message = response.try(:message).presence || response.try(:body)
         
     | 
| 
       12 
12 
     | 
    
         
             
                end
         
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
13 
     | 
    
         
             
              end
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
14 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,67 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'atlassian/jwt'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module JIRA
         
     | 
| 
      
 4 
     | 
    
         
            +
              class JwtClient < HttpClient
         
     | 
| 
      
 5 
     | 
    
         
            +
                def make_request(http_method, url, body = '', headers = {})
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @http_method = http_method
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  super(http_method, url, body, headers)
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def make_multipart_request(url, data, headers = {})
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @http_method = :post
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 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
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                private
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                attr_reader :http_method
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                def request_path(url)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  JwtUriBuilder.new(
         
     | 
| 
      
 59 
     | 
    
         
            +
                    url,
         
     | 
| 
      
 60 
     | 
    
         
            +
                    http_method.to_s,
         
     | 
| 
      
 61 
     | 
    
         
            +
                    @options[:shared_secret],
         
     | 
| 
      
 62 
     | 
    
         
            +
                    @options[:site],
         
     | 
| 
      
 63 
     | 
    
         
            +
                    @options[:issuer]
         
     | 
| 
      
 64 
     | 
    
         
            +
                  ).build
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/jira/oauth_client.rb
    CHANGED
    
    | 
         @@ -4,22 +4,21 @@ require 'forwardable' 
     | 
|
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            module JIRA
         
     | 
| 
       6 
6 
     | 
    
         
             
              class OauthClient < RequestClient
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
7 
     | 
    
         
             
                DEFAULT_OPTIONS = {
         
     | 
| 
       9 
     | 
    
         
            -
                  : 
     | 
| 
       10 
     | 
    
         
            -
                  : 
     | 
| 
       11 
     | 
    
         
            -
                  : 
     | 
| 
       12 
     | 
    
         
            -
                  : 
     | 
| 
       13 
     | 
    
         
            -
                  : 
     | 
| 
       14 
     | 
    
         
            -
                  : 
     | 
| 
       15 
     | 
    
         
            -
                  : 
     | 
| 
       16 
     | 
    
         
            -
                }
         
     | 
| 
      
 8 
     | 
    
         
            +
                  signature_method: 'RSA-SHA1',
         
     | 
| 
      
 9 
     | 
    
         
            +
                  request_token_path: '/plugins/servlet/oauth/request-token',
         
     | 
| 
      
 10 
     | 
    
         
            +
                  authorize_path: '/plugins/servlet/oauth/authorize',
         
     | 
| 
      
 11 
     | 
    
         
            +
                  access_token_path: '/plugins/servlet/oauth/access-token',
         
     | 
| 
      
 12 
     | 
    
         
            +
                  private_key_file: 'rsakey.pem',
         
     | 
| 
      
 13 
     | 
    
         
            +
                  consumer_key: nil,
         
     | 
| 
      
 14 
     | 
    
         
            +
                  consumer_secret: nil
         
     | 
| 
      
 15 
     | 
    
         
            +
                }.freeze
         
     | 
| 
       17 
16 
     | 
    
         | 
| 
       18 
17 
     | 
    
         
             
                # This exception is thrown when the client is used before the OAuth access token
         
     | 
| 
       19 
18 
     | 
    
         
             
                # has been initialized.
         
     | 
| 
       20 
19 
     | 
    
         
             
                class UninitializedAccessTokenError < StandardError
         
     | 
| 
       21 
20 
     | 
    
         
             
                  def message
         
     | 
| 
       22 
     | 
    
         
            -
                     
     | 
| 
      
 21 
     | 
    
         
            +
                    'init_access_token must be called before using the client'
         
     | 
| 
       23 
22 
     | 
    
         
             
                  end
         
     | 
| 
       24 
23 
     | 
    
         
             
                end
         
     | 
| 
       25 
24 
     | 
    
         | 
| 
         @@ -35,17 +34,19 @@ module JIRA 
     | 
|
| 
       35 
34 
     | 
    
         
             
                  @consumer = init_oauth_consumer(@options)
         
     | 
| 
       36 
35 
     | 
    
         
             
                end
         
     | 
| 
       37 
36 
     | 
    
         | 
| 
       38 
     | 
    
         
            -
                def init_oauth_consumer( 
     | 
| 
      
 37 
     | 
    
         
            +
                def init_oauth_consumer(_options)
         
     | 
| 
       39 
38 
     | 
    
         
             
                  @options[:request_token_path] = @options[:context_path] + @options[:request_token_path]
         
     | 
| 
       40 
39 
     | 
    
         
             
                  @options[:authorize_path] = @options[:context_path] + @options[:authorize_path]
         
     | 
| 
       41 
40 
     | 
    
         
             
                  @options[:access_token_path] = @options[:context_path] + @options[:access_token_path]
         
     | 
| 
       42 
     | 
    
         
            -
                   
     | 
| 
      
 41 
     | 
    
         
            +
                  # proxy_address does not exist in oauth's gem context but proxy does
         
     | 
| 
      
 42 
     | 
    
         
            +
                  @options[:proxy] = @options[:proxy_address] if @options[:proxy_address]
         
     | 
| 
      
 43 
     | 
    
         
            +
                  OAuth::Consumer.new(@options[:consumer_key], @options[:consumer_secret], @options)
         
     | 
| 
       43 
44 
     | 
    
         
             
                end
         
     | 
| 
       44 
45 
     | 
    
         | 
| 
       45 
46 
     | 
    
         
             
                # Returns the current request token if it is set, else it creates
         
     | 
| 
       46 
47 
     | 
    
         
             
                # and sets a new token.
         
     | 
| 
       47 
48 
     | 
    
         
             
                def request_token(options = {}, *arguments, &block)
         
     | 
| 
       48 
     | 
    
         
            -
                  @request_token ||= get_request_token(options, *arguments, block)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  @request_token ||= get_request_token(options, *arguments, &block)
         
     | 
| 
       49 
50 
     | 
    
         
             
                end
         
     | 
| 
       50 
51 
     | 
    
         | 
| 
       51 
52 
     | 
    
         
             
                # Sets the request token from a given token and secret.
         
     | 
| 
         @@ -62,23 +63,52 @@ module JIRA 
     | 
|
| 
       62 
63 
     | 
    
         
             
                # Sets the access token from a preexisting token and secret.
         
     | 
| 
       63 
64 
     | 
    
         
             
                def set_access_token(token, secret)
         
     | 
| 
       64 
65 
     | 
    
         
             
                  @access_token = OAuth::AccessToken.new(@consumer, token, secret)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  @authenticated = true
         
     | 
| 
      
 67 
     | 
    
         
            +
                  @access_token
         
     | 
| 
       65 
68 
     | 
    
         
             
                end
         
     | 
| 
       66 
69 
     | 
    
         | 
| 
       67 
70 
     | 
    
         
             
                # Returns the current access token. Raises an
         
     | 
| 
       68 
71 
     | 
    
         
             
                # JIRA::Client::UninitializedAccessTokenError exception if it is not set.
         
     | 
| 
       69 
72 
     | 
    
         
             
                def access_token
         
     | 
| 
       70 
     | 
    
         
            -
                  raise UninitializedAccessTokenError 
     | 
| 
      
 73 
     | 
    
         
            +
                  raise UninitializedAccessTokenError unless @access_token
         
     | 
| 
       71 
74 
     | 
    
         
             
                  @access_token
         
     | 
| 
       72 
75 
     | 
    
         
             
                end
         
     | 
| 
       73 
76 
     | 
    
         | 
| 
       74 
     | 
    
         
            -
                def make_request(http_method,  
     | 
| 
      
 77 
     | 
    
         
            +
                def make_request(http_method, url, body = '', headers = {})
         
     | 
| 
      
 78 
     | 
    
         
            +
                  # When using oauth_2legged we need to add an empty oauth_token parameter to every request.
         
     | 
| 
      
 79 
     | 
    
         
            +
                  if @options[:auth_type] == :oauth_2legged
         
     | 
| 
      
 80 
     | 
    
         
            +
                    oauth_params_str = 'oauth_token='
         
     | 
| 
      
 81 
     | 
    
         
            +
                    uri = URI.parse(url)
         
     | 
| 
      
 82 
     | 
    
         
            +
                    uri.query = if uri.query.to_s == ''
         
     | 
| 
      
 83 
     | 
    
         
            +
                                  oauth_params_str
         
     | 
| 
      
 84 
     | 
    
         
            +
                                else
         
     | 
| 
      
 85 
     | 
    
         
            +
                                  uri.query + '&' + oauth_params_str
         
     | 
| 
      
 86 
     | 
    
         
            +
                                end
         
     | 
| 
      
 87 
     | 
    
         
            +
                    url = uri.to_s
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
       75 
90 
     | 
    
         
             
                  case http_method
         
     | 
| 
       76 
91 
     | 
    
         
             
                  when :delete, :get, :head
         
     | 
| 
       77 
     | 
    
         
            -
                    response = access_token.send http_method,  
     | 
| 
      
 92 
     | 
    
         
            +
                    response = access_token.send http_method, url, headers
         
     | 
| 
       78 
93 
     | 
    
         
             
                  when :post, :put
         
     | 
| 
       79 
     | 
    
         
            -
                    response = access_token.send http_method,  
     | 
| 
      
 94 
     | 
    
         
            +
                    response = access_token.send http_method, url, body, headers
         
     | 
| 
       80 
95 
     | 
    
         
             
                  end
         
     | 
| 
      
 96 
     | 
    
         
            +
                  @authenticated = true
         
     | 
| 
       81 
97 
     | 
    
         
             
                  response
         
     | 
| 
       82 
98 
     | 
    
         
             
                end
         
     | 
| 
      
 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 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                def authenticated?
         
     | 
| 
      
 111 
     | 
    
         
            +
                  @authenticated
         
     | 
| 
      
 112 
     | 
    
         
            +
                end
         
     | 
| 
       83 
113 
     | 
    
         
             
              end
         
     | 
| 
       84 
114 
     | 
    
         
             
            end
         
     | 
    
        data/lib/jira/request_client.rb
    CHANGED
    
    | 
         @@ -1,20 +1,31 @@ 
     | 
|
| 
       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
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
7 
     | 
    
         
             
                # Returns the response if the request was successful (HTTP::2xx) and
         
     | 
| 
       10 
8 
     | 
    
         
             
                # raises a JIRA::HTTPError if it was not successful, with the response
         
     | 
| 
       11 
9 
     | 
    
         
             
                # attached.
         
     | 
| 
       12 
10 
     | 
    
         | 
| 
       13 
11 
     | 
    
         
             
                def request(*args)
         
     | 
| 
       14 
12 
     | 
    
         
             
                  response = make_request(*args)
         
     | 
| 
       15 
     | 
    
         
            -
                   
     | 
| 
       16 
     | 
    
         
            -
                   
     | 
| 
      
 13 
     | 
    
         
            +
                  raise HTTPError, response unless response.is_a?(Net::HTTPSuccess)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  response
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def request_multipart(*args)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  response = make_multipart_request(*args)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  raise HTTPError, response unless response.is_a?(Net::HTTPSuccess)
         
     | 
| 
       17 
20 
     | 
    
         
             
                  response
         
     | 
| 
       18 
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
         
     | 
| 
       19 
30 
     | 
    
         
             
              end
         
     | 
| 
       20 
     | 
    
         
            -
            end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/jira/resource/agile.rb
    CHANGED
    
    | 
         @@ -2,32 +2,59 @@ require 'cgi' 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module JIRA
         
     | 
| 
       4 
4 
     | 
    
         
             
              module Resource
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
5 
     | 
    
         
             
                class AgileFactory < JIRA::BaseFactory # :nodoc:
         
     | 
| 
       7 
6 
     | 
    
         
             
                end
         
     | 
| 
       8 
7 
     | 
    
         | 
| 
       9 
8 
     | 
    
         
             
                class Agile < JIRA::Base
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
                   
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
      
 9 
     | 
    
         
            +
                  # @param client [JIRA::Client]
         
     | 
| 
      
 10 
     | 
    
         
            +
                  # @param options [Hash<Symbol, Object>]
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # @return [Hash]
         
     | 
| 
      
 12 
     | 
    
         
            +
                  def self.all(client, options = {})
         
     | 
| 
      
 13 
     | 
    
         
            +
                    opts = options.empty? ? '' : "?#{hash_to_query_string(options)}"
         
     | 
| 
      
 14 
     | 
    
         
            +
                    response = client.get(path_base(client) + "/board#{opts}")
         
     | 
| 
       13 
15 
     | 
    
         
             
                    parse_json(response.body)
         
     | 
| 
       14 
16 
     | 
    
         
             
                  end
         
     | 
| 
       15 
17 
     | 
    
         | 
| 
       16 
18 
     | 
    
         
             
                  def self.get_backlog_issues(client, board_id, options = {})
         
     | 
| 
       17 
19 
     | 
    
         
             
                    options[:maxResults] ||= 100
         
     | 
| 
       18 
     | 
    
         
            -
                    response = client.get("/ 
     | 
| 
      
 20 
     | 
    
         
            +
                    response = client.get(path_base(client) + "/board/#{board_id}/backlog?#{hash_to_query_string(options)}")
         
     | 
| 
       19 
21 
     | 
    
         
             
                    parse_json(response.body)
         
     | 
| 
       20 
22 
     | 
    
         
             
                  end
         
     | 
| 
       21 
23 
     | 
    
         | 
| 
      
 24 
     | 
    
         
            +
                  def self.get_board_issues(client, board_id, options = {})
         
     | 
| 
      
 25 
     | 
    
         
            +
                    response = client.get(path_base(client) + "/board/#{board_id}/issue?#{hash_to_query_string(options)}")
         
     | 
| 
      
 26 
     | 
    
         
            +
                    json = parse_json(response.body)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    # To get Issue objects with the same structure as for Issue.all
         
     | 
| 
      
 28 
     | 
    
         
            +
                    return {} if json['issues'].size.zero?
         
     | 
| 
      
 29 
     | 
    
         
            +
                    issue_ids = json['issues'].map do |issue|
         
     | 
| 
      
 30 
     | 
    
         
            +
                      issue['id']
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
                    client.Issue.jql("id IN(#{issue_ids.join(', ')})")
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
       22 
35 
     | 
    
         
             
                  def self.get_sprints(client, board_id, options = {})
         
     | 
| 
       23 
36 
     | 
    
         
             
                    options[:maxResults] ||= 100
         
     | 
| 
       24 
     | 
    
         
            -
                    response = client.get("/ 
     | 
| 
      
 37 
     | 
    
         
            +
                    response = client.get(path_base(client) + "/board/#{board_id}/sprint?#{hash_to_query_string(options)}")
         
     | 
| 
       25 
38 
     | 
    
         
             
                    parse_json(response.body)
         
     | 
| 
       26 
39 
     | 
    
         
             
                  end
         
     | 
| 
       27 
40 
     | 
    
         | 
| 
       28 
41 
     | 
    
         
             
                  def self.get_sprint_issues(client, sprint_id, options = {})
         
     | 
| 
       29 
42 
     | 
    
         
             
                    options[:maxResults] ||= 100
         
     | 
| 
       30 
     | 
    
         
            -
                    response = client.get("/ 
     | 
| 
      
 43 
     | 
    
         
            +
                    response = client.get(path_base(client) + "/sprint/#{sprint_id}/issue?#{hash_to_query_string(options)}")
         
     | 
| 
      
 44 
     | 
    
         
            +
                    parse_json(response.body)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  def self.get_projects_full(client, board_id, _options = {})
         
     | 
| 
      
 48 
     | 
    
         
            +
                    response = client.get(path_base(client) + "/board/#{board_id}/project/full")
         
     | 
| 
      
 49 
     | 
    
         
            +
                    parse_json(response.body)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  def self.get_projects(client, board_id, options = {})
         
     | 
| 
      
 53 
     | 
    
         
            +
                    options[:maxResults] ||= 100
         
     | 
| 
      
 54 
     | 
    
         
            +
                    create_meta_url = path_base(client) + "/board/#{board_id}/project"
         
     | 
| 
      
 55 
     | 
    
         
            +
                    params = hash_to_query_string(options)
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                    response = client.get("#{create_meta_url}?#{params}")
         
     | 
| 
       31 
58 
     | 
    
         
             
                    parse_json(response.body)
         
     | 
| 
       32 
59 
     | 
    
         
             
                  end
         
     | 
| 
       33 
60 
     | 
    
         | 
| 
         @@ -47,8 +74,6 @@ module JIRA 
     | 
|
| 
       47 
74 
     | 
    
         
             
                  def path_base(client)
         
     | 
| 
       48 
75 
     | 
    
         
             
                    self.class.path_base(client)
         
     | 
| 
       49 
76 
     | 
    
         
             
                  end
         
     | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
       51 
77 
     | 
    
         
             
                end
         
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
78 
     | 
    
         
             
              end
         
     | 
| 
       54 
79 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,13 +1,11 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module JIRA
         
     | 
| 
       2 
2 
     | 
    
         
             
              module Resource
         
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
3 
     | 
    
         
             
                class ApplicationLinkFactory < JIRA::BaseFactory # :nodoc:
         
     | 
| 
       5 
4 
     | 
    
         
             
                  delegate_to_target_class :manifest
         
     | 
| 
       6 
5 
     | 
    
         
             
                end
         
     | 
| 
       7 
6 
     | 
    
         | 
| 
       8 
7 
     | 
    
         
             
                class ApplicationLink < JIRA::Base
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
                  REST_BASE_PATH = '/rest/applinks/1.0'
         
     | 
| 
      
 8 
     | 
    
         
            +
                  REST_BASE_PATH = '/rest/applinks/1.0'.freeze
         
     | 
| 
       11 
9 
     | 
    
         | 
| 
       12 
10 
     | 
    
         
             
                  def self.endpoint_name
         
     | 
| 
       13 
11 
     | 
    
         
             
                    'listApplicationlinks'
         
     | 
| 
         @@ -18,7 +16,7 @@ module JIRA 
     | 
|
| 
       18 
16 
     | 
    
         
             
                  end
         
     | 
| 
       19 
17 
     | 
    
         | 
| 
       20 
18 
     | 
    
         
             
                  def self.collection_path(client, prefix = '/')
         
     | 
| 
       21 
     | 
    
         
            -
                     
     | 
| 
      
 19 
     | 
    
         
            +
                    full_url(client) + prefix + endpoint_name
         
     | 
| 
       22 
20 
     | 
    
         
             
                  end
         
     | 
| 
       23 
21 
     | 
    
         | 
| 
       24 
22 
     | 
    
         
             
                  def self.all(client, options = {})
         
     | 
| 
         @@ -26,17 +24,16 @@ module JIRA 
     | 
|
| 
       26 
24 
     | 
    
         
             
                    json = parse_json(response.body)
         
     | 
| 
       27 
25 
     | 
    
         
             
                    json = json['list']
         
     | 
| 
       28 
26 
     | 
    
         
             
                    json.map do |attrs|
         
     | 
| 
       29 
     | 
    
         
            -
                       
     | 
| 
      
 27 
     | 
    
         
            +
                      new(client, { attrs: attrs }.merge(options))
         
     | 
| 
       30 
28 
     | 
    
         
             
                    end
         
     | 
| 
       31 
29 
     | 
    
         
             
                  end
         
     | 
| 
       32 
30 
     | 
    
         | 
| 
       33 
31 
     | 
    
         
             
                  def self.manifest(client)
         
     | 
| 
       34 
     | 
    
         
            -
                    url =  
     | 
| 
      
 32 
     | 
    
         
            +
                    url = full_url(client) + '/manifest'
         
     | 
| 
       35 
33 
     | 
    
         
             
                    response = client.get(url)
         
     | 
| 
       36 
34 
     | 
    
         
             
                    json = parse_json(response.body)
         
     | 
| 
       37 
     | 
    
         
            -
                    JIRA::Base.new(client,  
     | 
| 
      
 35 
     | 
    
         
            +
                    JIRA::Base.new(client, attrs: json)
         
     | 
| 
       38 
36 
     | 
    
         
             
                  end
         
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
37 
     | 
    
         
             
                end
         
     | 
| 
       41 
38 
     | 
    
         
             
              end
         
     | 
| 
       42 
39 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,12 +1,50 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'net/http/post/multipart'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module JIRA
         
     | 
| 
       2 
4 
     | 
    
         
             
              module Resource
         
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
5 
     | 
    
         
             
                class AttachmentFactory < JIRA::BaseFactory # :nodoc:
         
     | 
| 
      
 6 
     | 
    
         
            +
                  delegate_to_target_class :meta
         
     | 
| 
       5 
7 
     | 
    
         
             
                end
         
     | 
| 
       6 
8 
     | 
    
         | 
| 
       7 
9 
     | 
    
         
             
                class Attachment < JIRA::Base
         
     | 
| 
       8 
     | 
    
         
            -
                   
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
      
 10 
     | 
    
         
            +
                  belongs_to :issue
         
     | 
| 
      
 11 
     | 
    
         
            +
                  has_one :author, class: JIRA::Resource::User
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def self.endpoint_name
         
     | 
| 
      
 14 
     | 
    
         
            +
                    'attachments'
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  def self.meta(client)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    response = client.get(client.options[:rest_base_path] + '/attachment/meta')
         
     | 
| 
      
 19 
     | 
    
         
            +
                    parse_json(response.body)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 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'
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    headers = { 'X-Atlassian-Token' => 'nocheck' }
         
     | 
| 
      
 27 
     | 
    
         
            +
                    data = { 'file' => UploadIO.new(file, mime_type, file) }
         
     | 
| 
       10 
28 
     | 
    
         | 
| 
      
 29 
     | 
    
         
            +
                    response = client.post_multipart(path, data , headers)
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    set_attributes(attrs, response)
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    @expanded = false
         
     | 
| 
      
 34 
     | 
    
         
            +
                    true
         
     | 
| 
      
 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
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
       11 
49 
     | 
    
         
             
              end
         
     | 
| 
       12 
50 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,91 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'cgi'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module JIRA
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Resource
         
     | 
| 
      
 5 
     | 
    
         
            +
                class BoardFactory < JIRA::BaseFactory # :nodoc:
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                class Board < JIRA::Base
         
     | 
| 
      
 9 
     | 
    
         
            +
                  def self.all(client)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    path = path_base(client) + '/board'
         
     | 
| 
      
 11 
     | 
    
         
            +
                    response = client.get(path)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    json = parse_json(response.body)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    results = json['values']
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    until json['isLast']
         
     | 
| 
      
 16 
     | 
    
         
            +
                      params = { 'startAt' => (json['startAt'] + json['maxResults']).to_s }
         
     | 
| 
      
 17 
     | 
    
         
            +
                      response = client.get(url_with_query_params(path, params))
         
     | 
| 
      
 18 
     | 
    
         
            +
                      json = parse_json(response.body)
         
     | 
| 
      
 19 
     | 
    
         
            +
                      results += json['values']
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    results.map do |board|
         
     | 
| 
      
 23 
     | 
    
         
            +
                      client.Board.build(board)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def self.find(client, key, _options = {})
         
     | 
| 
      
 28 
     | 
    
         
            +
                    response = client.get(path_base(client) + "/board/#{key}")
         
     | 
| 
      
 29 
     | 
    
         
            +
                    json = parse_json(response.body)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    client.Board.build(json)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  def issues(params = {})
         
     | 
| 
      
 34 
     | 
    
         
            +
                    path = path_base(client) + "/board/#{id}/issue"
         
     | 
| 
      
 35 
     | 
    
         
            +
                    response = client.get(url_with_query_params(path, params))
         
     | 
| 
      
 36 
     | 
    
         
            +
                    json = self.class.parse_json(response.body)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    results = json['issues']
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    while (json['startAt'] + json['maxResults']) < json['total']
         
     | 
| 
      
 40 
     | 
    
         
            +
                      params['startAt'] = (json['startAt'] + json['maxResults'])
         
     | 
| 
      
 41 
     | 
    
         
            +
                      response = client.get(url_with_query_params(path, params))
         
     | 
| 
      
 42 
     | 
    
         
            +
                      json = self.class.parse_json(response.body)
         
     | 
| 
      
 43 
     | 
    
         
            +
                      results += json['issues']
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    results.map { |issue| client.Issue.build(issue) }
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  def configuration(params = {})
         
     | 
| 
      
 50 
     | 
    
         
            +
                    path = path_base(client) + "/board/#{id}/configuration"
         
     | 
| 
      
 51 
     | 
    
         
            +
                    response = client.get(url_with_query_params(path, params))
         
     | 
| 
      
 52 
     | 
    
         
            +
                    json = self.class.parse_json(response.body)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    client.BoardConfiguration.build(json)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  # options
         
     | 
| 
      
 57 
     | 
    
         
            +
                  #   - state ~ future, active, closed, you can define multiple states separated by commas, e.g. state=active,closed
         
     | 
| 
      
 58 
     | 
    
         
            +
                  #   - maxResults ~ default: 50 (JIRA API), 1000 (this library)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  #   - startAt ~ base index, starts at 0
         
     | 
| 
      
 60 
     | 
    
         
            +
                  def sprints(options = {})
         
     | 
| 
      
 61 
     | 
    
         
            +
                    # options.reverse_merge!(DEFAULT_OPTIONS)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    response = client.get(path_base(client) + "/board/#{id}/sprint?#{options.to_query}")
         
     | 
| 
      
 63 
     | 
    
         
            +
                    json = self.class.parse_json(response.body)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    json['values'].map do |sprint|
         
     | 
| 
      
 65 
     | 
    
         
            +
                      sprint['rapidview_id'] = id
         
     | 
| 
      
 66 
     | 
    
         
            +
                      client.Sprint.build(sprint)
         
     | 
| 
      
 67 
     | 
    
         
            +
                    end
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  def project
         
     | 
| 
      
 71 
     | 
    
         
            +
                    response = client.get(path_base(client) + "/board/#{id}/project")
         
     | 
| 
      
 72 
     | 
    
         
            +
                    json = self.class.parse_json(response.body)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    json['values'][0]
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                  def add_issue_to_backlog(issue)
         
     | 
| 
      
 77 
     | 
    
         
            +
                    client.post(path_base(client) + '/backlog/issue', { issues: [issue.id] }.to_json)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  private
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                  def self.path_base(client)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    client.options[:context_path] + '/rest/agile/1.0'
         
     | 
| 
      
 84 
     | 
    
         
            +
                  end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                  def path_base(client)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    self.class.path_base(client)
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
            end
         
     |